From f6b385cfa135d23d217fa5c7c2ae6500cb5c940e Mon Sep 17 00:00:00 2001 From: HydrallHarsh Date: Fri, 24 Oct 2025 11:40:04 +0530 Subject: [PATCH] refactor and improve UI component --- CHANGELOG.md | 5 ++- .../admin-users/admin-users.component.ts | 34 +++++++++++-------- .../interfaces/interfaces.ts | 3 +- .../user-detail-dialog.component.ts | 30 ++++------------ .../user-detail-dialog.html | 18 ++++++---- 5 files changed, 41 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad34180ad..e46b9d490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +- User detail dialog component to view user information in admin users management + ## 2.210.0 - 2025-10-22 ### Added - Added support for data gathering by date range in the asset profile details dialog of the admin control panel -- Added user detail dialog component to view user information in admin users management ### Changed 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 e708ec010..8e6079297 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 @@ -77,8 +77,8 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { public dataSource = new MatTableDataSource(); public defaultDateFormat: string; - public displayedColumns: string[] = []; public deviceType: string; + public displayedColumns: string[] = []; public getEmojiFlag = getEmojiFlag; public hasPermissionForSubscription: boolean; public hasPermissionToImpersonateAllUsers: boolean; @@ -103,6 +103,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { private tokenStorageService: TokenStorageService, private userService: UserService ) { + this.deviceType = this.deviceService.getDeviceInfo().deviceType; this.info = this.dataService.fetchInfo(); this.hasPermissionForSubscription = hasPermission( @@ -132,6 +133,14 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { ]; } + this.route.queryParams + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((params) => { + if (params['userDetailDialog'] && params['userId']) { + this.openUserDetailDialog(params['userId']); + } + }); + this.userService.stateChanged .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((state) => { @@ -156,20 +165,12 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { personOutline, trashOutline }); - - this.deviceType = this.deviceService.getDeviceInfo().deviceType; - this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((params) => { - if (params['userDetailDialog'] && params['userId']) { - this.openUserDetailDialog(params['userId']); - } - }); } public ngOnInit() { this.fetchUsers(); } + public onOpenUserDetailDialog(userId: string) { this.router.navigate([], { queryParams: { userId, userDetailDialog: true } @@ -178,14 +179,16 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { private openUserDetailDialog(userId: string) { // Find the user data from the current dataSource - const userData = this.dataSource.data.find((user) => user.id === userId); + const userData = this.dataSource.data.find(({ id }) => { + return id === userId; + }); const dialogRef = this.dialog.open(GfUserDetailDialogComponent, { autoFocus: false, data: { + userData, userId, - deviceType: this.deviceType, - userData: userData // Pass the user data + deviceType: this.deviceType } as UserDetailDialogParams, height: this.deviceType === 'mobile' ? '80vh' : '60vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' @@ -195,10 +198,11 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { .afterClosed() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { - this.fetchUsers(); // Refresh the users list - this.router.navigate(['.'], { relativeTo: this.route }); // Clear query params + this.fetchUsers(); + this.router.navigate(['.'], { relativeTo: this.route }); }); } + public formatDistanceToNow(aDateString: string) { if (aDateString) { const distanceString = formatDistanceToNowStrict(parseISO(aDateString), { 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 0d75fdbe2..9fbf37ea3 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,5 @@ import { AdminUsers } from '@ghostfolio/common/interfaces'; export interface UserDetailDialogParams { deviceType: string; - userData?: AdminUsers['users'][0]; - userId: string; + userData: AdminUsers['users'][0]; } 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 7184055fe..61d193145 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 @@ -6,18 +6,16 @@ import { GfValueComponent } from '@ghostfolio/ui/value'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, + ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, Inject, OnDestroy, - OnInit, - ChangeDetectorRef + OnInit } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog'; -import { addIcons } from 'ionicons'; -import { personOutline } from 'ionicons/icons'; import { Subject } from 'rxjs'; import { UserDetailDialogParams } from './interfaces/interfaces'; @@ -39,20 +37,15 @@ import { UserDetailDialogParams } from './interfaces/interfaces'; templateUrl: './user-detail-dialog.html' }) export class GfUserDetailDialogComponent implements OnDestroy, OnInit { - public isLoading = false; - public registrationDate: Date; + public title: string = 'User Information'; public user: User; - public userId: string; private unsubscribeSubject = new Subject(); public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: UserDetailDialogParams, public dialogRef: MatDialogRef - ) { - this.userId = this.data.userId; - addIcons({ personOutline }); - } + ) {} public ngOnInit() { this.initialize(); @@ -62,23 +55,12 @@ export class GfUserDetailDialogComponent implements OnDestroy, OnInit { this.dialogRef.close(); } - private fetchUserDetails(): void { - this.isLoading = true; - - // Use the user data passed from the admin users list if available + private fetchUserDetails() { if (this.data.userData) { - this.userId = this.data.userData.id; - this.registrationDate = this.data.userData.createdAt; - this.isLoading = false; - this.changeDetectorRef.markForCheck(); - } else { - // Fallback: use the user ID and set a placeholder registration date - this.userId = this.data.userId; - this.registrationDate = new Date(); // Placeholder - this.isLoading = false; this.changeDetectorRef.markForCheck(); } } + private initialize() { this.fetchUserDetails(); } 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 79e7f69df..b2d5915a0 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 @@ -1,24 +1,28 @@
-
-
- User Information -
+
+
- User ID + User ID
- Registration Date