Browse Source

Add support for creating account cash balances from the account detail dialogue tab

pull/3260/head
Sonlis 1 year ago
committed by Thomas Kaul
parent
commit
a2a836572b
  1. 24
      apps/api/src/app/account-balance/account-balance.controller.ts
  2. 25
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts
  3. 1
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html
  4. 28
      apps/client/src/app/services/data.service.ts
  5. 3
      libs/common/src/lib/permissions.ts
  6. 41
      libs/ui/src/lib/account-balances/account-balances.component.html
  7. 7
      libs/ui/src/lib/account-balances/account-balances.component.scss
  8. 37
      libs/ui/src/lib/account-balances/account-balances.component.ts

24
apps/api/src/app/account-balance/account-balance.controller.ts

@ -5,6 +5,8 @@ import type { RequestWithUser } from '@ghostfolio/common/types';
import { import {
Controller, Controller,
Body,
Post,
Delete, Delete,
HttpException, HttpException,
Inject, Inject,
@ -46,4 +48,26 @@ export class AccountBalanceController {
id id
}); });
} }
@HasPermission(permissions.createAccountBalance)
@Post()
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async createAccountBalance(
@Body() body: any
): Promise<AccountBalance> {
const account = body.Account.connect.id_userId;
const data = {
Account: {
connect: {
id_userId: {
id: account.id,
userId: account.userId
}
}
},
value: body.balance,
date: body.date
};
return this.accountBalanceService.createAccountBalance(data);
}
} }

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

@ -140,6 +140,31 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
this.dialogRef.close(); this.dialogRef.close();
} }
public onAddAccountBalance({
date,
balance
}: {
date: string;
balance: number;
}) {
const formattedDate = new Date(date);
this.dataService
.postAccountBalance({
userId: this.user.id,
accountId: this.data.accountId,
balance: balance,
currency: this.currency,
date: formattedDate
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe({
next: () => {
this.fetchAccountBalances();
this.fetchPortfolioPerformance();
}
});
}
public onDeleteAccountBalance(aId: string) { public onDeleteAccountBalance(aId: string) {
this.dataService this.dataService
.deleteAccountBalance(aId) .deleteAccountBalance(aId)

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

@ -122,6 +122,7 @@
hasPermissionToDeleteAccountBalance && hasPermissionToDeleteAccountBalance &&
!user.settings.isRestrictedView !user.settings.isRestrictedView
" "
(accountBalanceCreated)="onAddAccountBalance($event)"
(accountBalanceDeleted)="onDeleteAccountBalance($event)" (accountBalanceDeleted)="onDeleteAccountBalance($event)"
/> />
</mat-tab> </mat-tab>

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

@ -611,6 +611,34 @@ export class DataService {
return this.http.post<OrderModel>(`/api/v1/account`, aAccount); return this.http.post<OrderModel>(`/api/v1/account`, aAccount);
} }
public postAccountBalance({
date,
accountId,
balance,
currency,
userId
}: {
date: Date;
accountId: string;
balance: number;
currency: string;
userId: string;
}) {
return this.http.post<any>(`/api/v1/account-balance`, {
Account: {
connect: {
id_userId: {
id: accountId,
userId
}
}
},
currency,
date,
balance: balance
});
}
public postBenchmark(benchmark: UniqueAsset) { public postBenchmark(benchmark: UniqueAsset) {
return this.http.post(`/api/v1/benchmark`, benchmark); return this.http.post(`/api/v1/benchmark`, benchmark);
} }

3
libs/common/src/lib/permissions.ts

@ -7,6 +7,7 @@ export const permissions = {
accessAssistant: 'accessAssistant', accessAssistant: 'accessAssistant',
createAccess: 'createAccess', createAccess: 'createAccess',
createAccount: 'createAccount', createAccount: 'createAccount',
createAccountBalance: 'createAccountBalance',
createOrder: 'createOrder', createOrder: 'createOrder',
createPlatform: 'createPlatform', createPlatform: 'createPlatform',
createTag: 'createTag', createTag: 'createTag',
@ -47,6 +48,7 @@ export function getPermissions(aRole: Role): string[] {
permissions.accessAssistant, permissions.accessAssistant,
permissions.createAccess, permissions.createAccess,
permissions.createAccount, permissions.createAccount,
permissions.createAccountBalance,
permissions.deleteAccountBalance, permissions.deleteAccountBalance,
permissions.createOrder, permissions.createOrder,
permissions.createPlatform, permissions.createPlatform,
@ -75,6 +77,7 @@ export function getPermissions(aRole: Role): string[] {
permissions.accessAssistant, permissions.accessAssistant,
permissions.createAccess, permissions.createAccess,
permissions.createAccount, permissions.createAccount,
permissions.createAccountBalance,
permissions.createOrder, permissions.createOrder,
permissions.deleteAccess, permissions.deleteAccess,
permissions.deleteAccount, permissions.deleteAccount,

41
libs/ui/src/lib/account-balances/account-balances.component.html

@ -1,3 +1,4 @@
<form [formGroup]="accountBalanceForm" (ngSubmit)="onSubmitAccountBalance()">
<table <table
class="gf-table w-100" class="gf-table w-100"
mat-table mat-table
@ -13,6 +14,20 @@
<td *matCellDef="let element" class="px-2" mat-cell> <td *matCellDef="let element" class="px-2" mat-cell>
<gf-value [isDate]="true" [locale]="locale" [value]="element?.date" /> <gf-value [isDate]="true" [locale]="locale" [value]="element?.date" />
</td> </td>
<td *matFooterCellDef class="px-2" mat-footer-cell>
<mat-form-field appearance="outline">
<mat-label i18n>Date</mat-label>
<input formControlName="date" matInput [matDatepicker]="date" />
<mat-datepicker-toggle matSuffix [for]="date">
<ion-icon
class="text-muted"
matDatepickerToggleIcon
name="calendar-clear-outline"
/>
</mat-datepicker-toggle>
<mat-datepicker #date disabled="false" />
</mat-form-field>
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
@ -29,6 +44,18 @@
/> />
</div> </div>
</td> </td>
<td *matFooterCellDef class="px-2" mat-footer-cell>
<div class="d-flex justify-content-end">
<mat-form-field apperance="outline">
<input
formControlName="balance"
matInput
placeholder="Value"
type="number"
/>
</mat-form-field>
</div>
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions" stickyEnd> <ng-container matColumnDef="actions" stickyEnd>
@ -53,8 +80,22 @@
</button> </button>
</mat-menu> </mat-menu>
</td> </td>
<td *matFooterCellDef class="px-1 text-center" mat-footer-cell>
<button
class="mx-1 no-min-width px-2"
color="primary"
mat-flat-button
type="submit"
[disabled]="accountBalanceForm.invalid"
>
<ion-icon name="add" />
<span i18n>Add</span>
</button>
</td>
</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></tr>
<tr *matFooterRowDef="displayedColumns" mat-footer-row></tr>
</table> </table>
</form>

7
libs/ui/src/lib/account-balances/account-balances.component.scss

@ -1,3 +1,10 @@
:host { :host {
display: block; display: block;
} }
:host-context(.is-dark-theme) {
input {
color: rgb(var(--light-primary-text));
background-color: rgb(var(--palette-foreground-text-light));
}
}

37
libs/ui/src/lib/account-balances/account-balances.component.ts

@ -14,7 +14,17 @@ import {
Output, Output,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import {
FormGroup,
FormControl,
Validators,
ReactiveFormsModule
} from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { DateAdapter } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu'; import { MatMenuModule } from '@angular/material/menu';
import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { MatTableDataSource, MatTableModule } from '@angular/material/table';
@ -29,9 +39,13 @@ import { GfValueComponent } from '../value';
CommonModule, CommonModule,
GfValueComponent, GfValueComponent,
MatButtonModule, MatButtonModule,
MatDatepickerModule,
MatFormFieldModule,
MatInputModule,
MatMenuModule, MatMenuModule,
MatSortModule, MatSortModule,
MatTableModule MatTableModule,
ReactiveFormsModule
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-account-balances', selector: 'gf-account-balances',
@ -47,10 +61,16 @@ export class GfAccountBalancesComponent
@Input() locale = getLocale(); @Input() locale = getLocale();
@Input() showActions = true; @Input() showActions = true;
@Output() accountBalanceCreated = new EventEmitter<{
balance: number;
date: string;
}>();
@Output() accountBalanceDeleted = new EventEmitter<string>(); @Output() accountBalanceDeleted = new EventEmitter<string>();
@ViewChild(MatSort) sort: MatSort; @ViewChild(MatSort) sort: MatSort;
public Validators = Validators;
public dataSource: MatTableDataSource< public dataSource: MatTableDataSource<
AccountBalancesResponse['balances'][0] AccountBalancesResponse['balances'][0]
> = new MatTableDataSource(); > = new MatTableDataSource();
@ -58,9 +78,16 @@ export class GfAccountBalancesComponent
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
public constructor() {} public constructor(private dateAdapter: DateAdapter<any>) {}
public accountBalanceForm = new FormGroup({
balance: new FormControl(0, Validators.required),
date: new FormControl(new Date().toISOString(), Validators.required)
});
public ngOnInit() {} public ngOnInit() {
this.dateAdapter.setLocale(this.locale);
}
public ngOnChanges() { public ngOnChanges() {
if (this.accountBalances) { if (this.accountBalances) {
@ -81,6 +108,10 @@ export class GfAccountBalancesComponent
} }
} }
public onSubmitAccountBalance() {
this.accountBalanceCreated.emit(this.accountBalanceForm.getRawValue());
}
public ngOnDestroy() { public ngOnDestroy() {
this.unsubscribeSubject.next(); this.unsubscribeSubject.next();
this.unsubscribeSubject.complete(); this.unsubscribeSubject.complete();

Loading…
Cancel
Save