Browse Source

Improve usability by eliminating page reloads

pull/7518/head
Thomas Kaul 4 weeks ago
parent
commit
c93b3236ba
  1. 54
      apps/client/src/app/components/admin-market-data/admin-market-data.component.ts
  2. 17
      apps/client/src/app/components/admin-market-data/admin-market-data.service.ts
  3. 9
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  4. 23
      apps/client/src/app/components/user-account-membership/user-account-membership.component.ts

54
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 });
}
});

17
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<void>();
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<void>();
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();
}
}

9
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({

23
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();
});
});
}
},

Loading…
Cancel
Save