diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts index b29ccc7d7b..a42ee933b4 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts @@ -43,6 +43,7 @@ import { MatPaginatorModule, PageEvent } from '@angular/material/paginator'; +import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSort, MatSortModule, @@ -64,6 +65,7 @@ import { ellipsisVertical, trashOutline } from 'ionicons/icons'; +import ms from 'ms'; import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; @@ -88,6 +90,7 @@ import { CreateAssetProfileDialogParams } from './create-asset-profile-dialog/in MatCheckboxModule, MatMenuModule, MatPaginatorModule, + MatSnackBarModule, MatSortModule, MatTableModule, NgxSkeletonLoaderModule, @@ -177,6 +180,7 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { private readonly dialog = inject(MatDialog); private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); + private readonly snackBar = inject(MatSnackBar); private readonly userService = inject(UserService); public constructor() { @@ -285,15 +289,25 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { dataSource, symbol }: AssetProfileIdentifier) { - this.adminMarketDataService.deleteAssetProfile({ dataSource, symbol }); + this.adminMarketDataService + .deleteAssetProfile({ dataSource, symbol }) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.loadData(); + }); } protected onDeleteAssetProfiles() { - this.adminMarketDataService.deleteAssetProfiles( - this.selection.selected.map(({ dataSource, symbol }) => { - return { dataSource, symbol }; - }) - ); + this.adminMarketDataService + .deleteAssetProfiles( + this.selection.selected.map(({ dataSource, symbol }) => { + return { dataSource, symbol }; + }) + ) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.loadData(); + }); } protected onGatherMax() { @@ -301,9 +315,7 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { .gatherMax() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { - setTimeout(() => { - window.location.reload(); - }, 300); + this.notifyDataGatheringHasBeenStarted(); }); } @@ -311,7 +323,9 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { this.adminService .gatherProfileData() .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(); + .subscribe(() => { + this.notifyDataGatheringHasBeenStarted(); + }); } protected onGatherRecentMarketData() { @@ -319,9 +333,7 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { .gatherRecentMarketData() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { - setTimeout(() => { - window.location.reload(); - }, 300); + this.notifyDataGatheringHasBeenStarted(); }); } @@ -396,6 +408,16 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { }); } + private notifyDataGatheringHasBeenStarted() { + this.snackBar.open( + '✅ ' + $localize`Data gathering has been started.`, + undefined, + { + duration: ms('3 seconds') + } + ); + } + private openAssetProfileDialog({ dataSource, symbol @@ -431,6 +453,12 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { if (newAssetProfileIdentifier) { this.onOpenAssetProfileDialog(newAssetProfileIdentifier); } else { + this.loadData({ + pageIndex: this.paginator().pageIndex, + sortColumn: this.sort().active, + sortDirection: this.sort().direction + }); + this.router.navigate(['.'], { relativeTo: this.route }); } }); diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts index 28c8c2d9fa..c4d45b7f0f 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts @@ -4,7 +4,7 @@ import { NotificationService } from '@ghostfolio/ui/notifications'; import { AdminService } from '@ghostfolio/ui/services'; import { Injectable } from '@angular/core'; -import { EMPTY, catchError, finalize, forkJoin } from 'rxjs'; +import { EMPTY, Subject, catchError, finalize, forkJoin } from 'rxjs'; @Injectable() export class AdminMarketDataService { @@ -14,25 +14,29 @@ export class AdminMarketDataService { ) {} public deleteAssetProfile({ dataSource, symbol }: AssetProfileIdentifier) { + const assetProfileDeleted = new Subject(); + this.notificationService.confirm({ confirmFn: () => { this.adminService .deleteProfileData({ dataSource, symbol }) .subscribe(() => { - setTimeout(() => { - window.location.reload(); - }, 300); + assetProfileDeleted.next(); + assetProfileDeleted.complete(); }); }, confirmType: ConfirmationDialogType.Warn, title: $localize`Do you really want to delete this asset profile?` }); + + return assetProfileDeleted.asObservable(); } public deleteAssetProfiles( aAssetProfileIdentifiers: AssetProfileIdentifier[] ) { const assetProfileCount = aAssetProfileIdentifiers.length; + const assetProfilesDeleted = new Subject(); this.notificationService.confirm({ confirmFn: () => { @@ -55,7 +59,8 @@ export class AdminMarketDataService { return EMPTY; }), finalize(() => { - window.location.reload(); + assetProfilesDeleted.next(); + assetProfilesDeleted.complete(); }) ) .subscribe(); @@ -66,5 +71,7 @@ export class AdminMarketDataService { ? $localize`Do you really want to delete this asset profile?` : $localize`Do you really want to delete these ${assetProfileCount}:count: asset profiles?` }); + + return assetProfilesDeleted.asObservable(); } } diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index f0e8eaf171..aa61845f4a 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -531,9 +531,12 @@ export class GfAssetProfileDialogComponent implements OnInit { dataSource, symbol }: AssetProfileIdentifier) { - this.adminMarketDataService.deleteAssetProfile({ dataSource, symbol }); - - this.dialogRef.close(); + this.adminMarketDataService + .deleteAssetProfile({ dataSource, symbol }) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.dialogRef.close(); + }); } protected onGatherProfileDataBySymbol({ diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts index 63bf6e24e9..35aaa9e8ac 100644 --- a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts +++ b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts @@ -24,7 +24,7 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { RouterModule } from '@angular/router'; import ms, { StringValue } from 'ms'; import { EMPTY } from 'rxjs'; -import { catchError } from 'rxjs/operators'; +import { catchError, switchMap } from 'rxjs/operators'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -184,30 +184,19 @@ export class GfUserAccountMembershipComponent { return EMPTY; }), + switchMap(() => { + return this.userService.get(true); + }), takeUntilDestroyed(this.destroyRef) ) .subscribe(() => { - const snackBarRef = this.snackBar.open( + this.snackBar.open( '✅ ' + $localize`Coupon code has been redeemed`, - $localize`Reload`, + undefined, { duration: ms('3 seconds') } ); - - snackBarRef - .afterDismissed() - .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(() => { - window.location.reload(); - }); - - snackBarRef - .onAction() - .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(() => { - window.location.reload(); - }); }); } },