accept string and date in toLocalDate() util

This commit is contained in:
2025-11-10 16:09:53 +01:00
parent 2b974fafb5
commit 26cb144151
7 changed files with 220 additions and 15 deletions
+187 -2
View File
@@ -73,6 +73,31 @@ const cancelChanges = (event: Event | null) => {
}
}
const handleLogoUpload = (event: Event) => {
const target = event.target as HTMLInputElement;
if (target.files && target.files[0]) {
const file = target.files[0];
// Hier könntest du die Datei validieren (Größe, Typ, etc.)
if (file.size > 2 * 1024 * 1024) { // 2MB
alert('Die Datei ist zu groß. Maximal 2MB erlaubt.');
return;
}
// Hier könntest du die Datei hochladen und den Pfad speichern
// customer.value.logo = ... // Pfad zur hochgeladenen Datei
// Für die Vorschau:
const reader = new FileReader();
reader.onload = (e) => {
if (customer.value) {
customer.value.logo = e.target?.result as string;
}
};
reader.readAsDataURL(file);
}
};
</script>
<template>
@@ -111,8 +136,168 @@ const cancelChanges = (event: Event | null) => {
</div>
</div>
<div class="flex-none md:flex gap-12 mt-6 2 p-6 bg-slate-100 dark:bg-neutral-900 rounded-lg">
Customer Form hier
<div class="flex-none md:flex gap-12 mt-6 p-6 bg-slate-100 dark:bg-neutral-900 rounded-lg">
<div class="space-y-4 w-full">
<!-- Logo Upload -->
<div>
<div class="flex items-center gap-4">
<div v-if="customer.logo" class="w-24 h-24 border rounded-md overflow-hidden">
<img :src="'/storage/uploads/' + customer.logo" alt="Aktuelles Logo"
class="w-full h-full object-contain">
</div>
<!-- Logo hochladen -->
<div class="flex-1">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Neues
Logo hochladen</label>
<input type="file" @change="handleLogoUpload" accept="image/*"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Max. 2MB, JPG, PNG oder GIF
</p>
</div>
</div>
</div>
<!-- Firmenname -->
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Firmenname</label>
<input type="text" v-model="customer.companyName"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<!-- Kunden-Nummer -->
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Kunden-Nummer</label>
<input type="text" v-model="customer.customerNr"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<!-- USt-IdNr -->
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">USt-IdNr</label>
<input type="text" v-model="customer.vatId"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<!-- Website -->
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Website</label>
<input type="url" v-model="customer.url"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<!-- Telefon -->
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Telefon</label>
<input type="tel" v-model="customer.phone"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<!-- Rechnungsadresse -->
<div class="mt-6">
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-3">Rechnungsadresse</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Straße</label>
<input type="text" v-model="customer.billingAddress.lineOne"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Zusatzzeile</label>
<input type="text" v-model="customer.billingAddress.lineTwo"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">PLZ</label>
<input type="text" v-model="customer.billingAddress.postalCode"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Stadt</label>
<input type="text" v-model="customer.billingAddress.city"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Land</label>
<input type="text" v-model="customer.billingAddress.country"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
</div>
</div>
<!-- Zahlungsbedingungen -->
<div class="mt-6">
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-3">Zahlungsbedingungen
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Bezeichnung</label>
<input type="text" v-model="customer.paymentTerms.name"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Beschreibung</label>
<input type="text" v-model="customer.paymentTerms.description"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<div>
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Tage</label>
<input type="number" v-model="customer.paymentTerms.days"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
</div>
<div class="flex items-center mt-5">
<input type="checkbox" v-model="customer.paymentTerms.isFixed"
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded dark:bg-neutral-800 dark:border-neutral-700">
<label class="ml-2 block text-sm text-gray-700 dark:text-gray-300">Fix</label>
</div>
</div>
</div>
<!-- Status -->
<div class="mt-6">
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Status</label>
<select v-model="customer.status"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700">
<option value="active">Aktiv</option>
<option value="inactive">Inaktiv</option>
<option value="prospect">Interessent</option>
</select>
</div>
<!-- Notizen -->
<div class="mt-6">
<label
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Notizen</label>
<textarea v-model="customer.notes" rows="4"
class="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700"></textarea>
</div>
</div>
</div>
<div class="px-4 mt-6">
@@ -119,8 +119,9 @@ const calcTaxes = (amount: number) => {
<TableHead class="sticky top-0 w-1/20 text-right hidden lg:table-cell">Brutto</TableHead>
</TableRow>
</TableHeader>
<TableBody class="overflow-clip rounded-lg">
<TableRow v-for="invoice in invoices" :key="invoice.nr" @click="onItemClicked(invoice)"
<TableRow v-for="invoice in invoices" :key="invoice.nr" @dblclick="onItemClicked(invoice)"
class="select-none md:select-auto cursor-default bg-background"
:style="'color:' + statusBadgeTextColor(invoice.paymentStatus)">
<TableCell class="w-1/100 hidden md:table-cell lg:pr-5 tabular-nums">{{ invoice.nr }}
@@ -205,7 +205,7 @@ const cancelChanges = (event: Event | null) => {
isOpen.value = false
},
onCancel: () => {
if(!event) return
if (!event) return
event.preventDefault()
event.returnValue = true
}
@@ -293,7 +293,10 @@ const updateTotalAmount = () => {
@escapeKeyDown="cancelChanges" @interactOutside="cancelChanges">
<DialogHeader class="px-3 pt-3 flex flex-row justify-end">
<DialogTitle class="sr-only">Rechnung</DialogTitle>
<DialogTitle class="sr-only">Rechnung {{ invoice?.nr }}</DialogTitle>
<DialogDescription>
{{ invoice?.title }}
</DialogDescription>
<div v-if="invoice && invoice.id > 0" class="hidden md:flex mr-4">
<Button :size="'sm'" :variant="'ghost'" @click="preview">
+1 -1
View File
@@ -18,7 +18,7 @@ export const buttonVariants = cva(
secondary:
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost:
'border-none shadow-none hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
'border-none shadow-none hover:bg-slate-100 hover:text-accent-foreground dark:hover:bg-accent/50',
link: 'text-primary underline-offset-4 hover:underline',
pressed:
'bg-slate-100 dark:bg-neutral-700 shadow-none inset-shadow-2xs inset-shadow-black/15 border-none',