Browse Source

Add account detail dialog

pull/1047/head
Thomas 3 years ago
parent
commit
4c10e2cb73
  1. 33
      apps/api/src/app/order/order.controller.ts
  2. 3
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.scss
  3. 112
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts
  4. 65
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html
  5. 29
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts
  6. 5
      apps/client/src/app/components/account-detail-dialog/interfaces/interfaces.ts
  7. 9
      apps/client/src/app/components/accounts-table/accounts-table.component.html
  8. 10
      apps/client/src/app/components/accounts-table/accounts-table.component.ts
  9. 32
      apps/client/src/app/pages/accounts/accounts-page.component.ts
  10. 1
      apps/client/src/app/pages/accounts/accounts-page.html
  11. 4
      apps/client/src/app/pages/accounts/accounts-page.module.ts
  12. 14
      apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts
  13. 83
      apps/client/src/app/services/data.service.ts
  14. 3
      libs/common/src/lib/types/account-with-value.type.ts

33
apps/api/src/app/order/order.controller.ts

@ -4,6 +4,7 @@ import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor'; import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor';
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor';
import { ImpersonationService } from '@ghostfolio/api/services/impersonation.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation.service';
import { Filter } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types'; import type { RequestWithUser } from '@ghostfolio/common/types';
import { import {
@ -17,6 +18,7 @@ import {
Param, Param,
Post, Post,
Put, Put,
Query,
UseGuards, UseGuards,
UseInterceptors UseInterceptors
} from '@nestjs/common'; } from '@nestjs/common';
@ -66,8 +68,36 @@ export class OrderController {
@UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getAllOrders( public async getAllOrders(
@Headers('impersonation-id') impersonationId @Headers('impersonation-id') impersonationId,
@Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('tags') filterByTags?: string
): Promise<Activities> { ): Promise<Activities> {
const accountIds = filterByAccounts?.split(',') ?? [];
const assetClasses = filterByAssetClasses?.split(',') ?? [];
const tagIds = filterByTags?.split(',') ?? [];
const filters: Filter[] = [
...accountIds.map((accountId) => {
return <Filter>{
id: accountId,
type: 'ACCOUNT'
};
}),
...assetClasses.map((assetClass) => {
return <Filter>{
id: assetClass,
type: 'ASSET_CLASS'
};
}),
...tagIds.map((tagId) => {
return <Filter>{
id: tagId,
type: 'TAG'
};
})
];
const impersonationUserId = const impersonationUserId =
await this.impersonationService.validateImpersonationId( await this.impersonationService.validateImpersonationId(
impersonationId, impersonationId,
@ -76,6 +106,7 @@ export class OrderController {
const userCurrency = this.request.user.Settings.currency; const userCurrency = this.request.user.Settings.currency;
let activities = await this.orderService.getOrders({ let activities = await this.orderService.getOrders({
filters,
userCurrency, userCurrency,
includeDrafts: true, includeDrafts: true,
userId: impersonationUserId || this.request.user.id userId: impersonationUserId || this.request.user.id

3
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.scss

@ -0,0 +1,3 @@
:host {
display: block;
}

112
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts

@ -0,0 +1,112 @@
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Inject,
OnDestroy,
OnInit
} from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { downloadAsFile } from '@ghostfolio/common/helper';
import { User } from '@ghostfolio/common/interfaces';
import { OrderWithAccount } from '@ghostfolio/common/types';
import { AccountType } from '@prisma/client';
import { format, parseISO } from 'date-fns';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { AccountDetailDialogParams } from './interfaces/interfaces';
@Component({
host: { class: 'd-flex flex-column h-100' },
selector: 'gf-account-detail-dialog',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: 'account-detail-dialog.html',
styleUrls: ['./account-detail-dialog.component.scss']
})
export class AccountDetailDialog implements OnDestroy, OnInit {
public accountType: AccountType;
public name: string;
public orders: OrderWithAccount[];
public platformName: string;
public user: User;
public valueInBaseCurrency: number;
private unsubscribeSubject = new Subject<void>();
public constructor(
private changeDetectorRef: ChangeDetectorRef,
@Inject(MAT_DIALOG_DATA) public data: AccountDetailDialogParams,
private dataService: DataService,
public dialogRef: MatDialogRef<AccountDetailDialog>,
private userService: UserService
) {
this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((state) => {
if (state?.user) {
this.user = state.user;
this.changeDetectorRef.markForCheck();
}
});
}
public ngOnInit(): void {
this.dataService
.fetchAccount(this.data.accountId)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ accountType, name, Platform, valueInBaseCurrency }) => {
this.accountType = accountType;
this.name = name;
this.platformName = Platform?.name;
this.valueInBaseCurrency = valueInBaseCurrency;
this.changeDetectorRef.markForCheck();
});
this.dataService
.fetchActivities({
filters: [{ id: this.data.accountId, type: 'ACCOUNT' }]
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ activities }) => {
this.orders = activities;
this.changeDetectorRef.markForCheck();
});
}
public onClose(): void {
this.dialogRef.close();
}
public onExport() {
this.dataService
.fetchExport(
this.orders.map((order) => {
return order.id;
})
)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((data) => {
downloadAsFile({
content: data,
fileName: `ghostfolio-export-${this.name
.replace(/\s+/g, '-')
.toLowerCase()}-${format(
parseISO(data.meta.date),
'yyyyMMddHHmm'
)}.json`,
format: 'json'
});
});
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
}

65
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html

@ -0,0 +1,65 @@
<gf-dialog-header
mat-dialog-title
position="center"
[deviceType]="data.deviceType"
[title]="name"
(closeButtonClicked)="onClose()"
></gf-dialog-header>
<div class="flex-grow-1" mat-dialog-content>
<div class="container p-0">
<div class="row">
<div class="col-12 d-flex justify-content-center mb-3">
<gf-value
size="large"
[currency]="user?.settings?.baseCurrency"
[locale]="user?.settings?.locale"
[value]="valueInBaseCurrency"
></gf-value>
</div>
</div>
<div class="row">
<div class="col-6 mb-3">
<gf-value
label="Account Type"
size="medium"
[value]="accountType"
></gf-value>
</div>
<div class="col-6 mb-3">
<gf-value
label="Platform"
size="medium"
[value]="platformName"
></gf-value>
</div>
</div>
<div *ngIf="orders?.length > 0" class="row">
<div class="col mb-3">
<div class="h5 mb-0" i18n>Activities</div>
<gf-activities-table
[activities]="orders"
[baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="data.deviceType"
[hasPermissionToCreateActivity]="false"
[hasPermissionToExportActivities]="!hasImpersonationId"
[hasPermissionToFilter]="false"
[hasPermissionToImportActivities]="false"
[hasPermissionToOpenDetails]="false"
[locale]="user?.settings?.locale"
[showActions]="false"
[showSymbolColumn]="false"
(export)="onExport()"
></gf-activities-table>
</div>
</div>
</div>
</div>
<gf-dialog-footer
mat-dialog-actions
[deviceType]="data.deviceType"
(closeButtonClicked)="onClose()"
></gf-dialog-footer>

29
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts

@ -0,0 +1,29 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module';
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
import { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module';
import { GfValueModule } from '@ghostfolio/ui/value';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { AccountDetailDialog } from './account-detail-dialog.component';
@NgModule({
declarations: [AccountDetailDialog],
exports: [],
imports: [
CommonModule,
GfActivitiesTableModule,
GfDialogFooterModule,
GfDialogHeaderModule,
GfValueModule,
MatButtonModule,
MatDialogModule,
NgxSkeletonLoaderModule
],
providers: [],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class GfAccountDetailDialogModule {}

5
apps/client/src/app/components/account-detail-dialog/interfaces/interfaces.ts

@ -0,0 +1,5 @@
export interface AccountDetailDialogParams {
accountId: string;
deviceType: string;
hasImpersonationId: boolean;
}

9
apps/client/src/app/components/accounts-table/accounts-table.component.html

@ -65,7 +65,7 @@
<ng-container matColumnDef="transactions"> <ng-container matColumnDef="transactions">
<th *matHeaderCellDef class="px-1 text-right" mat-header-cell> <th *matHeaderCellDef class="px-1 text-right" mat-header-cell>
<span class="d-block d-sm-none">#</span> <span class="d-block d-sm-none">#</span>
<span class="d-none d-sm-block" i18n>Transactions</span> <span class="d-none d-sm-block" i18n>Activities</span>
</th> </th>
<td *matCellDef="let element" class="px-1 text-right" mat-cell> <td *matCellDef="let element" class="px-1 text-right" mat-cell>
<ng-container *ngIf="element.accountType === 'SECURITIES'">{{ <ng-container *ngIf="element.accountType === 'SECURITIES'">{{
@ -212,7 +212,12 @@
</ng-container> </ng-container>
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> <tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr> <tr
*matRowDef="let row; columns: displayedColumns"
mat-row
[ngClass]="{ 'cursor-pointer': hasPermissionToShowValues }"
(click)="hasPermissionToShowValues && onOpenAccountDetailDialog(row.id)"
></tr>
<tr <tr
*matFooterRowDef="displayedColumns" *matFooterRowDef="displayedColumns"
mat-footer-row mat-footer-row

10
apps/client/src/app/components/accounts-table/accounts-table.component.ts

@ -9,6 +9,7 @@ import {
Output Output
} from '@angular/core'; } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { Router } from '@angular/router';
import { Account as AccountModel } from '@prisma/client'; import { Account as AccountModel } from '@prisma/client';
import { Subject, Subscription } from 'rxjs'; import { Subject, Subscription } from 'rxjs';
@ -22,6 +23,7 @@ export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit {
@Input() accounts: AccountModel[]; @Input() accounts: AccountModel[];
@Input() baseCurrency: string; @Input() baseCurrency: string;
@Input() deviceType: string; @Input() deviceType: string;
@Input() hasPermissionToShowValues = true;
@Input() locale: string; @Input() locale: string;
@Input() showActions: boolean; @Input() showActions: boolean;
@Input() totalBalanceInBaseCurrency: number; @Input() totalBalanceInBaseCurrency: number;
@ -39,7 +41,7 @@ export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit {
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
public constructor() {} public constructor(private router: Router) {}
public ngOnInit() {} public ngOnInit() {}
@ -75,6 +77,12 @@ export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit {
} }
} }
public onOpenAccountDetailDialog(accountId: string) {
this.router.navigate([], {
queryParams: { accountId, accountDetailDialog: true }
});
}
public onUpdateAccount(aAccount: AccountModel) { public onUpdateAccount(aAccount: AccountModel) {
this.accountToUpdate.emit(aAccount); this.accountToUpdate.emit(aAccount);
} }

32
apps/client/src/app/pages/accounts/accounts-page.component.ts

@ -3,6 +3,8 @@ import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto'; import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto';
import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto'; import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto';
import { AccountDetailDialog } from '@ghostfolio/client/components/account-detail-dialog/account-detail-dialog.component';
import { AccountDetailDialogParams } from '@ghostfolio/client/components/account-detail-dialog/interfaces/interfaces';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
@ -27,6 +29,7 @@ export class AccountsPageComponent implements OnDestroy, OnInit {
public hasImpersonationId: boolean; public hasImpersonationId: boolean;
public hasPermissionToCreateAccount: boolean; public hasPermissionToCreateAccount: boolean;
public hasPermissionToDeleteAccount: boolean; public hasPermissionToDeleteAccount: boolean;
public hasPermissionToShowValues: boolean;
public routeQueryParams: Subscription; public routeQueryParams: Subscription;
public totalBalanceInBaseCurrency = 0; public totalBalanceInBaseCurrency = 0;
public totalValueInBaseCurrency = 0; public totalValueInBaseCurrency = 0;
@ -48,7 +51,12 @@ export class AccountsPageComponent implements OnDestroy, OnInit {
this.route.queryParams this.route.queryParams
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe((params) => { .subscribe((params) => {
if (params['createDialog'] && this.hasPermissionToCreateAccount) { if (params['accountId'] && params['accountDetailDialog']) {
this.openAccountDetailDialog(params['accountId']);
} else if (
params['createDialog'] &&
this.hasPermissionToCreateAccount
) {
this.openCreateAccountDialog(); this.openCreateAccountDialog();
} else if (params['editDialog']) { } else if (params['editDialog']) {
if (this.accounts) { if (this.accounts) {
@ -72,6 +80,8 @@ export class AccountsPageComponent implements OnDestroy, OnInit {
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe((aId) => { .subscribe((aId) => {
this.hasImpersonationId = !!aId; this.hasImpersonationId = !!aId;
this.hasPermissionToShowValues = !this.hasImpersonationId;
}); });
this.userService.stateChanged this.userService.stateChanged
@ -197,6 +207,26 @@ export class AccountsPageComponent implements OnDestroy, OnInit {
this.unsubscribeSubject.complete(); this.unsubscribeSubject.complete();
} }
private openAccountDetailDialog(aAccountId) {
const dialogRef = this.dialog.open(AccountDetailDialog, {
autoFocus: false,
data: <AccountDetailDialogParams>{
accountId: aAccountId,
deviceType: this.deviceType,
hasImpersonationId: this.hasImpersonationId
},
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh',
width: this.deviceType === 'mobile' ? '100vw' : '50rem'
});
dialogRef
.afterClosed()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.router.navigate(['.'], { relativeTo: this.route });
});
}
private openCreateAccountDialog(): void { private openCreateAccountDialog(): void {
const dialogRef = this.dialog.open(CreateOrUpdateAccountDialog, { const dialogRef = this.dialog.open(CreateOrUpdateAccountDialog, {
data: { data: {

1
apps/client/src/app/pages/accounts/accounts-page.html

@ -7,6 +7,7 @@
[accounts]="accounts" [accounts]="accounts"
[baseCurrency]="user?.settings?.baseCurrency" [baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="deviceType" [deviceType]="deviceType"
[hasPermissionToShowValues]="hasPermissionToShowValues"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[showActions]="!hasImpersonationId && hasPermissionToDeleteAccount && !user.settings.isRestrictedView" [showActions]="!hasImpersonationId && hasPermissionToDeleteAccount && !user.settings.isRestrictedView"
[totalBalanceInBaseCurrency]="totalBalanceInBaseCurrency" [totalBalanceInBaseCurrency]="totalBalanceInBaseCurrency"

4
apps/client/src/app/pages/accounts/accounts-page.module.ts

@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { GfAccountDetailDialogModule } from '@ghostfolio/client/components/account-detail-dialog/account-detail-dialog.module';
import { GfAccountsTableModule } from '@ghostfolio/client/components/accounts-table/accounts-table.module'; import { GfAccountsTableModule } from '@ghostfolio/client/components/accounts-table/accounts-table.module';
import { AccountsPageRoutingModule } from './accounts-page-routing.module'; import { AccountsPageRoutingModule } from './accounts-page-routing.module';
@ -10,16 +11,15 @@ import { GfCreateOrUpdateAccountDialogModule } from './create-or-update-account-
@NgModule({ @NgModule({
declarations: [AccountsPageComponent], declarations: [AccountsPageComponent],
exports: [],
imports: [ imports: [
AccountsPageRoutingModule, AccountsPageRoutingModule,
CommonModule, CommonModule,
GfAccountDetailDialogModule,
GfAccountsTableModule, GfAccountsTableModule,
GfCreateOrUpdateAccountDialogModule, GfCreateOrUpdateAccountDialogModule,
MatButtonModule, MatButtonModule,
RouterModule RouterModule
], ],
providers: [],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
}) })
export class AccountsPageModule {} export class AccountsPageModule {}

14
apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts

@ -111,12 +111,12 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
} }
}); });
this.fetchOrders(); this.fetchActivities();
} }
public fetchOrders() { public fetchActivities() {
this.dataService this.dataService
.fetchOrders() .fetchActivities({})
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ activities }) => { .subscribe(({ activities }) => {
this.activities = activities; this.activities = activities;
@ -139,7 +139,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe({ .subscribe({
next: () => { next: () => {
this.fetchOrders(); this.fetchActivities();
} }
}); });
} }
@ -298,7 +298,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe({ .subscribe({
next: () => { next: () => {
this.fetchOrders(); this.fetchActivities();
} }
}); });
} }
@ -332,7 +332,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
} }
private handleImportSuccess() { private handleImportSuccess() {
this.fetchOrders(); this.fetchActivities();
this.snackBar.open('✅ Import has been completed', undefined, { this.snackBar.open('✅ Import has been completed', undefined, {
duration: 3000 duration: 3000
@ -376,7 +376,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
if (transaction) { if (transaction) {
this.dataService.postOrder(transaction).subscribe({ this.dataService.postOrder(transaction).subscribe({
next: () => { next: () => {
this.fetchOrders(); this.fetchActivities();
} }
}); });
} }

83
apps/client/src/app/services/data.service.ts

@ -59,10 +59,81 @@ export class DataService {
}); });
} }
public fetchAccount(aAccountId: string) {
return this.http.get<Accounts>('/api/v1/account').pipe(
map((response) => {
return response.accounts.find((account) => {
return account.id === aAccountId;
});
})
);
}
public fetchAccounts() { public fetchAccounts() {
return this.http.get<Accounts>('/api/v1/account'); return this.http.get<Accounts>('/api/v1/account');
} }
public fetchActivities({
filters
}: {
filters?: Filter[];
}): Observable<Activities> {
let params = new HttpParams();
if (filters?.length > 0) {
const {
ACCOUNT: filtersByAccount,
ASSET_CLASS: filtersByAssetClass,
TAG: filtersByTag
} = groupBy(filters, (filter) => {
return filter.type;
});
if (filtersByAccount) {
params = params.append(
'accounts',
filtersByAccount
.map(({ id }) => {
return id;
})
.join(',')
);
}
if (filtersByAssetClass) {
params = params.append(
'assetClasses',
filtersByAssetClass
.map(({ id }) => {
return id;
})
.join(',')
);
}
if (filtersByTag) {
params = params.append(
'tags',
filtersByTag
.map(({ id }) => {
return id;
})
.join(',')
);
}
}
return this.http.get<any>('/api/v1/order', { params }).pipe(
map(({ activities }) => {
for (const activity of activities) {
activity.createdAt = parseISO(activity.createdAt);
activity.date = parseISO(activity.date);
}
return { activities };
})
);
}
public fetchAdminData() { public fetchAdminData() {
return this.http.get<AdminData>('/api/v1/admin'); return this.http.get<AdminData>('/api/v1/admin');
} }
@ -179,18 +250,6 @@ export class DataService {
); );
} }
public fetchOrders(): Observable<Activities> {
return this.http.get<any>('/api/v1/order').pipe(
map(({ activities }) => {
for (const activity of activities) {
activity.createdAt = parseISO(activity.createdAt);
activity.date = parseISO(activity.date);
}
return { activities };
})
);
}
public fetchPortfolioDetails({ filters }: { filters?: Filter[] }) { public fetchPortfolioDetails({ filters }: { filters?: Filter[] }) {
let params = new HttpParams(); let params = new HttpParams();

3
libs/common/src/lib/types/account-with-value.type.ts

@ -1,7 +1,8 @@
import { Account as AccountModel } from '@prisma/client'; import { Account as AccountModel, Platform } from '@prisma/client';
export type AccountWithValue = AccountModel & { export type AccountWithValue = AccountModel & {
balanceInBaseCurrency: number; balanceInBaseCurrency: number;
Platform?: Platform;
transactionCount: number; transactionCount: number;
value: number; value: number;
valueInBaseCurrency: number; valueInBaseCurrency: number;

Loading…
Cancel
Save