Skip to content
This repository has been archived by the owner on Oct 26, 2022. It is now read-only.

Commit

Permalink
feat(app): add dynamic translation to agent detail form (#311)
Browse files Browse the repository at this point in the history
* fix(title): reference correct value

* feat(resolvers): initialize new agent object with dynamic content

* test(update-agent): add dependencies

* style(app): reorder statements, clean up aliases

* feat(i18n, title): add `setTranslation`, translations

* feat, refactor(agents): use event emitter instead of state for trigger

* feat(models, dynamic-form): add and bind `formTitleParams` to template

* feat(agent-detail): add `isSetTranslation` boolean

* feat(agent-detail): disable form control based on `isSetTranslation`

* feat(agent-detail): update submit action based on conditions

* feat(agent-detail): map selected language to form

* feat(agent-detail): set form name and params

* test(agent-detail): add test dependencies

* feat(content-routing): wire up `set-translation/:id/:languageCode` route

* refactor(agent): improve typing

* feat(content, i18n): add translation for `set-translation` route name

* refactor(content-routing): adds HasValidLanguageGuard to `set-translation` route

* feat(agent-detail, dynamic-form-action, JSONs): creates a new property `setTranslation` under the dynamicForm.action & adds translation for its value in all of the JSON files. Uses this new property to set the form submit button text when setting translation on an agent

* refactor(form-input, form-select): reads formControl from the `group.get()` if the fieldConfig is not for dynamicContent translation fields. Otherwise uses `group.control` to get the value of fields that requires translation

* refactor(agent): removes description property from agent dto since it is nested inside dynamicContent

* chore(agent-detail): adds TODO to send request to the server to set Translation

Co-authored-by: Pratima Sakinala <[email protected]>
  • Loading branch information
Karvel and pratimasakinala authored Apr 8, 2021
1 parent 935545e commit f26e384
Show file tree
Hide file tree
Showing 30 changed files with 212 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AgencyListPresentationComponent {
@Input() public agencyList: IAgencyDTO;
@Input() public agencyList: IAgencyDTO[];

@Output() public emitDelete = new EventEmitter<IAgencyDTO>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { TranslocoTestingModule } from '@ngneat/transloco';

import { AgentDetailPresentationComponent } from './agent-detail-presentation.component';
import { AgentDetailSmartComponent } from './agent-detail-smart.component';
import { AgentDTO, AgentTranslation } from '@models/agent';
import { environment } from '@env/environment.test';
import { Logger } from '@utils/logger';
import { ToastrTestingModule } from '@utils/test/toastr-testing-module';
import { ActivatedRoute } from '@angular/router';

!environment.testIntegration
? Logger.log('Integration skipped')
Expand All @@ -31,6 +33,28 @@ import { ToastrTestingModule } from '@utils/test/toastr-testing-module';
ToastrTestingModule,
TranslocoTestingModule,
],
providers: [
{
provide: ActivatedRoute,
useValue: {
snapshot: {
data: {
agent: new AgentDTO({
dynamicContent: {
['en-US']: new AgentTranslation(),
},
}),
},
params: {
languageCode: '',
},
routeConfig: {
path: 'test',
},
},
},
},
],
}).compileComponents();
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,16 @@ import {
} from '@models/translation/dynamic-form/dynamic-form';
import { IInputField, InputField } from '@models/form/input';
import { ISelectField, SelectField } from '@models/form/select';
import { LANGUAGE } from '@models/enums';
import {
INavigationTranslationKey,
NavigationTranslationKey,
} from '@models/translation/navigation';
import { PhoneValidation } from '@utils/validation/phone-validation';
import { RequiredValidation } from '@utils/validation/required-validation';
import { SaveCancelButtonConfig } from '@models/form/button';
import { stateList } from '@models/state';
import { translocoConfigObj } from '@app/transloco/transloco-config';

@Component({
template: `
Expand All @@ -35,6 +41,11 @@ export class AgentDetailSmartComponent implements OnInit {
public agent: IAgentDTO;
public form: FormGroup = new FormGroup({});
public formConfig: IFormConfig = new FormConfig();
public languageCode: string = '';
public languageName: string = '';
public isSetTranslation: boolean =
this.activatedRoute.snapshot.routeConfig.path ===
'set-translation/:id/:languageCode';

constructor(
private activatedRoute: ActivatedRoute,
Expand All @@ -43,6 +54,10 @@ export class AgentDetailSmartComponent implements OnInit {
private router: Router,
) {
this.agent = this.activatedRoute.snapshot.data.agent;
this.languageCode =
this.activatedRoute.snapshot.params.languageCode ||
translocoConfigObj.defaultLang;
this.languageName = LANGUAGE[this.languageCode];
}

public ngOnInit(): void {
Expand All @@ -54,19 +69,24 @@ export class AgentDetailSmartComponent implements OnInit {
}

public updateOrCreateAgent(): void {
return this.agent.id ? this.updateAgent() : this.createAgent();
if (this.isSetTranslation) {
this.setTranslation();
} else {
this.agent.id ? this.updateAgent() : this.createAgent();
}
}

private buildFormConfig() {
const dynamicFormTranslationKeys: IDynamicFormTranslationKey = new DynamicFormTranslationKey();
const formConfig = new FormConfig({
formName: 'form',
formTitle: this.agent?.id
? dynamicFormTranslationKeys.title.updateAgent
: dynamicFormTranslationKeys.title.createAgent,
formTitle: this.setFormTitle(dynamicFormTranslationKeys),
formTitleParams: this.setFormTitleParams(),
submit: new SaveCancelButtonConfig({
save: this.agent?.id
? dynamicFormTranslationKeys.action.update
? this.isSetTranslation
? dynamicFormTranslationKeys.action.setTranslation
: dynamicFormTranslationKeys.action.update
: dynamicFormTranslationKeys.action.create,
}),
controls: [
Expand All @@ -77,6 +97,7 @@ export class AgentDetailSmartComponent implements OnInit {
label: dynamicFormTranslationKeys.label.fullName,
fieldConfig: new InputField(),
validation: [RequiredValidation.required('Full Name')],
disabled: this.isSetTranslation,
}),
new FormField<IInputField>({
name: 'email',
Expand All @@ -85,10 +106,11 @@ export class AgentDetailSmartComponent implements OnInit {
label: dynamicFormTranslationKeys.label.email,
fieldConfig: new InputField({ inputType: 'email' }),
validation: [EmailValidation.validEmail(true)],
disabled: this.isSetTranslation,
}),
new FormField<IInputField>({
name: 'description',
value: this.agent?.description,
name: 'dynamicContent.description',
value: this.agent?.dynamicContent[this.languageCode]?.description,
fieldType: 'input',
label: dynamicFormTranslationKeys.label.description,
fieldConfig: new InputField(),
Expand All @@ -101,6 +123,7 @@ export class AgentDetailSmartComponent implements OnInit {
label: dynamicFormTranslationKeys.label.phoneNumber,
fieldConfig: new InputField({ mask: Constants.masks.US_PHONE }),
validation: [PhoneValidation.validPhone(true)],
disabled: this.isSetTranslation,
}),
new FormField<IInputField>({
name: 'address1',
Expand All @@ -109,13 +132,15 @@ export class AgentDetailSmartComponent implements OnInit {
label: dynamicFormTranslationKeys.label.address,
fieldConfig: new InputField(),
validation: [RequiredValidation.required('Address')],
disabled: this.isSetTranslation,
}),
new FormField<IInputField>({
name: 'address2',
value: this.agent?.address.address2,
fieldType: 'input',
label: dynamicFormTranslationKeys.label.address2,
fieldConfig: new InputField(),
disabled: this.isSetTranslation,
}),
new FormField<IInputField>({
name: 'city',
Expand All @@ -124,6 +149,7 @@ export class AgentDetailSmartComponent implements OnInit {
label: dynamicFormTranslationKeys.label.city,
fieldConfig: new InputField(),
validation: [RequiredValidation.required('City')],
disabled: this.isSetTranslation,
}),
new FormField<ISelectField<string>>({
name: 'state',
Expand All @@ -134,6 +160,7 @@ export class AgentDetailSmartComponent implements OnInit {
options: stateList,
}),
validation: [RequiredValidation.required('State')],
disabled: this.isSetTranslation,
}),
new FormField<IInputField>({
name: 'zipCode',
Expand All @@ -142,13 +169,34 @@ export class AgentDetailSmartComponent implements OnInit {
label: dynamicFormTranslationKeys.label.zipCode,
fieldConfig: new InputField(),
validation: [RequiredValidation.required('Zip Code')],
disabled: this.isSetTranslation,
}),
],
});

return formConfig;
}

private setFormTitle(
dynamicFormTranslationKeys: IDynamicFormTranslationKey,
): string {
if (this.isSetTranslation) {
return dynamicFormTranslationKeys.title.setTranslation;
} else {
return this.agent.id
? dynamicFormTranslationKeys.title.updateAgent
: dynamicFormTranslationKeys.title.createAgent;
}
}

private setFormTitleParams(): string {
if (this.isSetTranslation) {
const navigationKeys: INavigationTranslationKey = new NavigationTranslationKey();

return navigationKeys.languages[this.languageName];
}
}

private buildPayload(): IAgentRequest {
const payloadDTO = new AgentRequest();
const payload = this.formService.buildRequestPayload(this.form, payloadDTO);
Expand All @@ -175,4 +223,9 @@ export class AgentDetailSmartComponent implements OnInit {
.updateAgent(requestPayload, this.agent.id)
.subscribe(() => this.router.navigateByUrl('/content/agent-list'));
}

private setTranslation(): void {
const requestPayload = this.buildPayload();
// TODO: send request to update/create the translation records in the database
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
[checkRole]="checkRole"
[tableData]="agentList"
(emitDelete)="deleteAgent($event)"
(emitSelectLanguage)="selectLanguage($event)"
></app-agent-table>
</ng-container>
<ng-template #loading>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
DynamicFormAction,
} from '@models/translation/dynamic-form/action';
import { IRoleCheck, RoleCheck } from '@models/role';
import { translocoConfigObj } from '@app/transloco/transloco-config';
import { ISelectedLanguage } from '@models/translation/translation';

@Component({
selector: 'app-agent-list-presentation',
Expand All @@ -23,15 +23,18 @@ import { translocoConfigObj } from '@app/transloco/transloco-config';
export class AgentListPresentationComponent {
@Input() public agentList: IAgentDTO[] = [];
@Input() public checkRole: IRoleCheck = new RoleCheck();
@Input() public dynamicLanguageForTranslation: string =
translocoConfigObj.defaultLang;

@Output() public emitDelete = new EventEmitter<IAgentDTO>();
@Output() public emitSelectLanguage = new EventEmitter<ISelectedLanguage>();

private dynamicFormAction: IDynamicFormAction = new DynamicFormAction();
public addButtonText: string = this.dynamicFormAction.addAgent;

public deleteAgent(agent: IAgentDTO): void {
this.emitDelete.emit(agent);
}

public selectLanguage(selectedLanguage: ISelectedLanguage): void {
this.emitSelectLanguage.emit(selectedLanguage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
EventEmitter,
OnInit,
} from '@angular/core';
import { Router } from '@angular/router';

import { TranslocoService } from '@ngneat/transloco';
import { combineLatest, Observable, of as observableOf } from 'rxjs';
import { catchError, map } from 'rxjs/operators';

Expand All @@ -16,18 +18,17 @@ import {
ConfirmationModalTranslationKey,
} from '@models/translation/confirmation-modal';
import { IRoleCheck } from '@models/role';
import { LanguageStateService } from '@core/services/state/language-state.service';
import { ISelectedLanguage } from '@models/translation/translation';
import { ModalService } from '@core/services/modal.service';
import { UserStateService } from '@core/services/state/user-state.service';
import { TranslocoService } from '@ngneat/transloco';

@Component({
template: `
<app-agent-list-presentation
[agentList]="agentList$ | async"
[checkRole]="checkRole$ | async"
[dynamicLanguageForTranslation]="dynamicLanguageForTranslation$ | async"
(emitDelete)="openDeleteModal($event)"
(emitSelectLanguage)="selectLanguage($event)"
></app-agent-list-presentation>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
Expand All @@ -40,16 +41,15 @@ export class AgentListSmartComponent implements OnInit {

constructor(
private agentService: AgentService,
private languageStateService: LanguageStateService,
private modalService: ModalService,
private router: Router,
private translocoService: TranslocoService,
private userStateService: UserStateService,
) {}

public ngOnInit(): void {
this.getAgentList();
this.checkRole$ = this.checkRoleList();
this.dynamicLanguageForTranslation$ = this.getDynamicLanguageForTranslation();
}

public checkRoleList(): Observable<IRoleCheck> {
Expand All @@ -72,8 +72,10 @@ export class AgentListSmartComponent implements OnInit {
});
}

private getDynamicLanguageForTranslation() {
return this.languageStateService.getDynamicLanguageForTranslation();
public selectLanguage(selectedLanguage: ISelectedLanguage): void {
this.router.navigateByUrl(
`/content/set-translation/${selectedLanguage.id}/${selectedLanguage.languageCode}`,
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
<ng-template #popContent let-agent="agent"
><app-select-language
[hasTranslationList]="agent.hasTranslationList"
[id]="agent.id"
(emitSetLanguage)="selectLanguage($event)"
></app-select-language
></ng-template>
<ng-template #tipContent>{{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '@models/translation/dynamic-table';
import { NgbPositionEnum } from '@models/enums';
import { IRoleCheck, RoleCheck } from '@models/role';
import { ISelectedLanguage } from '@models/translation/translation';
import { ITableConfig, TableConfig } from '@models/table';

@Component({
Expand All @@ -29,13 +30,18 @@ export class AgentTableComponent {
@Input() public tableData: IAgentDTO[] = [];

@Output() public emitDelete = new EventEmitter<IAgentDTO>();
@Output() public emitSelectLanguage = new EventEmitter<ISelectedLanguage>();

public dynamicTableTranslationKeys: IDynamicTableTranslationKey = new DynamicTableTranslationKey();

public deleteAgent(agent: IAgentDTO): void {
this.emitDelete.emit(agent);
}

public selectLanguage(selectedLanguage: ISelectedLanguage): void {
this.emitSelectLanguage.emit(selectedLanguage);
}

public openSelectLanguagePopover(
popover: NgbPopover,
agent: IAgentDTO,
Expand Down
12 changes: 12 additions & 0 deletions src/app/features/content/content-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ContentLayoutComponent } from './content-layout/content-layout.componen

import { AdminAuthGuard } from '@core/guards/admin-auth.guard';
import { CanEditAuthGuard } from '@core/guards/can-edit-auth.guard';
import { HasValidLanguageGuard } from '@core/guards/has-valid-language.guard';
import {
IRoutingContentTranslationKey,
RoutingContentTranslationKey,
Expand Down Expand Up @@ -43,6 +44,17 @@ const routes: Routes = [
agent: resolverList.CreateAgentResolver,
},
},
{
path: 'set-translation/:id/:languageCode',
component: AgentDetailSmartComponent,
canActivate: [CanEditAuthGuard, HasValidLanguageGuard],
data: {
title: contentRoutingTranslationKeys.setTranslation,
},
resolve: {
agent: resolverList.UpdateAgentResolver,
},
},
{
path: 'update-agent/:id',
component: AgentDetailSmartComponent,
Expand Down
Loading

0 comments on commit f26e384

Please sign in to comment.