diff --git a/apps/api/src/app/account/transfer-balance.dto.ts b/apps/api/src/app/account/transfer-balance.dto.ts new file mode 100644 index 000000000..fb602033e --- /dev/null +++ b/apps/api/src/app/account/transfer-balance.dto.ts @@ -0,0 +1,12 @@ +import { IsNumber, IsString } from 'class-validator'; + +export class TransferBalanceDto { + @IsString() + accountIdFrom: string; + + @IsString() + accountIdTo: string; + + @IsNumber() + balance: number; +} diff --git a/apps/client/src/app/components/accounts-table/accounts-table.component.html b/apps/client/src/app/components/accounts-table/accounts-table.component.html index d3ece8977..664694735 100644 --- a/apps/client/src/app/components/accounts-table/accounts-table.component.html +++ b/apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -1,3 +1,14 @@ +
+ +
+
(); @Output() accountToUpdate = new EventEmitter(); + @Output() transferBalance = new EventEmitter(); @ViewChild(MatSort) sort: MatSort; @@ -97,6 +98,10 @@ export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit { alert(aComment); } + public onTransferBalance() { + this.transferBalance.emit(); + } + public onUpdateAccount(aAccount: AccountModel) { this.accountToUpdate.emit(aAccount); } diff --git a/apps/client/src/app/pages/accounts/accounts-page.component.ts b/apps/client/src/app/pages/accounts/accounts-page.component.ts index ab03340df..18d5d1e2a 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -2,6 +2,7 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto'; +import { TransferBalanceDto } from '@ghostfolio/api/app/account/transfer-balance.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'; @@ -16,6 +17,7 @@ import { Subject, Subscription } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { CreateOrUpdateAccountDialog } from './create-or-update-account-dialog/create-or-update-account-dialog.component'; +import { TransferBalanceDialog } from './transfer-balance/transfer-balance-dialog.component'; @Component({ host: { class: 'page' }, @@ -67,6 +69,8 @@ export class AccountsPageComponent implements OnDestroy, OnInit { } else { this.router.navigate(['.'], { relativeTo: this.route }); } + } else if (params['transferBalanceDialog']) { + this.openTransferBalanceDialog(); } }); } @@ -144,6 +148,12 @@ export class AccountsPageComponent implements OnDestroy, OnInit { }); } + public onTransferBalance() { + this.router.navigate([], { + queryParams: { transferBalanceDialog: true } + }); + } + public onUpdateAccount(aAccount: AccountModel) { this.router.navigate([], { queryParams: { accountId: aAccount.id, editDialog: true } @@ -267,4 +277,30 @@ export class AccountsPageComponent implements OnDestroy, OnInit { this.router.navigate(['.'], { relativeTo: this.route }); }); } + + private openTransferBalanceDialog(): void { + const dialogRef = this.dialog.open(TransferBalanceDialog, { + data: { + accounts: this.accounts + }, + height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); + + dialogRef + .afterClosed() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((data: any) => { + if (data) { + const { accountIdFrom, accountIdTo, balance }: TransferBalanceDto = + data?.account; + + console.log( + `Transfer cash balance of ${balance} from account ${accountIdFrom} to account ${accountIdTo}` + ); + } + + this.router.navigate(['.'], { relativeTo: this.route }); + }); + } } diff --git a/apps/client/src/app/pages/accounts/accounts-page.html b/apps/client/src/app/pages/accounts/accounts-page.html index 6057802df..a7d5901bb 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.html +++ b/apps/client/src/app/pages/accounts/accounts-page.html @@ -14,6 +14,7 @@ [transactionCount]="transactionCount" (accountDeleted)="onDeleteAccount($event)" (accountToUpdate)="onUpdateAccount($event)" + (transferBalance)="onTransferBalance()" > diff --git a/apps/client/src/app/pages/accounts/accounts-page.module.ts b/apps/client/src/app/pages/accounts/accounts-page.module.ts index 9edb43ba7..7de50983c 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.module.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.module.ts @@ -8,6 +8,7 @@ import { GfAccountsTableModule } from '@ghostfolio/client/components/accounts-ta import { AccountsPageRoutingModule } from './accounts-page-routing.module'; import { AccountsPageComponent } from './accounts-page.component'; import { GfCreateOrUpdateAccountDialogModule } from './create-or-update-account-dialog/create-or-update-account-dialog.module'; +import { GfTransferBalanceDialogModule } from './transfer-balance/transfer-balance-dialog.module'; @NgModule({ declarations: [AccountsPageComponent], @@ -17,6 +18,7 @@ import { GfCreateOrUpdateAccountDialogModule } from './create-or-update-account- GfAccountDetailDialogModule, GfAccountsTableModule, GfCreateOrUpdateAccountDialogModule, + GfTransferBalanceDialogModule, MatButtonModule, RouterModule ], diff --git a/apps/client/src/app/pages/accounts/transfer-balance/interfaces/interfaces.ts b/apps/client/src/app/pages/accounts/transfer-balance/interfaces/interfaces.ts new file mode 100644 index 000000000..3a0b921fd --- /dev/null +++ b/apps/client/src/app/pages/accounts/transfer-balance/interfaces/interfaces.ts @@ -0,0 +1,5 @@ +import { Account } from '@prisma/client'; + +export interface TransferBalanceDialogParams { + accounts: Account[]; +} diff --git a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts new file mode 100644 index 000000000..4850e96e3 --- /dev/null +++ b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts @@ -0,0 +1,69 @@ +import { + ChangeDetectionStrategy, + Component, + Inject, + OnDestroy +} from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { TransferBalanceDto } from '@ghostfolio/api/app/account/transfer-balance.dto'; +import { Account } from '@prisma/client'; +import { Subject } from 'rxjs'; + +import { TransferBalanceDialogParams } from './interfaces/interfaces'; + +@Component({ + host: { class: 'h-100' }, + selector: 'gf-transfer-balance-dialog', + changeDetection: ChangeDetectionStrategy.OnPush, + styleUrls: ['./transfer-balance-dialog.scss'], + templateUrl: 'transfer-balance-dialog.html' +}) +export class TransferBalanceDialog implements OnDestroy { + public accounts: Account[] = []; + public currency: string; + public transferBalanceForm: FormGroup; + + private unsubscribeSubject = new Subject(); + + public constructor( + @Inject(MAT_DIALOG_DATA) public data: TransferBalanceDialogParams, + public dialogRef: MatDialogRef, + private formBuilder: FormBuilder + ) {} + + public ngOnInit() { + this.accounts = this.data.accounts; + + this.transferBalanceForm = this.formBuilder.group({ + balance: [0, Validators.required], + fromAccount: ['', Validators.required], + toAccount: ['', Validators.required] + }); + + this.transferBalanceForm.get('fromAccount').valueChanges.subscribe((id) => { + this.currency = this.accounts.find((account) => { + return account.id === id; + }).currency; + }); + } + + public onCancel() { + this.dialogRef.close(); + } + + public onSubmit() { + const account: TransferBalanceDto = { + accountIdFrom: this.transferBalanceForm.controls['fromAccount'].value, + accountIdTo: this.transferBalanceForm.controls['toAccount'].value, + balance: this.transferBalanceForm.controls['balance'].value + }; + + this.dialogRef.close({ account }); + } + + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } +} diff --git a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html new file mode 100644 index 000000000..9cce7b87a --- /dev/null +++ b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html @@ -0,0 +1,53 @@ +
+

Transfer Cash Balance

+
+
+ + From + + {{ account.name }} + + +
+
+ + To + + {{ account.name }} + + +
+
+ + Value + + {{ currency }} + +
+
+
+ + +
+
diff --git a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.module.ts b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.module.ts new file mode 100644 index 000000000..5a56b5810 --- /dev/null +++ b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.module.ts @@ -0,0 +1,24 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; + +import { TransferBalanceDialog } from './transfer-balance-dialog.component'; + +@NgModule({ + declarations: [TransferBalanceDialog], + imports: [ + CommonModule, + MatButtonModule, + MatDialogModule, + MatFormFieldModule, + MatInputModule, + MatSelectModule, + ReactiveFormsModule + ] +}) +export class GfTransferBalanceDialogModule {} diff --git a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.scss b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.scss new file mode 100644 index 000000000..b63df0134 --- /dev/null +++ b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.scss @@ -0,0 +1,7 @@ +:host { + display: block; + + .mat-mdc-dialog-content { + max-height: unset; + } +}