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 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" />
|
||||
Einzahlen
|
||||
</button>
|
||||
<button class="btn gap-2">
|
||||
</label>
|
||||
<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" />
|
||||
Gehalt
|
||||
</button>
|
||||
<button class="btn gap-2">
|
||||
</label>
|
||||
<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" />
|
||||
Auszahlen
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ITransaction } from '../../interfaces/transaction.interface';
|
||||
import { CurrencyService } from '../services/currency.service';
|
||||
import MoleculeTransactionTable from '../molecules/MoleculeTransactionTable.vue';
|
||||
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 transactions: ITransaction[] = [
|
||||
{
|
||||
|
@ -99,6 +134,26 @@ const transactions: ITransaction[] = [
|
|||
amount: -2000,
|
||||
},
|
||||
].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>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
Loading…
Reference in a new issue