forked from Kispi/Core
		
	feat(webapp): add backend to bank view
This commit is contained in:
		
							parent
							
								
									069da4fc5e
								
							
						
					
					
						commit
						4915be99b8
					
				
					 6 changed files with 130 additions and 90 deletions
				
			
		|  | @ -11,7 +11,7 @@ | |||
|         <td> | ||||
|           <div class="flex items-center"> | ||||
|             <div> | ||||
|               <div class="font-bold">{{ transaction.type }}</div> | ||||
|               <div class="font-bold">{{ transaction.label }}</div> | ||||
|               <div>{{ DateService.toString(transaction.date) }}</div> | ||||
|             </div> | ||||
|           </div> | ||||
|  |  | |||
							
								
								
									
										54
									
								
								src/components/services/bank.service.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/components/services/bank.service.ts
									
										
									
									
									
										Normal 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, | ||||
| } | ||||
|  | @ -6,6 +6,7 @@ export class DateService { | |||
|       year: 'numeric', | ||||
|       hour: '2-digit', | ||||
|       minute: '2-digit', | ||||
|       second: '2-digit', | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | @ -1,15 +1,18 @@ | |||
| <template> | ||||
|   <div class="hero-content flex-col text-center lg:p-6 pt-0"> | ||||
|     <h1 class="text-8xl mt-5">{{ CurrencyService.toString(balance) }}</h1> | ||||
|     <h3 class="text-5xl font-bold mt-10">Kontoinhaber: John Doe</h3> | ||||
|     <h4 class="text-4xl mb-10">Kontonummer: 0000123456</h4> | ||||
|   <div | ||||
|     v-if="accountDetails" | ||||
|     class="hero-content flex-col text-center lg:p-6 pt-0" | ||||
|   > | ||||
|     <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 | ||||
|       class="w-[42rem]" | ||||
|       :balance="balance" | ||||
|       :transactions="transactions" | ||||
|       class="w-[42rem] mb-24" | ||||
|       :balance="accountDetails.balance" | ||||
|       :transactions="accountDetails.transactions" | ||||
|     /> | ||||
|   </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 | ||||
|       :id="depositModalId" | ||||
|       title="Einzahlung" | ||||
|  | @ -18,6 +21,7 @@ | |||
|       @submit="handleDeposit" | ||||
|     /> | ||||
|     <label | ||||
|       ref="depositModalLabel" | ||||
|       class="btn gap-2" | ||||
|       :for="depositModalId" | ||||
|     > | ||||
|  | @ -32,6 +36,7 @@ | |||
|       @submit="handleSalary" | ||||
|     /> | ||||
|     <label | ||||
|       ref="salaryModalLabel" | ||||
|       class="btn gap-2" | ||||
|       :for="salaryModalId" | ||||
|     > | ||||
|  | @ -46,6 +51,7 @@ | |||
|       @submit="handleWithdraw" | ||||
|     /> | ||||
|     <label | ||||
|       ref="withdrawModalLabel" | ||||
|       class="btn gap-2" | ||||
|       :for="withdrawModalId" | ||||
|     > | ||||
|  | @ -62,97 +68,67 @@ import { CurrencyDollarIcon, ChevronDownIcon, ChevronUpIcon } from '@heroicons/v | |||
| import MoleculeTransactionTable from '../molecules/MoleculeTransactionTable.vue'; | ||||
| import MoleculeInputModal from '../molecules/MoleculeInputModal.vue'; | ||||
| 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 salaryModalId = 'salary-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', (e) => { | ||||
| onKeyStroke(['e', 'g', 'a'], (e) => { | ||||
|   e.preventDefault(); | ||||
|   console.log('e pressed'); | ||||
|   // TODO: open deposit modal | ||||
|   switch (e.key) { | ||||
|   case 'e': | ||||
|     depositModalLabel.value?.click(); | ||||
|     break; | ||||
|   case 'g': | ||||
|     salaryModalLabel.value?.click(); | ||||
|     break; | ||||
|   case 'a': | ||||
|     withdrawModalLabel.value?.click(); | ||||
|     break; | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| function handleDeposit(amount: number) { | ||||
|   console.log('Deposit:', amount); | ||||
| async function handleDeposit(amount: string) { | ||||
|   const amountNumber = parseInt(amount); | ||||
|   if(!isNaN(amountNumber)) { | ||||
|     updateTransactions(await BankService.addTransaction(DEMO_ACCOUNT_ID, amountNumber, TransactionType.DEPOSIT)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function handleSalary(amount: number) { | ||||
|   console.log('Salary:', amount); | ||||
| async function handleSalary(amount: string) { | ||||
|   const amountNumber = parseInt(amount); | ||||
|   if(!isNaN(amountNumber)) { | ||||
|     updateTransactions(await BankService.addTransaction(DEMO_ACCOUNT_ID, amountNumber, TransactionType.SALARY)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function handleWithdraw(amount: number) { | ||||
|   console.log('Withdraw:', amount); | ||||
| async function handleWithdraw(amount: string) { | ||||
|   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> | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										9
									
								
								src/interfaces/account.interface.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/interfaces/account.interface.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| import { ITransaction } from './transaction.interface'; | ||||
| 
 | ||||
| export interface IAccount { | ||||
|   accountNumber: string; | ||||
|   firstName: string; | ||||
|   lastName: string; | ||||
|   balance: number; | ||||
|   transactions: ITransaction[]; | ||||
| } | ||||
|  | @ -1,5 +1,5 @@ | |||
| export interface ITransaction { | ||||
|   type: string; | ||||
|   date: Date; | ||||
|   label: string; | ||||
|   amount: number; | ||||
|   date: Date; | ||||
| } | ||||
		Loading…
	
	Add table
		
		Reference in a new issue