1
0
Fork 0
forked from Kispi/Core

feat(webapp): add backend to bank view

This commit is contained in:
Simon Giesel 2022-07-26 16:28:45 +02:00
parent 069da4fc5e
commit 4915be99b8
6 changed files with 130 additions and 90 deletions

View file

@ -11,7 +11,7 @@
<td> <td>
<div class="flex items-center"> <div class="flex items-center">
<div> <div>
<div class="font-bold">{{ transaction.type }}</div> <div class="font-bold">{{ transaction.label }}</div>
<div>{{ DateService.toString(transaction.date) }}</div> <div>{{ DateService.toString(transaction.date) }}</div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,54 @@
import { AppwriteService } from './appwrite.service';
import { IAccount } from '../../interfaces/account.interface';
import { Databases, Models, Query } from 'appwrite';
import { ITransaction } from '../../interfaces/transaction.interface';
const DATABASE_ID = '62dfd5787755e7ed9fcd';
const ACCOUNTS_COLLECTION_ID = '62dfd6ca06197f9baa86';
const TRANSACTIONS_COLLECTION_ID = '62dfd81b7671727b27cd';
const DEPOSIT_LABEL = 'Bargeldeinzahlung';
const SALARY_LABEL = 'Gehalt';
const WITHDRAW_LABEL = 'Bargeldauszahlung';
const sdk = AppwriteService.getSDK();
export const BankService = {
async getAccountDetails(accountNumber: string): Promise<IAccount> {
const database = new Databases(sdk, DATABASE_ID);
const accountDocument = await database.listDocuments<IAccount & Models.Document>(
ACCOUNTS_COLLECTION_ID, [Query.equal('accountNumber', accountNumber)], 1);
const transactionDocuments = await database.listDocuments<ITransaction & Models.Document>(
TRANSACTIONS_COLLECTION_ID, [Query.equal('accountNumber', accountNumber)], 100, 0, undefined, undefined, ['$createdAt'], ['DESC']);
const account: IAccount = {
accountNumber: accountDocument.documents[0].accountNumber,
firstName: accountDocument.documents[0].firstName,
lastName: accountDocument.documents[0].lastName,
balance: accountDocument.documents[0].balance,
transactions: transactionDocuments.documents.map(transaction => ({
label: transaction.label,
amount: transaction.amount,
date: new Date(transaction.$createdAt * 1000),
})),
};
return account;
},
async addTransaction(accountNumber: string, amount: number, type: TransactionType): Promise<ITransaction> {
const database = new Databases(sdk, DATABASE_ID);
const accountDocument = await database.listDocuments<IAccount & Models.Document>(
ACCOUNTS_COLLECTION_ID, [Query.equal('accountNumber', accountNumber)], 1);
const transactionDocument = await database.createDocument<ITransaction & Models.Document>(TRANSACTIONS_COLLECTION_ID, 'unique()', {
accountNumber: accountNumber,
label: type === TransactionType.DEPOSIT ? DEPOSIT_LABEL : (type === TransactionType.SALARY ? SALARY_LABEL : WITHDRAW_LABEL),
amount: (type === TransactionType.WITHDRAW ? -amount : amount),
});
await database.updateDocument<IAccount & Models.Document>(ACCOUNTS_COLLECTION_ID, accountDocument.documents[0].$id, {
balance: accountDocument.documents[0].balance + (type === TransactionType.WITHDRAW ? -amount : amount),
});
return { label: transactionDocument.label, amount: transactionDocument.amount, date: new Date(transactionDocument.$createdAt * 1000) };
},
};
export enum TransactionType {
DEPOSIT,
SALARY,
WITHDRAW,
}

View file

@ -6,6 +6,7 @@ export class DateService {
year: 'numeric', year: 'numeric',
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit',
second: '2-digit',
}); });
} }
} }

View file

@ -1,15 +1,18 @@
<template> <template>
<div class="hero-content flex-col text-center lg:p-6 pt-0"> <div
<h1 class="text-8xl mt-5">{{ CurrencyService.toString(balance) }}</h1> v-if="accountDetails"
<h3 class="text-5xl font-bold mt-10">Kontoinhaber: John Doe</h3> class="hero-content flex-col text-center lg:p-6 pt-0"
<h4 class="text-4xl mb-10">Kontonummer: 0000123456</h4> >
<h1 class="text-8xl mt-5">{{ CurrencyService.toString(accountDetails.balance) }}</h1>
<h3 class="text-5xl font-bold mt-10">Kontoinhaber: {{ `${accountDetails.firstName} ${accountDetails.lastName}` }}</h3>
<h4 class="text-4xl mb-10">Kontonummer: {{ accountDetails.accountNumber }}</h4>
<MoleculeTransactionTable <MoleculeTransactionTable
class="w-[42rem]" class="w-[42rem] mb-24"
:balance="balance" :balance="accountDetails.balance"
:transactions="transactions" :transactions="accountDetails.transactions"
/> />
</div> </div>
<div class="sticky flex place-content-center lg:gap-32 gap-16 bg-base-100 bottom-0 w-100 p-5"> <div class="fixed flex place-content-center lg:gap-32 gap-16 bg-base-100 bottom-0 lg:w-[calc(100%-16rem)] w-full p-5">
<MoleculeInputModal <MoleculeInputModal
:id="depositModalId" :id="depositModalId"
title="Einzahlung" title="Einzahlung"
@ -18,6 +21,7 @@
@submit="handleDeposit" @submit="handleDeposit"
/> />
<label <label
ref="depositModalLabel"
class="btn gap-2" class="btn gap-2"
:for="depositModalId" :for="depositModalId"
> >
@ -32,6 +36,7 @@
@submit="handleSalary" @submit="handleSalary"
/> />
<label <label
ref="salaryModalLabel"
class="btn gap-2" class="btn gap-2"
:for="salaryModalId" :for="salaryModalId"
> >
@ -46,6 +51,7 @@
@submit="handleWithdraw" @submit="handleWithdraw"
/> />
<label <label
ref="withdrawModalLabel"
class="btn gap-2" class="btn gap-2"
:for="withdrawModalId" :for="withdrawModalId"
> >
@ -62,97 +68,67 @@ import { CurrencyDollarIcon, ChevronDownIcon, ChevronUpIcon } from '@heroicons/v
import MoleculeTransactionTable from '../molecules/MoleculeTransactionTable.vue'; import MoleculeTransactionTable from '../molecules/MoleculeTransactionTable.vue';
import MoleculeInputModal from '../molecules/MoleculeInputModal.vue'; import MoleculeInputModal from '../molecules/MoleculeInputModal.vue';
import { onKeyStroke } from '@vueuse/core'; import { onKeyStroke } from '@vueuse/core';
import { BankService, TransactionType } from '../services/bank.service';
import { onMounted, ref } from 'vue';
import { IAccount } from '../../interfaces/account.interface';
const DEMO_ACCOUNT_ID = '0000123456';
const accountDetails = ref<IAccount>();
const depositModalLabel = ref<HTMLLabelElement>();
const salaryModalLabel = ref<HTMLLabelElement>();
const withdrawModalLabel = ref<HTMLLabelElement>();
onMounted(async () => {
// TODO: Remove this demo account id
accountDetails.value = await BankService.getAccountDetails(DEMO_ACCOUNT_ID);
});
const depositModalId = 'deposit-modal'; const depositModalId = 'deposit-modal';
const salaryModalId = 'salary-modal'; const salaryModalId = 'salary-modal';
const withdrawModalId = 'withdraw-modal'; const withdrawModalId = 'withdraw-modal';
const balance = 135;
const transactions: ITransaction[] = [
{
type: 'Kontoeröffnung',
date: new Date(2022, 7, 12, 17, 30, 0),
amount: 5,
},
{
type: 'Bargeldeinzahlung',
date: new Date(2022, 7, 12, 17, 30, 10),
amount: 100,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Gehalt',
date: new Date(2022, 7, 12, 17, 34, 10),
amount: 50,
},
{
type: 'Bargeldauszahlung',
date: new Date(2022, 7, 15, 18, 26, 0),
amount: -20,
},
].sort((a, b) => b.date.getTime() - a.date.getTime());
onKeyStroke(['e', 'g', 'a'], (e) => {
onKeyStroke('e', (e) => {
e.preventDefault(); e.preventDefault();
console.log('e pressed'); switch (e.key) {
// TODO: open deposit modal case 'e':
depositModalLabel.value?.click();
break;
case 'g':
salaryModalLabel.value?.click();
break;
case 'a':
withdrawModalLabel.value?.click();
break;
}
}); });
function handleDeposit(amount: number) { async function handleDeposit(amount: string) {
console.log('Deposit:', amount); const amountNumber = parseInt(amount);
if(!isNaN(amountNumber)) {
updateTransactions(await BankService.addTransaction(DEMO_ACCOUNT_ID, amountNumber, TransactionType.DEPOSIT));
}
} }
function handleSalary(amount: number) { async function handleSalary(amount: string) {
console.log('Salary:', amount); const amountNumber = parseInt(amount);
if(!isNaN(amountNumber)) {
updateTransactions(await BankService.addTransaction(DEMO_ACCOUNT_ID, amountNumber, TransactionType.SALARY));
}
} }
function handleWithdraw(amount: number) { async function handleWithdraw(amount: string) {
console.log('Withdraw:', amount); const amountNumber = parseInt(amount);
if(!isNaN(amountNumber)) {
updateTransactions(await BankService.addTransaction(DEMO_ACCOUNT_ID, amountNumber, TransactionType.WITHDRAW));
}
}
function updateTransactions(transaction: ITransaction) {
if(accountDetails.value) {
accountDetails.value.balance += transaction.amount;
accountDetails.value.transactions.unshift(transaction);
}
} }
</script> </script>

View file

@ -0,0 +1,9 @@
import { ITransaction } from './transaction.interface';
export interface IAccount {
accountNumber: string;
firstName: string;
lastName: string;
balance: number;
transactions: ITransaction[];
}

View file

@ -1,5 +1,5 @@
export interface ITransaction { export interface ITransaction {
type: string; label: string;
date: Date;
amount: number; amount: number;
date: Date;
} }