cents/apps/web/src/components/QuickEntryHost.vue

75 lines
2.6 KiB
Vue

<script setup lang="ts">
import { BarChart3, BookOpen, Check, CircleUserRound, LibraryBig, Plus } from "@lucide/vue";
import { computed, onMounted, ref } from "vue";
import { useRoute } from "vue-router";
import { createEntry } from "../data/entries";
import { useEntryStore } from "../stores/entries";
import { useAuthStore } from "../stores/auth";
import { useLedgerStore } from "../stores/ledgers";
import QuickEntryDrawer from "./QuickEntryDrawer.vue";
const route = useRoute();
const entryStore = useEntryStore();
const authStore = useAuthStore();
const ledgerStore = useLedgerStore();
const drawerOpen = ref(false);
const savedToast = ref(false);
const ledgerOptions = computed(() =>
ledgerStore.ledgers.map((ledger) => ({ id: ledger.id, name: ledger.name, color: ledger.color })),
);
onMounted(async () => {
if (!ledgerStore.loaded) await ledgerStore.loadLedgers();
});
async function saveEntry(input: {
type: "expense" | "income";
amount: number;
categoryId: string;
note: string;
occurredAt: string;
ledgerIds: string[];
}) {
const ledger = ledgerStore.currentLedger;
if (!ledger) return;
await entryStore.addEntry(createEntry({
...input,
currency: ledger.defaultCurrency,
createdBy: authStore.user?.id,
}));
drawerOpen.value = false;
savedToast.value = true;
window.setTimeout(() => (savedToast.value = false), 1800);
}
</script>
<template>
<nav class="bottom-nav" aria-label="主导航">
<RouterLink to="/" :class="{ active: route.name === 'ledger' }"><BookOpen :size="20" /><span>流水</span></RouterLink>
<RouterLink to="/stats" :class="{ active: route.name === 'stats' }"><BarChart3 :size="20" /><span>统计</span></RouterLink>
<span class="nav-spacer"></span>
<RouterLink to="/ledgers" :class="{ active: route.name === 'ledgers' }"><LibraryBig :size="20" /><span>账本</span></RouterLink>
<RouterLink to="/me" :class="{ active: route.name === 'me' }"><CircleUserRound :size="20" /><span>我的</span></RouterLink>
</nav>
<button v-if="!drawerOpen" class="add-entry-button" type="button" aria-label="记一笔" title="记一笔" @click="drawerOpen = true">
<Plus :size="28" />
</button>
<Transition name="drawer">
<QuickEntryDrawer
v-if="drawerOpen && ledgerStore.currentLedger"
:ledger-id="ledgerStore.currentLedger.id"
:ledger-name="ledgerStore.currentLedger.name"
:ledger-options="ledgerOptions"
@close="drawerOpen = false"
@save="saveEntry"
/>
</Transition>
<Transition name="toast">
<div v-if="savedToast" class="saved-toast" role="status"><Check :size="17" />已记入账本</div>
</Transition>
</template>