Optimise invoice data requests #56

This commit is contained in:
2025-11-18 10:27:49 +01:00
parent d3b6371105
commit 6d67d3d6cd
14 changed files with 308 additions and 972 deletions
+38 -45
View File
@@ -1,15 +1,13 @@
<script setup lang="ts">
import { computed, ref, onMounted, watch, defineProps, HTMLAttributes } from 'vue'
import { type Invoice, type Customer, type Address } from '@/types'
import { newInvoice } from '@/types/index.d'
import { computed, ref, onMounted } from 'vue'
import { type Invoice } from '@/types'
import axios from 'axios'
import AppLayout from '@/layouts/AppLayout.vue'
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, } from '@/components/ui/select'
import { Button } from '@/components/ui/button'
import DocumentTable from '@/components/documents/DocumentTable.vue'
import { ChevronLeft, ChevronRight, Plus, Search, Delete } from "lucide-vue-next"
import InvoiceDialog from '@/components/documents/InvoiceDialog.vue'
import Fuse from 'fuse.js';
import { Input } from '@/components/ui/input'
import { toast } from 'vue-sonner'
@@ -18,38 +16,35 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/comp
import { Kbd, KbdGroup } from '@/components/ui/kbd'
import { statusBadgeLabels } from '@/components/ui/status-badge'
import AppHeader from '@/components/AppHeader.vue'
import InvoiceDialog from '@/components/documents/InvoiceDialog.vue'
const invoicesData = ref([] as Invoice[])
const activeInvoice = ref<Invoice | null>(null)
const customersData = ref([] as Customer[])
// initial invoice data from inertia
interface Props {
invoicesData: Invoice[];
}
const props = defineProps<Props>();
const invoicesData = ref(props.invoicesData || [])
const activeInvoice = ref<Invoice | undefined>(undefined)
const selectedYearIndex = ref(0)
const detailDialogOpen = ref(false)
const searchQuery = ref('')
const searchField = ref()
onMounted(async () => {
const invoiceResponse = await axios.get('/api/invoices')
invoicesData.value = invoiceResponse.data as Invoice[]
const customerResponse = await axios.get('/api/customers')
customersData.value = customerResponse.data as Customer[]
searchField.value = document.getElementById('search')
// Load older invoices after initial page load
try {
const invoiceBeforeThisYearResponse = await axios.get('/api/invoices/summaryBeforeThisYear')
invoicesData.value = invoicesData.value.concat(invoiceBeforeThisYearResponse.data as Invoice[])
} catch (error) {
console.error('Fehler beim Laden der Daten:', error)
}
let queryString = window.location.search
let params = new URLSearchParams(queryString)
if (params.get('action') == 'new') showDetail(newInvoice())
})
if (params.get('action') == 'new') editInvoice()
watch(invoicesData, () => {
// Die watch-Funktion wird automatisch ausgelöst, wenn sich invoicesData ändert
// Das filteredInvoices-Array wird automatisch aktualisiert
// Fügen Sie eine kleine Verzögerung hinzu, um sicherzustellen, dass die Daten aktualisiert werden
setTimeout(() => {
// Die watch-Funktion wird automatisch ausgelöst, wenn sich invoicesData ändert
// Das filteredInvoices-Array wird automatisch aktualisiert
}, 0);
}, { deep: true });
searchField.value = document.getElementById('search')
})
const years = computed((): number[] => {
const allYears = invoicesData.value.map(invoice => {
@@ -61,10 +56,11 @@ const years = computed((): number[] => {
return uniqueYears
})
// Filter / search
const fuse = computed(() => {
const options = {
keys: [
'customer.companyName',
'billingData.companyName',
{
name: 'paymentStatus',
getFn: (invoice: Invoice) => statusBadgeLabels[invoice.paymentStatus] || invoice.paymentStatus
@@ -79,28 +75,26 @@ const fuse = computed(() => {
})
const filteredInvoices = computed(() => {
// Filter by query
if (!searchQuery.value) {
return years.value[selectedYearIndex.value] ?
invoicesData.value.filter(invoice => {
return years.value[selectedYearIndex.value]
? invoicesData.value.filter(invoice => {
const invoiceDate = new Date(invoice.invoiceDate);
return invoiceDate.getFullYear() === years.value[selectedYearIndex.value];
}) :
invoicesData.value;
})
: invoicesData.value;
}
return fuse.value.search(searchQuery.value)
.map(result => result.item)
.filter(invoice => {
// Stellen Sie sicher, dass die gefilterten Rechnungen auch zum ausgewählten Jahr gehören
const invoiceDate = new Date(invoice.invoiceDate);
return !years.value[selectedYearIndex.value] || invoiceDate.getFullYear() === years.value[selectedYearIndex.value];
});
});
const showDetail = (invoice: Invoice) => {
const editInvoice = (invoice?: Invoice) => {
// make a deep copy, so the changes in the dialog wont affect the data until saved
activeInvoice.value = JSON.parse(JSON.stringify(invoice))
activeInvoice.value = invoice ? JSON.parse(JSON.stringify(invoice)) : null
detailDialogOpen.value = true
}
@@ -171,10 +165,9 @@ const saveInvoice = async (updatedInvoice: Invoice) => {
}
const deleteInvoice = async (id: number) => {
try {
const response = axios.delete('/api/invoices/' + id)
const index = invoicesData.value.findIndex(invoice => invoice.id === id);
await axios.delete('/api/invoices/' + id)
const index = invoicesData.value.findIndex(invoice => invoice.id === id)
if (index !== -1) {
invoicesData.value.splice(index, 1)
}
@@ -189,7 +182,7 @@ const deleteInvoice = async (id: number) => {
<template>
<!-- Function Header -->
<AppLayout title="Rechnungen">
@@ -200,9 +193,10 @@ const deleteInvoice = async (id: number) => {
@click="selectedYearIndex++">
<ChevronLeft />
</Button>
<Select size="sm" v-model="selectedYearIndex" v-if="years.length > 1">
<SelectTrigger class=" hover:bg-accent">
<SelectValue placeholder="Jahr" />
<Select size="sm" v-model="selectedYearIndex">
<SelectTrigger class="hover:bg-accent">
<SelectValue :placeholder="(new Date()).getFullYear().toString()"
:disabled="years.length < 1" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
@@ -240,7 +234,7 @@ const deleteInvoice = async (id: number) => {
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<Button size="sm" variant="action" @click="showDetail(newInvoice())">
<Button size="sm" variant="action" @click="editInvoice()">
<Plus />
Neu
</Button>
@@ -260,11 +254,10 @@ const deleteInvoice = async (id: number) => {
</AppHeader>
<!-- Invoice Table -->
<DocumentTable :invoices="filteredInvoices" :onItemClicked="showDetail" />
<DocumentTable :invoices="filteredInvoices" :onItemClicked="editInvoice" />
<!-- Invoice detail dialog -->
<InvoiceDialog :invoiceData="activeInvoice" :customers="customersData" v-model="detailDialogOpen"
@save="saveInvoice" @delete="deleteInvoice" />
<InvoiceDialog :invoiceData="activeInvoice" v-model="detailDialogOpen" @save="" @delete="" />
</AppLayout>
</template>