From df148a05f84489897ef85498120775801ce89246 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 30 Sep 2026 09:21:10 +0200 Subject: [PATCH] Include last request in user detail dialog --- .../admin-overview.component.ts | 22 +------------ .../admin-users/admin-users.component.ts | 31 +++++-------------- .../components/admin-users/admin-users.html | 19 ++++++++++-- .../interfaces/interfaces.ts | 1 + .../user-detail-dialog.component.ts | 2 ++ .../user-detail-dialog.html | 19 ++++++++++++ apps/client/src/app/util/date.util.ts | 28 +++++++++++++++++ 7 files changed, 75 insertions(+), 47 deletions(-) create mode 100644 apps/client/src/app/util/date.util.ts diff --git a/apps/client/src/app/components/admin-overview/admin-overview.component.ts b/apps/client/src/app/components/admin-overview/admin-overview.component.ts index 733200c912..72b9194890 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.component.ts +++ b/apps/client/src/app/components/admin-overview/admin-overview.component.ts @@ -48,12 +48,7 @@ import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; -import { - addMilliseconds, - differenceInSeconds, - formatDistanceToNowStrict, - parseISO -} from 'date-fns'; +import { addMilliseconds, formatDistanceToNowStrict } from 'date-fns'; import { addIcons } from 'ionicons'; import { closeCircleOutline, @@ -187,21 +182,6 @@ export class GfAdminOverviewComponent implements OnInit { this.fetchAdminData(); } - protected formatDistanceToNow(aDateString: string) { - if (aDateString) { - const distanceString = formatDistanceToNowStrict(parseISO(aDateString), { - addSuffix: true - }); - - return Math.abs(differenceInSeconds(parseISO(aDateString), new Date())) < - 60 - ? 'just now' - : distanceString; - } - - return ''; - } - protected formatStringValue(aStringValue: StringValue) { return formatDistanceToNowStrict( addMilliseconds(new Date(), ms(aStringValue)), diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index 0060b38ee0..6018ea3eb8 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -5,12 +5,16 @@ import { import { GfUserDetailDialogComponent } from '@ghostfolio/client/components/user-detail-dialog/user-detail-dialog.component'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { DEFAULT_LOCALE, DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config'; +import { formatDistanceToNow } from '@ghostfolio/client/util/date.util'; +import { + DEFAULT_LANGUAGE_CODE, + DEFAULT_LOCALE, + DEFAULT_PAGE_SIZE +} from '@ghostfolio/common/config'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { canDeleteUser, getCountryName, - getDateFnsLocale, getDateFormatString, getEmojiFlag } from '@ghostfolio/common/helper'; @@ -49,11 +53,6 @@ import { import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; -import { - differenceInSeconds, - formatDistanceToNowStrict, - parseISO -} from 'date-fns'; import { addIcons } from 'ionicons'; import { contractOutline, @@ -93,6 +92,7 @@ export class GfAdminUsersComponent implements OnInit { protected defaultDateFormat: string; protected displayedColumns: string[] = []; protected readonly canDeleteUser = canDeleteUser; + protected readonly formatDistanceToNow = formatDistanceToNow; protected readonly getCountryName = getCountryName; protected readonly getEmojiFlag = getEmojiFlag; protected hasPermissionForSubscription: boolean; @@ -209,22 +209,6 @@ export class GfAdminUsersComponent implements OnInit { }); } - protected formatDistanceToNow(aDateString: string) { - if (aDateString) { - const distanceString = formatDistanceToNowStrict(parseISO(aDateString), { - addSuffix: true, - locale: getDateFnsLocale(this.user?.settings?.language) - }); - - return Math.abs(differenceInSeconds(parseISO(aDateString), new Date())) < - 60 - ? $localize`just now` - : distanceString; - } - - return ''; - } - protected onChangePage(page: PageEvent) { this.fetchUsers({ pageIndex: page.pageIndex @@ -332,6 +316,7 @@ export class GfAdminUsersComponent implements OnInit { currentUserId: this.user?.id, deviceType: this.deviceType(), hasPermissionForSubscription: this.hasPermissionForSubscription, + language: this.user?.settings?.language ?? DEFAULT_LANGUAGE_CODE, locale: this.user?.settings?.locale ?? DEFAULT_LOCALE, userId: aUserId } satisfies UserDetailDialogParams, diff --git a/apps/client/src/app/components/admin-users/admin-users.html b/apps/client/src/app/components/admin-users/admin-users.html index 1be6174ace..33e6a8593e 100644 --- a/apps/client/src/app/components/admin-users/admin-users.html +++ b/apps/client/src/app/components/admin-users/admin-users.html @@ -32,7 +32,10 @@ class="ml-1" i18n-title title="Expires {{ - formatDistanceToNow(element.subscription.expiresAt) + formatDistanceToNow({ + date: element.subscription.expiresAt, + language: user?.settings?.language + }) }} ({{ element.subscription.expiresAt | date: defaultDateFormat }})" @@ -79,7 +82,12 @@ class="mat-mdc-cell px-1 py-2 text-nowrap" mat-cell > - {{ formatDistanceToNow(element.createdAt) }} + {{ + formatDistanceToNow({ + date: element.createdAt, + language: user?.settings?.language + }) + }} @@ -185,7 +193,12 @@ class="mat-mdc-cell px-1 py-2 text-nowrap" mat-cell > - {{ formatDistanceToNow(element.lastActivity) }} + {{ + formatDistanceToNow({ + date: element.lastActivity, + language: user?.settings?.language + }) + }} } diff --git a/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts index 41b2b210f1..102a6ca837 100644 --- a/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts @@ -2,6 +2,7 @@ export interface UserDetailDialogParams { currentUserId: string; deviceType: string; hasPermissionForSubscription: boolean; + language: string; locale: string; userId: string; } diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts index 8d12d0ba03..93109de8f2 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts @@ -1,3 +1,4 @@ +import { formatDistanceToNow } from '@ghostfolio/client/util/date.util'; import { canDeleteUser, getCountryName, @@ -55,6 +56,7 @@ import { export class GfUserDetailDialogComponent implements OnInit { protected readonly baseCurrency: string; protected readonly canDeleteUser = canDeleteUser; + protected readonly formatDistanceToNow = formatDistanceToNow; protected readonly getCountryName = getCountryName; protected isLoading = true; diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html index 4cc5b8a260..560a1f189c 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -154,6 +154,25 @@ +
+
+ Last Request +
+
+ @if (subscriptionsDataSource.data.length > 0) {
diff --git a/apps/client/src/app/util/date.util.ts b/apps/client/src/app/util/date.util.ts new file mode 100644 index 0000000000..5d403cf9e2 --- /dev/null +++ b/apps/client/src/app/util/date.util.ts @@ -0,0 +1,28 @@ +import { getDateFnsLocale } from '@ghostfolio/common/helper'; + +import { + differenceInSeconds, + formatDistanceToNowStrict, + parseISO +} from 'date-fns'; + +export function formatDistanceToNow({ + date, + language +}: { + date: string; + language?: string; +}) { + if (date) { + const distanceString = formatDistanceToNowStrict(parseISO(date), { + addSuffix: true, + locale: getDateFnsLocale(language) + }); + + return Math.abs(differenceInSeconds(parseISO(date), new Date())) < 60 + ? $localize`just now` + : distanceString; + } + + return ''; +}