forked from Kispi/Core
feat(webapp): add modal for bank operations
This commit is contained in:
parent
8151cad10b
commit
4555ca1140
5 changed files with 234 additions and 7 deletions
20
src/components/atoms/AtomCurrencyInput.vue
Normal file
20
src/components/atoms/AtomCurrencyInput.vue
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<AtomInput
|
||||||
|
ref="input"
|
||||||
|
type="number"
|
||||||
|
class="text-right pr-16"
|
||||||
|
step="1"
|
||||||
|
/>
|
||||||
|
<span class="text-sm opacity-50 absolute -ml-16 top-2/4 -mt-8 pointer-events-none">,00 Öro</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import AtomInput from './AtomInput.vue';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
32
src/components/atoms/AtomInput.vue
Normal file
32
src/components/atoms/AtomInput.vue
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<template>
|
||||||
|
<input
|
||||||
|
ref="input"
|
||||||
|
:type="type"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
class="input input-bordered w-full max-w-xs"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineProps({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text',
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
input::-webkit-outer-spin-button,
|
||||||
|
input::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
input[type=number] {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
38
src/components/atoms/AtomModal.vue
Normal file
38
src/components/atoms/AtomModal.vue
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
|
<input
|
||||||
|
:id="id"
|
||||||
|
type="checkbox"
|
||||||
|
class="modal-toggle"
|
||||||
|
@change="$emit('open', {id, open: ($event.target as HTMLInputElement).checked})"
|
||||||
|
/>
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-box">
|
||||||
|
<h3 class="font-bold text-lg">{{ title }}</h3>
|
||||||
|
<p class="py-4"><slot /></p>
|
||||||
|
<div class="modal-action">
|
||||||
|
<slot name="action" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
defineEmits(['open']);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
82
src/components/molecules/MoleculeInputModal.vue
Normal file
82
src/components/molecules/MoleculeInputModal.vue
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<AtomModal
|
||||||
|
:id="id"
|
||||||
|
:title="title"
|
||||||
|
@open="handleOpen"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between place-items-center">
|
||||||
|
<span>{{ inputLabel }}</span>
|
||||||
|
<AtomCurrencyInput
|
||||||
|
ref="input"
|
||||||
|
class="w-4/12"
|
||||||
|
@keyup.enter="handleSubmit()"
|
||||||
|
@keyup.esc="abortButton.click()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<template #action>
|
||||||
|
<label
|
||||||
|
ref="abortButton"
|
||||||
|
class="btn gap-2"
|
||||||
|
:for="id"
|
||||||
|
>
|
||||||
|
<XCircleIcon class="w-6 h-6" />
|
||||||
|
Abbrechen
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
class="btn gap-2"
|
||||||
|
@click="handleSubmit()"
|
||||||
|
>
|
||||||
|
<CheckCircleIcon class="w-6 h-6" />
|
||||||
|
{{ actionLabel }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</AtomModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { CheckCircleIcon, XCircleIcon } from '@heroicons/vue/outline';
|
||||||
|
import AtomModal from '../atoms/AtomModal.vue';
|
||||||
|
import AtomCurrencyInput from '../atoms/AtomCurrencyInput.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const input = ref();
|
||||||
|
const abortButton = ref();
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
actionLabel: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
inputLabel: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['submit']);
|
||||||
|
|
||||||
|
function handleOpen(event: {id: string, open: boolean}) {
|
||||||
|
if(event.open) {
|
||||||
|
// This is (currently) the only method to focus a input field inside a custom component.
|
||||||
|
input.value.$refs.input.$refs.input.value = '';
|
||||||
|
input.value.$refs.input.$refs.input.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
emit('submit', input.value.$refs.input.$refs.input.value);
|
||||||
|
abortButton.value.click();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -10,27 +10,62 @@
|
||||||
/>
|
/>
|
||||||
</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="sticky flex place-content-center lg:gap-32 gap-16 bg-base-100 bottom-0 w-100 p-5">
|
||||||
<button class="btn gap-2">
|
<MoleculeInputModal
|
||||||
|
:id="depositModalId"
|
||||||
|
title="Einzahlung"
|
||||||
|
action-label="Einzahlen"
|
||||||
|
input-label="Einzuzahlender Betrag:"
|
||||||
|
@submit="handleDeposit"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
class="btn gap-2"
|
||||||
|
:for="depositModalId"
|
||||||
|
>
|
||||||
<ChevronUpIcon class="w-6 h-6 text-success" />
|
<ChevronUpIcon class="w-6 h-6 text-success" />
|
||||||
Einzahlen
|
Einzahlen
|
||||||
</button>
|
</label>
|
||||||
<button class="btn gap-2">
|
<MoleculeInputModal
|
||||||
|
:id="salaryModalId"
|
||||||
|
title="Gehalt"
|
||||||
|
action-label="Gehalt hinzufügen"
|
||||||
|
input-label="Gehalt Betrag:"
|
||||||
|
@submit="handleSalary"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
class="btn gap-2"
|
||||||
|
:for="salaryModalId"
|
||||||
|
>
|
||||||
<CurrencyDollarIcon class="w-6 h-6 text-warning" />
|
<CurrencyDollarIcon class="w-6 h-6 text-warning" />
|
||||||
Gehalt
|
Gehalt
|
||||||
</button>
|
</label>
|
||||||
<button class="btn gap-2">
|
<MoleculeInputModal
|
||||||
|
:id="withdrawModalId"
|
||||||
|
title="Auszahlung"
|
||||||
|
action-label="Auszahlen"
|
||||||
|
input-label="Auszuzahlender Betrag:"
|
||||||
|
@submit="handleWithdraw"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
class="btn gap-2"
|
||||||
|
:for="withdrawModalId"
|
||||||
|
>
|
||||||
<ChevronDownIcon class="w-6 h-6 text-error" />
|
<ChevronDownIcon class="w-6 h-6 text-error" />
|
||||||
Auszahlen
|
Auszahlen
|
||||||
</button>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ITransaction } from '../../interfaces/transaction.interface';
|
import { ITransaction } from '../../interfaces/transaction.interface';
|
||||||
import { CurrencyService } from '../services/currency.service';
|
import { CurrencyService } from '../services/currency.service';
|
||||||
import MoleculeTransactionTable from '../molecules/MoleculeTransactionTable.vue';
|
|
||||||
import { CurrencyDollarIcon, ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/outline';
|
import { CurrencyDollarIcon, ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/outline';
|
||||||
|
import MoleculeTransactionTable from '../molecules/MoleculeTransactionTable.vue';
|
||||||
|
import MoleculeInputModal from '../molecules/MoleculeInputModal.vue';
|
||||||
|
import { onKeyStroke } from '@vueuse/core';
|
||||||
|
|
||||||
|
const depositModalId = 'deposit-modal';
|
||||||
|
const salaryModalId = 'salary-modal';
|
||||||
|
const withdrawModalId = 'withdraw-modal';
|
||||||
const balance = 13500;
|
const balance = 13500;
|
||||||
const transactions: ITransaction[] = [
|
const transactions: ITransaction[] = [
|
||||||
{
|
{
|
||||||
|
@ -99,6 +134,26 @@ const transactions: ITransaction[] = [
|
||||||
amount: -2000,
|
amount: -2000,
|
||||||
},
|
},
|
||||||
].sort((a, b) => b.date.getTime() - a.date.getTime());
|
].sort((a, b) => b.date.getTime() - a.date.getTime());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
onKeyStroke('e', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
console.log('e pressed');
|
||||||
|
// TODO: open deposit modal
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleDeposit(amount: number) {
|
||||||
|
console.log('Deposit:', amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSalary(amount: number) {
|
||||||
|
console.log('Salary:', amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWithdraw(amount: number) {
|
||||||
|
console.log('Withdraw:', amount);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
Loading…
Reference in a new issue