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

feat(app): add dynamic translation to agent detail form #311

Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ae28b68
fix(title): reference correct value
Karvel Apr 6, 2021
e96b8a5
feat(resolvers): initialize new agent object with dynamic content
Karvel Apr 6, 2021
cbc0150
test(update-agent): add dependencies
Karvel Apr 6, 2021
f8e78c6
style(app): reorder statements, clean up aliases
Karvel Apr 6, 2021
ed89044
feat(i18n, title): add `setTranslation`, translations
Karvel Apr 6, 2021
f47e60c
feat, refactor(agents): use event emitter instead of state for trigger
Karvel Apr 6, 2021
8f3a929
feat(models, dynamic-form): add and bind `formTitleParams` to template
Karvel Apr 6, 2021
fcd9e06
feat(agent-detail): add `isSetTranslation` boolean
Karvel Apr 6, 2021
029d44a
feat(agent-detail): disable form control based on `isSetTranslation`
Karvel Apr 6, 2021
7005891
feat(agent-detail): update submit action based on conditions
Karvel Apr 6, 2021
482a80a
feat(agent-detail): map selected language to form
Karvel Apr 6, 2021
8bcd2b1
feat(agent-detail): set form name and params
Karvel Apr 6, 2021
8fc1ca9
test(agent-detail): add test dependencies
Karvel Apr 6, 2021
33f7580
feat(content-routing): wire up `set-translation/:id/:languageCode` route
Karvel Apr 6, 2021
930c0b8
refactor(agent): improve typing
Karvel Apr 6, 2021
742c463
feat(content, i18n): add translation for `set-translation` route name
Karvel Apr 6, 2021
b0ef512
refactor(content-routing): adds HasValidLanguageGuard to `set-transla…
pratimasakinala Apr 6, 2021
35a5db9
feat(agent-detail, dynamic-form-action, JSONs): creates a new propert…
pratimasakinala Apr 6, 2021
e1607b7
refactor(form-input, form-select): reads formControl from the `group.…
pratimasakinala Apr 7, 2021
b8fb2a7
refactor(agent): removes description property from agent dto since it…
pratimasakinala Apr 7, 2021
b231e24
chore(agent-detail): adds TODO to send request to the server to set T…
pratimasakinala Apr 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function seems to just call this.buildPayload(), could we just call that here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That functionality isn't in yet. The method is essentially noop right now. We decided to handle the mapping of the data into the payload in a separate branch so we could merge this while the API catches up.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Karvel Got it, thank you!

} 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,8 @@ export class AgentDetailSmartComponent implements OnInit {
.updateAgent(requestPayload, this.agent.id)
.subscribe(() => this.router.navigateByUrl('/content/agent-list'));
}

private setTranslation(): void {
const requestPayload = this.buildPayload();
}
}
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { BehaviorSubject } from 'rxjs';

import { environment } from '@env/environment.test';
import { Logger } from '@utils/logger';
import { IUserDTO, UserDTO } from '@app/infrastructure/models/user';
import { RedirectRouteGuard } from './redirect-route.guard';
import { RoleDTO } from '@app/infrastructure/models/role';
import { RoleDTO } from '@models/role';
import { IUserDTO, UserDTO } from '@models/user';
import { UserStateService } from '../services/state/user-state.service';

!environment.testUnit
Expand Down
Loading