diff --git a/CHANGELOG.md b/CHANGELOG.md index 220b29036..36c8c3c29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,17 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -### Added - -- Added a close holding button to the holding detail dialog -- Extended the user detail dialog in the users section of the admin control panel - -### Changed - -- Refactored the generation of the holdings table in the _Copy AI prompt to clipboard for analysis_ action on the analysis page (experimental) -- Refactored the generation of the holdings table in the _Copy portfolio data to clipboard for AI prompt_ action on the analysis page (experimental) -- Improved the language localization for German (`de`) - ### Fixed - Ensured the locale is available in the settings dialog to customize the rule thresholds of the _X-ray_ page 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 fba54b0bb..0c1e73dee 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 @@ -133,14 +133,6 @@ 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) => { @@ -169,6 +161,23 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { public ngOnInit() { this.fetchUsers(); + + // Handle route parameter changes when component is reused + this.route.params + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((params) => { + if (params['userId']) { + // If data is already loaded, open dialog immediately + if (this.dataSource.data.length > 0) { + this.openUserDetailDialog(params['userId']); + } else { + // If data is not loaded yet, wait for it to load + this.fetchUsers().then(() => { + this.openUserDetailDialog(params['userId']); + }); + } + } + }); } public formatDistanceToNow(aDateString: string) { @@ -245,9 +254,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { } public onOpenUserDetailDialog(userId: string) { - this.router.navigate([], { - queryParams: { userId, userDetailDialog: true } - }); + this.router.navigate(['./', userId], { relativeTo: this.route }); } public ngOnDestroy() { @@ -255,50 +262,51 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { this.unsubscribeSubject.complete(); } - private fetchUsers({ pageIndex }: { pageIndex: number } = { pageIndex: 0 }) { + private fetchUsers( + { pageIndex }: { pageIndex: number } = { pageIndex: 0 } + ): Promise { this.isLoading = true; if (pageIndex === 0 && this.paginator) { this.paginator.pageIndex = 0; } - this.adminService - .fetchUsers({ - skip: pageIndex * this.pageSize, - take: this.pageSize - }) - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ count, users }) => { - this.dataSource = new MatTableDataSource(users); - this.totalItems = count; - - this.isLoading = false; - - this.changeDetectorRef.markForCheck(); - }); + return new Promise((resolve) => { + this.adminService + .fetchUsers({ + skip: pageIndex * this.pageSize, + take: this.pageSize + }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ count, users }) => { + this.dataSource = new MatTableDataSource(users); + this.totalItems = count; + + this.isLoading = false; + + this.changeDetectorRef.markForCheck(); + resolve(); + }); + }); } - private openUserDetailDialog(aUserId: string) { + private openUserDetailDialog(userId: string) { const userData = this.dataSource.data.find(({ id }) => { - return id === aUserId; + return id === userId; }); if (!userData) { - this.router.navigate(['.'], { relativeTo: this.route }); + this.router.navigate(['../'], { relativeTo: this.route }); return; } - const dialogRef = this.dialog.open< - GfUserDetailDialogComponent, - UserDetailDialogParams - >(GfUserDetailDialogComponent, { + const dialogRef = this.dialog.open(GfUserDetailDialogComponent, { autoFocus: false, data: { userData, deviceType: this.deviceType, - hasPermissionForSubscription: this.hasPermissionForSubscription, locale: this.user?.settings?.locale - }, + } as UserDetailDialogParams, height: this.deviceType === 'mobile' ? '98vh' : '60vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); @@ -308,7 +316,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { this.fetchUsers(); - this.router.navigate(['.'], { relativeTo: this.route }); + this.router.navigate(['../'], { relativeTo: this.route }); }); } } diff --git a/apps/client/src/app/pages/admin/admin-page.routes.ts b/apps/client/src/app/pages/admin/admin-page.routes.ts index 956e12c9a..5c059a841 100644 --- a/apps/client/src/app/pages/admin/admin-page.routes.ts +++ b/apps/client/src/app/pages/admin/admin-page.routes.ts @@ -38,6 +38,12 @@ export const routes: Routes = [ path: internalRoutes.adminControl.subRoutes.users.path, component: GfAdminUsersComponent, title: internalRoutes.adminControl.subRoutes.users.title + }, + { + path: `${internalRoutes.adminControl.subRoutes.users.path}/:userId`, + component: GfAdminUsersComponent, + title: internalRoutes.adminControl.subRoutes.users.title, + runGuardsAndResolvers: 'paramsOrQueryParamsChange' } ], component: AdminPageComponent,