Connect CalDAV todos to DB-Items, finish todo component and add it to pipeline items

This commit is contained in:
2026-02-24 16:15:21 +01:00
parent 7e2094847f
commit 823cd6391d
27 changed files with 605 additions and 205 deletions
@@ -105,7 +105,7 @@ const calcTaxes = (amount: number) => {
<template>
<Table class="relative document-table">
<TableHeader class="sticky top-0">
<TableHeader class="sticky -top-4 md:-top-6 lg:-top-8">
<TableRow>
<TableHead class="w-1/100 lg:w-1/100 hidden md:table-cell lg:pl-4 lg:pr-5">Nr.</TableHead>
<TableHead class="w-1/100 lg:w-1/20 text-center">Status</TableHead>
@@ -193,7 +193,7 @@ const calcTaxes = (amount: number) => {
</TableRow>
<TableRow v-if="totalNotIssued > 0">
<TableCell colspan="2" class="hidden lg:table-cell"></TableCell>
<TableCell class="hidden lg:table-cell"></TableCell>
<TableCell colspan="2" class="hidden md:table-cell"></TableCell>
<TableCell colspan="1"></TableCell>
<TableCell class="text-right tabular-nums w-1/100 font-bold">Nicht gestellt</TableCell>
@@ -30,6 +30,7 @@ import { Kbd, KbdGroup } from '@/components/ui/kbd'
import DialogClose from "../ui/dialog/DialogClose.vue"
import DialogCloseButton from "../DialogCloseButton/DialogCloseButton.vue"
import SendMailDialog from "../ui/send-mail-dialog/SendMailDialog.vue"
import TextEditor from "../TextEditor.vue"
const DEBUG = ref(false)
@@ -86,8 +87,8 @@ onMounted(async () => {
// Process each response
customers.value = responses[0].data
paymentTerms.value = responses[0].data
units.value = responses[0].data
paymentTerms.value = responses[1].data
units.value = responses[2].data
} catch (error) {
toast.error('Fehler beim Laden der Daten', error || String(error))
@@ -161,7 +162,7 @@ watch(invoice,
return;
}
// If no billing data is store in the invoice, generat ot from customer
// If no billing data is store in the invoice, generate ot from customer
if (!newValue.billingData) {
newValue.billingData = {
companyName: newValue.customer?.companyName || "",
@@ -176,7 +177,7 @@ watch(invoice,
contactSalutation: newValue.customer?.contacts && newValue.customer.contacts.length > 0 ? newValue.customer.contacts[0].salutation : "",
contactFirstName: newValue.customer?.contacts && newValue.customer.contacts.length > 0 ? newValue.customer.contacts[0].firstName : "",
contactLastName: newValue.customer?.contacts && newValue.customer.contacts.length > 0 ? newValue.customer.contacts[0].lastName : "",
paymentTerms: newValue.customer?.paymentTerms || paymentTermsData.value.length > 0 ? paymentTermsData.value[2] : null,
paymentTerms: newValue.customer?.paymentTerms || paymentTerms.value.length > 0 ? paymentTerms.value[2] : null,
}
}
@@ -395,6 +396,7 @@ const exportXml = function () {
const issueInvoice = function () {
if (!invoice.value) return;
invoice.value.paymentStatus = 'issued'
save()
}
const deleteInvoice = function () {
@@ -546,13 +548,12 @@ const handleFileUpload = async (event: Event) => {
<DialogHeader class="p-4 md:p-6 lg:p-12 pb-0 md:pb-2 lg:pb-8 flex flex-row items-start gap-12">
<div class="flex flex-col grow">
<DialogTitle class="text-primary-foreground font-bold text-left">
<DialogTitle class="text-primary font-bold text-left">
<h1>{{ title }}</h1>
</DialogTitle>
<DialogDescription>
<Input v-if="invoice" v-model="invoice.title" :id="'invoice-title'"
class="text-foreground md:text-base text-ellipsis px-0 bg-transparent dark:bg-transparent hover:bg-accent dark:hover:bg-accent/30 border-none shadow-none"
type="text" placeholder="Titel" />
<Input v-if="invoice" v-model="invoice.title" @update:model-value="isDirty = true"
:id="'invoice-title'" class="" type="text" placeholder="Titel" />
</DialogDescription>
</div>
@@ -899,7 +900,10 @@ const handleFileUpload = async (event: Event) => {
</div>
<div id="document-text" class="mt-6 md:mt-8 lg:mt-12">
<GrowingTextarea v-model="invoice.text" placeholder="Anschreiben"
<!-- <GrowingTextarea v-model="invoice.text" placeholder="Anschreiben"
class="font-light bg-transparent dark:bg-transparent hover:bg-accent dark:hover:bg-accent/30 border-none shadow-none" /> -->
<TextEditor v-model="invoice.text" placeholder="Anschreiben"
@change:model-value="isDirty = true"
class="font-light bg-transparent dark:bg-transparent hover:bg-accent dark:hover:bg-accent/30 border-none shadow-none" />
</div>
@@ -24,7 +24,7 @@ import { toast } from "vue-sonner";
import ButtonGroup from '../ui/button-group/ButtonGroup.vue';
const DEBUG = ref(true)
const DEBUG = ref(false)
const props = defineProps<{
isLoading?: boolean,
@@ -60,12 +60,12 @@ watch(() => props.lineItems, async (newLineItems) => {
updateFromParent.value = true
// Only update if the items actually changed
if (JSON.stringify(items.value) !== JSON.stringify(newLineItems)) {
items.value = (newLineItems ?? [])
} else {
console.log('already up to date, no change')
}
// items.value = (newLineItems ?? [])
// if (JSON.stringify(items.value) !== JSON.stringify(newLineItems)) {
// items.value = (newLineItems ?? [])
// } else {
// console.log('already up to date, no change')
// }
items.value = (newLineItems ?? [])
// Reset flag after next tick
await nextTick()
@@ -90,6 +90,7 @@ watch(items, (newItems) => {
// Don't emit changes in loading
if (props.isLoading || updateFromParent.value) return
recalculatePositions()
console.log('emit update:lineItems')
emit('update:lineItems', newItems)
}, { deep: true })
@@ -144,6 +145,7 @@ const deleteItem = (lineItem: LineItem) => {
}
const recalculatePositions = () => {
console.log('recalculatePositions')
for (let i = 0; i < items.value.length; i++) {
items.value[i].position = getNextPosition(i, items.value[i].isSection)
}
@@ -189,8 +191,7 @@ const recalculatePositions = () => {
<TableHead class="h-0 w-8"></TableHead>
</TableRow>
<draggable v-model="items" tag="tbody" item-key="position" handle=".handle" ghostClass="ghost"
@end="recalculatePositions">
<draggable v-model="items" tag="tbody" item-key="position" handle=".handle" ghostClass="ghost">
<template #item="{ element }">
<TableRow v-if="element.isSection">
@@ -205,8 +206,7 @@ const recalculatePositions = () => {
<GrowingTextarea v-model="element.description" placeholder="Text"
class="font-light bg-transparent dark:bg-transparent hover:bg-background/66 dark:hover:bg-background/66 py-0 px-1 m-0 border-none shadow-none" />
</TableCell>
<!-- Buttons -->
<TableCell class="w-8 text-right px-1">
<Button variant="ghost" size="sm" @click="deleteItem(element)"