diff --git a/frontend/src/app/features/member/detail-view/member-detail-view.component.html b/frontend/src/app/features/member/detail-view/member-detail-view.component.html index 9097098a3..0410b0232 100644 --- a/frontend/src/app/features/member/detail-view/member-detail-view.component.html +++ b/frontend/src/app/features/member/detail-view/member-detail-view.component.html @@ -18,7 +18,7 @@

{{ 'ABBREVIATION' | scopedTranslation }}:

- {{ m.abbreviation ? (m.abbreviation) : ('ATTRIBUTE_NULL' | scopedTranslation)}} + {{ m.abbreviation | nullFallback }}

@@ -30,12 +30,8 @@

{{ 'DATE_OF_HIRE' | scopedTranslation }}:

- {{ m.dateOfHire - ? (m.dateOfHire | date) - : ('ATTRIBUTE_NULL' | scopedTranslation) - }} + {{ m.dateOfHire | date | nullFallback }}

-
@@ -46,11 +42,7 @@

{{ 'ORGANISATION_UNIT' | scopedTranslation }}:

- @if (m.organisationUnitName) { - {{m.organisationUnitName}} - } @else { - {{'ATTRIBUTE_NULL' | scopedTranslation}} - } + {{m.organisationUnitName | nullFallback}}

diff --git a/frontend/src/app/features/member/detail-view/member-detail-view.component.ts b/frontend/src/app/features/member/detail-view/member-detail-view.component.ts index fcf061ec5..7b2b1ca3c 100644 --- a/frontend/src/app/features/member/detail-view/member-detail-view.component.ts +++ b/frontend/src/app/features/member/detail-view/member-detail-view.component.ts @@ -18,6 +18,7 @@ import { getLeadershipExperienceTable } from './cv/member-detail-cv-table-definition'; import { MemberOverviewModel } from '../member-overview.model'; +import { NullFallbackPipe } from '../../../shared/pipes/null-fallback.pipe'; @Component({ selector: 'app-member-detail-view', @@ -26,6 +27,9 @@ import { MemberOverviewModel } from '../member-overview.model'; CommonModule, ScopedTranslationPipe, CrudButtonComponent, + NullFallbackPipe, + TranslationScopeDirective, + CrudButtonComponent, GenericCvContentComponent, MatTabGroup, MatTab, diff --git a/frontend/src/app/features/member/form/member-form.component.ts b/frontend/src/app/features/member/form/member-form.component.ts index 68da57c2a..b1fd8a8c8 100644 --- a/frontend/src/app/features/member/form/member-form.component.ts +++ b/frontend/src/app/features/member/form/member-form.component.ts @@ -119,7 +119,7 @@ export class MemberFormComponent implements OnInit { this.memberForm.get('organisationUnit') ?.setValue(this.organisationUnitsOptions() - .find((orgUnit) => orgUnit.id === this.member().organisationUnit.id)); + .find((orgUnit) => orgUnit.id === this.member().organisationUnit?.id)); }); } diff --git a/frontend/src/app/features/member/member.model.ts b/frontend/src/app/features/member/member.model.ts index 8ceacfdf9..62c3fb00a 100644 --- a/frontend/src/app/features/member/member.model.ts +++ b/frontend/src/app/features/member/member.model.ts @@ -8,6 +8,6 @@ export interface MemberModel { birthDate: Date; abbreviation: string | null; employmentState: EmploymentState; - organisationUnit: OrganisationUnitModel; + organisationUnit: OrganisationUnitModel | null; dateOfHire: Date | null; } diff --git a/frontend/src/app/features/member/overview/member-overview.component.html b/frontend/src/app/features/member/overview/member-overview.component.html index 1099a16a9..b3b4d9c1c 100644 --- a/frontend/src/app/features/member/overview/member-overview.component.html +++ b/frontend/src/app/features/member/overview/member-overview.component.html @@ -41,8 +41,9 @@

[class.active]="isFilterActive(state)" (click)="toggleFilter(state)" [attr.data-testid]="state" + *appTranslationScope="'EMPLOYMENT_STATUS_VALUES'" > - {{ 'EMPLOYMENT_STATUS_VALUES.' + state | scopedTranslation }} + {{ state | scopedTranslation }} } @@ -67,7 +68,7 @@

mat-sort-header="firstName" data-testid="first-name-sort" class="col-range" > - {{ 'MEMBER.FIRST_NAME' | translate }} + {{ 'FIRST_NAME' | scopedTranslation }} {{ 'BIRTH_DATE' | scopedTranslation }} - {{ member.birthDate | date: GLOBAL_DATE_FORMAT }} + {{ member.birthDate | date }} @@ -103,11 +104,7 @@

{{ 'ORGANISATION_UNIT' | scopedTranslation }} - @if (member.organisationUnit) { - {{ member.organisationUnit.name }} - } @else { - {{ 'MEMBER.ATTRIBUTE_NULL' | translate }} - } + {{member.organisationUnit?.name | nullFallback}} @@ -116,7 +113,9 @@

{{ 'EMPLOYMENT_STATE' | scopedTranslation }} - {{ "MEMBER.EMPLOYMENT_STATUS_VALUES." + member.employmentState | translate }} + + {{ member.employmentState | scopedTranslation }} + diff --git a/frontend/src/app/features/member/overview/member-overview.component.ts b/frontend/src/app/features/member/overview/member-overview.component.ts index b0cca1d79..efe40cbee 100644 --- a/frontend/src/app/features/member/overview/member-overview.component.ts +++ b/frontend/src/app/features/member/overview/member-overview.component.ts @@ -10,19 +10,19 @@ import { DatePipe } from '@angular/common'; import { MatIcon } from '@angular/material/icon'; import { MatButton } from '@angular/material/button'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; -import { TranslatePipe, TranslateService } from '@ngx-translate/core'; +import { TranslateService } from '@ngx-translate/core'; import { EmploymentState } from '../../../shared/enum/employment-state.enum'; import { debounceTime } from 'rxjs/operators'; -import { GLOBAL_DATE_FORMAT } from '../../../shared/format/date-format'; import sortingDataAccessor from '../../../shared/utils/sortingDataAccessor'; import { ScopedTranslationPipe } from '../../../shared/pipes/scoped-translation-pipe'; import { CrudButtonComponent } from '../../../shared/crud-button/crud-button.component'; +import { NullFallbackPipe } from '../../../shared/pipes/null-fallback.pipe'; +import { TranslationScopeDirective } from '../../../shared/translation-scope/translation-scope.directive'; @Component({ selector: 'app-member-overview', standalone: true, - providers: [DatePipe], imports: [ ReactiveFormsModule, MatFormFieldModule, @@ -32,10 +32,11 @@ import { CrudButtonComponent } from '../../../shared/crud-button/crud-button.com DatePipe, MatIcon, MatButton, - TranslatePipe, RouterLink, ScopedTranslationPipe, - CrudButtonComponent + CrudButtonComponent, + TranslationScopeDirective, + NullFallbackPipe ], templateUrl: './member-overview.component.html', styleUrl: './member-overview.component.scss' @@ -43,16 +44,12 @@ import { CrudButtonComponent } from '../../../shared/crud-button/crud-button.com export class MemberOverviewComponent implements OnInit { private readonly service: MemberService = inject(MemberService); - private readonly datePipe: DatePipe = inject(DatePipe); - private readonly router = inject(Router); private readonly route = inject(ActivatedRoute); private readonly translate = inject(TranslateService); - protected readonly GLOBAL_DATE_FORMAT = GLOBAL_DATE_FORMAT; - displayedColumns: string[] = [ 'first_name', 'last_name', @@ -174,8 +171,4 @@ export class MemberOverviewComponent implements OnInit { } return all; } - - handleAddMemberClick(): void { - this.router.navigate(['/member/add']); - } } diff --git a/frontend/src/app/shared/format/date-format.ts b/frontend/src/app/shared/format/date-format.ts index a383dfda3..acbf00ab2 100644 --- a/frontend/src/app/shared/format/date-format.ts +++ b/frontend/src/app/shared/format/date-format.ts @@ -2,8 +2,6 @@ import { MatDateFormats } from '@angular/material/core'; import { format } from 'date-fns'; import { de } from 'date-fns/locale'; -export const GLOBAL_DATE_FORMAT = 'dd.MM.yyyy'; - export const GLOBAL_DATE_FORMATS: MatDateFormats = { parse: { dateInput: { month: 'short', diff --git a/frontend/src/app/shared/i18n-prefix.provider.ts b/frontend/src/app/shared/i18n-prefix.provider.ts index 1f013f148..2df09646a 100644 --- a/frontend/src/app/shared/i18n-prefix.provider.ts +++ b/frontend/src/app/shared/i18n-prefix.provider.ts @@ -1,4 +1,8 @@ -import { inject, Injectable, Provider } from '@angular/core'; +import { + inject, + Injectable, + Provider +} from '@angular/core'; import { InterpolationParameters } from '@ngx-translate/core'; import { I18N_PREFIX } from './i18n-prefix.token'; import { ScopedTranslationCoreService } from './services/scoped-translation-core.service'; diff --git a/frontend/src/app/shared/modal/base-modal.component.html b/frontend/src/app/shared/modal/base-modal.component.html index 334490b8c..97e149771 100644 --- a/frontend/src/app/shared/modal/base-modal.component.html +++ b/frontend/src/app/shared/modal/base-modal.component.html @@ -1,7 +1,7 @@
-

+

{{ "MODEL_NAME" | scopedTranslation }} {{ "ACTION" | scopedTranslation }}

@@ -9,8 +9,7 @@

close diff --git a/frontend/src/app/shared/modal/base-modal.component.ts b/frontend/src/app/shared/modal/base-modal.component.ts index 377d55f02..9e7fcdd8b 100644 --- a/frontend/src/app/shared/modal/base-modal.component.ts +++ b/frontend/src/app/shared/modal/base-modal.component.ts @@ -4,10 +4,10 @@ import { MatDivider } from '@angular/material/divider'; import { MatIconButton } from '@angular/material/button'; import { MatIcon } from '@angular/material/icon'; - -import { ScopedTranslationPipe } from '../pipes/scoped-translation-pipe'; import { BaseFormActionsComponent } from '../base-form-actions/base-form-actions.component'; import { FormGroup } from '@angular/forms'; +import { TranslatedModelSuffixPipe } from '../pipes/translated-model-suffix.pipe'; +import { ScopedTranslationPipe } from '../pipes/scoped-translation-pipe'; @Component({ selector: 'app-base-modal', @@ -19,8 +19,10 @@ import { FormGroup } from '@angular/forms'; MatIcon, MatDialogClose, MatIconButton, - ScopedTranslationPipe, - BaseFormActionsComponent + BaseFormActionsComponent, + TranslatedModelSuffixPipe, + TranslatedModelSuffixPipe, + ScopedTranslationPipe ], templateUrl: './base-modal.component.html' }) diff --git a/frontend/src/app/shared/pipes/null-fallback.pipe.ts b/frontend/src/app/shared/pipes/null-fallback.pipe.ts new file mode 100644 index 000000000..3fbd2f2b6 --- /dev/null +++ b/frontend/src/app/shared/pipes/null-fallback.pipe.ts @@ -0,0 +1,13 @@ +import { inject, Pipe, PipeTransform } from '@angular/core'; +import { ScopedTranslationService } from '../i18n-prefix.provider'; + +@Pipe({ + name: 'nullFallback' +}) +export class NullFallbackPipe implements PipeTransform { + scopedTranslationService = inject(ScopedTranslationService); + + transform(value: any, fallback = 'ATTRIBUTE_NULL'): string { + return value ?? this.scopedTranslationService.instant(fallback); + } +} diff --git a/frontend/src/app/shared/pipes/translated-model-suffix.pipe.ts b/frontend/src/app/shared/pipes/translated-model-suffix.pipe.ts new file mode 100644 index 000000000..bf5f4af4c --- /dev/null +++ b/frontend/src/app/shared/pipes/translated-model-suffix.pipe.ts @@ -0,0 +1,17 @@ +import { inject, Pipe, PipeTransform } from '@angular/core'; +import { ScopedTranslationService } from '../i18n-prefix.provider'; + +@Pipe({ + name: 'translatedModelSuffix' +}) +export class TranslatedModelSuffixPipe implements PipeTransform { + pctsTranslationService = inject(ScopedTranslationService); + + transform(prefix: string, suffix = ''): string { + const modelKey = 'MODEL_NAME'; + const translatedModelName = this.pctsTranslationService.instant(modelKey); + return [prefix, + translatedModelName, + suffix].join('-'); + } +} diff --git a/frontend/src/app/shared/services/scoped-translation-core.service.ts b/frontend/src/app/shared/services/scoped-translation-core.service.ts index 3af8dcb76..1b30e198f 100644 --- a/frontend/src/app/shared/services/scoped-translation-core.service.ts +++ b/frontend/src/app/shared/services/scoped-translation-core.service.ts @@ -87,8 +87,11 @@ export class ScopedTranslationCoreService { for (const key of keyList) { const translation = this.translateService.instant(key, params); - // instant() returns the key itself if no translation is found - if (translation !== key) { + /* + * instant() returns the key itself if no translation is found + * prevent returning anything else than a string since ngx-translate return an obj whenever a key is translated that contains sub keys + */ + if (translation !== key && typeof translation === 'string') { return translation; } }