Add dialog for cash transfer between accounts (#2433)

* Add dialog for cash transfer between accounts

---------

Co-authored-by: Thomas <4159106+dtslvr@users.noreply.github.com>
pull/2479/head
Aldrin 1 year ago committed by GitHub
parent d40bc5070a
commit e60fe48fdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,12 @@
import { IsNumber, IsString } from 'class-validator';
export class TransferBalanceDto {
@IsString()
accountIdFrom: string;
@IsString()
accountIdTo: string;
@IsNumber()
balance: number;
}

@ -1,3 +1,14 @@
<div *ngIf="false" class="d-flex justify-content-end">
<button
class="align-items-center d-flex"
mat-stroked-button
(click)="onTransferBalance()"
>
<ion-icon class="mr-2" name="arrow-redo-outline"></ion-icon>
<ng-container i18n>Transfer Cash Balance</ng-container>...
</button>
</div>
<table class="gf-table w-100" mat-table matSort [dataSource]="dataSource">
<ng-container matColumnDef="status">
<th

@ -34,6 +34,7 @@ export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit {
@Output() accountDeleted = new EventEmitter<string>();
@Output() accountToUpdate = new EventEmitter<AccountModel>();
@Output() transferBalance = new EventEmitter<void>();
@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);
}

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

@ -14,6 +14,7 @@
[transactionCount]="transactionCount"
(accountDeleted)="onDeleteAccount($event)"
(accountToUpdate)="onUpdateAccount($event)"
(transferBalance)="onTransferBalance()"
></gf-accounts-table>
</div>
</div>

@ -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
],

@ -0,0 +1,5 @@
import { Account } from '@prisma/client';
export interface TransferBalanceDialogParams {
accounts: Account[];
}

@ -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<void>();
public constructor(
@Inject(MAT_DIALOG_DATA) public data: TransferBalanceDialogParams,
public dialogRef: MatDialogRef<TransferBalanceDialog>,
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();
}
}

@ -0,0 +1,53 @@
<form
class="d-flex flex-column h-100"
[formGroup]="transferBalanceForm"
(keyup.enter)="transferBalanceForm.valid && onSubmit()"
(ngSubmit)="onSubmit()"
>
<h1 i18n mat-dialog-title>Transfer Cash Balance</h1>
<div class="flex-grow-1 py-3" mat-dialog-content>
<div>
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>From</mat-label>
<mat-select formControlName="fromAccount">
<mat-option *ngFor="let account of accounts" [value]="account.id"
>{{ account.name }}</mat-option
>
</mat-select>
</mat-form-field>
</div>
<div>
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>To</mat-label>
<mat-select formControlName="toAccount">
<mat-option *ngFor="let account of accounts" [value]="account.id"
>{{ account.name }}</mat-option
>
</mat-select>
</mat-form-field>
</div>
<div>
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Value</mat-label>
<input
formControlName="balance"
matInput
type="number"
(keydown.enter)="$event.stopPropagation()"
/>
<span class="ml-2" matTextSuffix>{{ currency }}</span>
</mat-form-field>
</div>
</div>
<div class="justify-content-end" mat-dialog-actions>
<button i18n mat-button type="button" (click)="onCancel()">Cancel</button>
<button
color="primary"
mat-flat-button
type="submit"
[disabled]="!transferBalanceForm.valid"
>
<ng-container i18n>Transfer</ng-container>
</button>
</div>
</form>

@ -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 {}

@ -0,0 +1,7 @@
:host {
display: block;
.mat-mdc-dialog-content {
max-height: unset;
}
}
Loading…
Cancel
Save