refactor: refactor date handling across components to use date-fns and Intl.DateTimeFormat

- Replaced moment.js usage with Intl.DateTimeFormat for date formatting in various components.
- Introduced utility functions `normalizeDateLocale` and `formatWithIntl` for locale normalization and date formatting.
- Updated PlaylistSwitcher, RecentPlaylists, ContentCard, EPG components, and MultiEpgContainer to utilize the new date formatting approach.
- Removed moment-date pipe and related tests, simplifying date handling logic.
- Ensured all date displays respect the current locale settings.

Entire-Checkpoint: 271bd0162027
This commit is contained in:
4gray committed 2026-04-11 10:41:33 +02:00
1 parent d3e30056f6
commit c97673b928
29 files changed
+410 -247

No files matched your search

@@ -125,7 +125,13 @@
{{ getPlaylistTypeLabel(playlist) }}
@if (playlist.updateDate) {
<span class="separator">|</span>
{{ playlist.updateDate | date: 'MMM d, HH:mm' }}
{{
playlist.updateDate
| date
: 'MMM d, HH:mm'
: undefined
: currentLocale()
}}
}
</span>
</div>
@@ -10,6 +10,7 @@ import {
signal,
viewChild,
} from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
import { MatIconButton } from '@angular/material/button';
import { MatRippleModule } from '@angular/material/core';
@@ -17,10 +18,12 @@ import { MatDivider } from '@angular/material/divider';
import { MatIcon } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenu, MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
import { TranslatePipe } from '@ngx-translate/core';
import { normalizeDateLocale } from '@iptvnator/pipes';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { PlaylistContextFacade } from '@iptvnator/playlist/shared/util';
import { PortalStatus, PortalStatusService } from 'services';
import { PlaylistMeta } from 'shared-interfaces';
import { startWith } from 'rxjs';
type PlaylistFilterType = 'm3u' | 'stalker' | 'xtream';
@@ -53,7 +56,12 @@ export class PlaylistSwitcherComponent {
private readonly destroyRef = inject(DestroyRef);
private readonly playlistContext = inject(PlaylistContextFacade);
private readonly portalStatusService = inject(PortalStatusService);
private readonly translate = inject(TranslateService);
private focusSearchTimeoutId: ReturnType<typeof setTimeout> | null = null;
private readonly languageTick = toSignal(
this.translate.onLangChange.pipe(startWith(null)),
{ initialValue: null }
);
readonly currentTitle = input.required<string>();
readonly subtitle = input<string>('');
@@ -116,6 +124,12 @@ export class PlaylistSwitcherComponent {
});
readonly portalStatuses = signal<Map<string, PortalStatus>>(new Map());
readonly currentLocale = computed(() => {
this.languageTick();
return normalizeDateLocale(
this.translate.currentLang || this.translate.defaultLang
);
});
constructor() {
this.destroyRef.onDestroy(() => {
@@ -83,11 +83,17 @@
{{ 'HOME.PLAYLISTS.CHANNELS' | translate }}: {{ item.count }}
@if (item.importDate.length > 3) {
| {{ 'HOME.PLAYLISTS.ADDED' | translate }}:
{{ item.importDate | date }}
{{ item.importDate | date: undefined : undefined : currentLocale() }}
}
@if (item.updateDate) {
| {{ 'HOME.PLAYLISTS.UPDATED' | translate }}:
{{ item.updateDate | date: 'MMMM d, yyyy, HH:mm' }}
{{
item.updateDate
| date
: 'MMMM d, yyyy, HH:mm'
: undefined
: currentLocale()
}}
}
@if (item.updateState === 2) {
<mat-icon
@@ -107,11 +113,17 @@
}
@if (item.importDate.length > 3) {
| {{ 'HOME.PLAYLISTS.ADDED' | translate }}:
{{ item.importDate | date }}
{{ item.importDate | date: undefined : undefined : currentLocale() }}
}
@if (item.updateDate) {
| {{ 'HOME.PLAYLISTS.UPDATED' | translate }}:
{{ item.updateDate | date: 'MMMM d, yyyy, HH:mm' }}
{{
item.updateDate
| date
: 'MMMM d, yyyy, HH:mm'
: undefined
: currentLocale()
}}
}
}
</div>
@@ -9,12 +9,15 @@ import {
input,
output,
} from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { MatIconButton } from '@angular/material/button';
import { MatIcon } from '@angular/material/icon';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatTooltip } from '@angular/material/tooltip';
import { TranslatePipe } from '@ngx-translate/core';
import { normalizeDateLocale } from '@iptvnator/pipes';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { startWith } from 'rxjs';
import { PortalStatus, PortalStatusService } from 'services';
import { PlaylistMeta } from 'shared-interfaces';
@@ -53,8 +56,19 @@ export class PlaylistItemComponent implements OnInit {
portalStatus: PortalStatus = 'unavailable';
private readonly portalStatusService = inject(PortalStatusService);
private readonly translate = inject(TranslateService);
private readonly languageTick = toSignal(
this.translate.onLangChange.pipe(startWith(null)),
{ initialValue: null }
);
readonly isElectron = !!window.electron;
readonly currentLocale = computed(() => {
this.languageTick();
return normalizeDateLocale(
this.translate.currentLang || this.translate.defaultLang
);
});
async ngOnInit() {
await this.checkPortalStatus();