Show invoice buttons depending of payment status. Fixes #54
This commit is contained in:
@@ -24,15 +24,14 @@ import { Input } from '@/components/ui/input';
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'
|
||||
import { StatusBadge, statusBadgeLabels, statusTextStyle, StatusBadgeVariants } from '@/components/ui/status-badge'
|
||||
import LineItemTable from '@/components/documents/LineItemTable.vue'
|
||||
import { Eye, FileText, CircleEllipsis, Trash, Trash2, BookUser, User, CodeXml, CalendarIcon, MessageCircleQuestion, X, CircleX, Logs, ListCheck, ClipboardCheck, ClipboardList, Loader, Loader2 } from "lucide-vue-next"
|
||||
import { Eye, FileText, Trash2, BookUser, User, CodeXml, CalendarIcon, MessageCircleQuestion, Loader2, Ellipsis, Check, FileCheck, FileX, Ban } from "lucide-vue-next"
|
||||
import { alertStore } from "@/stores/alertStore"
|
||||
import { Calendar } from "@/components/ui/calendar"
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
||||
import { exportPdf, exportXml } from "@/routes/invoice"
|
||||
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, } from '@/components/ui/sheet'
|
||||
import { GrowingTextarea } from '../ui/growing-textarea'
|
||||
import { toast } from "vue-sonner"
|
||||
import { SendMailDialog } from "../ui/send-mail-dialog"
|
||||
import { Kbd, KbdGroup } from "../ui/kbd"
|
||||
import DialogClose from "../ui/dialog/DialogClose.vue"
|
||||
import DialogCloseButton from "../DialogCloseButton/DialogCloseButton.vue"
|
||||
|
||||
const props = defineProps<{
|
||||
invoiceData: Invoice | null,
|
||||
@@ -182,6 +181,14 @@ watch(importContact,
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
const billingContactEmail = computed<string | undefined>(() => {
|
||||
// TODO: use e-mail from billing data if set
|
||||
// and fallback to primary contact email
|
||||
if (invoice.value?.customer && invoice.value?.customer.contacts[0])
|
||||
return invoice.value?.customer?.contacts[0].email
|
||||
else return ""
|
||||
})
|
||||
|
||||
onUpdated(() => {
|
||||
isLoading.value = false;
|
||||
// console.log("onUpdated", "Dirty: " + isDirty.value, "loading: " + isLoading.value)
|
||||
@@ -190,7 +197,7 @@ onUpdated(() => {
|
||||
const saveChanges = () => {
|
||||
if (invoice.value) {
|
||||
emit('save', invoice.value)
|
||||
isOpen.value = false
|
||||
// isOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +208,6 @@ const cancelChanges = (event: Event | null) => {
|
||||
"Es gibt ungespeicherte Änderungen, die dann verloren gehen.",
|
||||
{
|
||||
actionText: "Änderungen verwerfen",
|
||||
actionVariant: "destructive",
|
||||
onAction: () => {
|
||||
emit('cancel')
|
||||
isOpen.value = false
|
||||
@@ -234,6 +240,11 @@ const downloadXml = function () {
|
||||
window?.open('/invoice/' + invoice.value.id + '/xml');
|
||||
}
|
||||
|
||||
const issueInvoice = function () {
|
||||
if (!invoice.value) return;
|
||||
invoice.value.paymentStatus = 'issued'
|
||||
}
|
||||
|
||||
const deleteInvoice = function () {
|
||||
alert.show(
|
||||
"Möchtest Du diese Rechnung wirklich löschen?",
|
||||
@@ -249,34 +260,14 @@ const deleteInvoice = function () {
|
||||
)
|
||||
}
|
||||
|
||||
const cancelInvoice = function () {
|
||||
if (!invoice.value) return;
|
||||
invoice.value.paymentStatus = 'cancelled'
|
||||
}
|
||||
|
||||
const openReminderDialog = function () {
|
||||
if (!invoice.value) return
|
||||
|
||||
reminderDialogOpen.value = true
|
||||
|
||||
// alert.show(
|
||||
// "Zahlungserinnerung senden?",
|
||||
// "E-mail an " + invoice.value.customer?.contacts[0].email,
|
||||
// {
|
||||
// actionText: "Senden",
|
||||
// onAction: async () => {
|
||||
// // make button spin and disable button
|
||||
// reminderLoading.value = true
|
||||
|
||||
// // await axios call
|
||||
// await axios.get('/api/invoices/' + invoice.value.id + '/remind')
|
||||
// .then(function (response) {
|
||||
// toast.success("Zahlungserinnerung gesendet", { description: "daniel@vollstock.de" })
|
||||
// })
|
||||
// .catch(function (error) {
|
||||
// toast.error(error.title, { description: error.message })
|
||||
// })
|
||||
// .finally(() => {
|
||||
// reminderLoading.value = false
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
}
|
||||
|
||||
const sendReminder = async function (recipient: string | undefined) {
|
||||
@@ -314,141 +305,210 @@ const updateTotalAmount = () => {
|
||||
<template>
|
||||
<Dialog id="invoice-dialog" v-model:open="isOpen">
|
||||
<DialogContent
|
||||
class="sm:max-w-[min((100%-2rem),1152px)] grid-rows-[auto_minmax(0,1fr)_auto] p-0 h-[calc(100dvh-2rem)]"
|
||||
class="sm:max-w-[min((100%-2rem),1152px)] grid-rows-[auto_minmax(0,1fr)_auto] h-[calc(100dvh-2rem)] gap-0 p-0 outline-none"
|
||||
@escapeKeyDown="cancelChanges" @interactOutside="cancelChanges">
|
||||
|
||||
<DialogHeader class="px-3 pt-3 flex flex-row justify-end">
|
||||
<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">
|
||||
<Eye :strokeWidth="1.5" class="text-current" />
|
||||
<span>Vorschau</span>
|
||||
</Button>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Button :size="'sm'" :variant="'ghost'" @click="downloadPdf">
|
||||
<FileText :strokeWidth="1.5" class="text-current" />
|
||||
<span>PDF</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
ZUGFeRD
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Button :size="'sm'" :variant="'ghost'" @click="downloadXml">
|
||||
<CodeXml :strokeWidth="1.5" class="text-current" />
|
||||
<span>XML</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
XRechnung
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
|
||||
<Sheet as-child class="relativ">
|
||||
<SheetTrigger>
|
||||
<Button :size="'sm'" :variant="'ghost'">
|
||||
<ClipboardList :strokeWidth="1.5" class="text-current" />
|
||||
<span>Audit</span>
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Are you absolutely sure?</SheetTitle>
|
||||
<SheetDescription>
|
||||
This action cannot be undone. This will permanently delete your account
|
||||
and remove your data from our servers.
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
|
||||
<Button :size="'sm'" :variant="'ghost'" @click="deleteInvoice"
|
||||
class="text-destructive hover:bg-destructive/5 hover:text-destructive">
|
||||
<Trash2 :strokeWidth="1.5" class="text-current" />
|
||||
<span>Löschen</span>
|
||||
</Button>
|
||||
<DialogHeader class="p-4 md:p-6 lg:p-12 pb-0 md:pb-2 lg:pb-8 flex flex-row items-start gap-6">
|
||||
|
||||
<div class="flex flex-col grow">
|
||||
<DialogTitle class="text-primary-foreground font-bold text-left z-1">
|
||||
<h1 v-if="invoice.id > 0">Rechnung {{ invoice.nr }}</h1>
|
||||
<h1 v-else>Neue Rechnung</h1>
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Input
|
||||
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" v-model="invoice.title" placeholder="Titel" />
|
||||
</DialogDescription>
|
||||
</div>
|
||||
<div class="md:hidden">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button :variant="'ghost'" :size="'lg'">
|
||||
<CircleEllipsis class="size-6" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="mr-8">
|
||||
<DropdownMenuItem class="flex justify-between" @click="preview">
|
||||
<span class="mr-2">Vorschau</span>
|
||||
<Eye :strokeWidth="1.5" class="text-current" />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem class="flex justify-between" @click="downloadPdf">
|
||||
<div class="mr-2 flex flex-col">
|
||||
<span>PDF speichern</span>
|
||||
<span class="text-xs text-muted-foreground">(ZUGFeRD)</span>
|
||||
</div>
|
||||
<FileText :strokeWidth="1.5" class="text-current" />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem class="flex justify-between" @click="downloadXml">
|
||||
<div class="mr-2 flex flex-col">
|
||||
<span>XML speichern</span>
|
||||
<span class="text-xs text-muted-foreground">(XRechnung)</span>
|
||||
</div>
|
||||
<CodeXml :strokeWidth="1.5" class="text-current" />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem class="flex justify-between text-destructive">
|
||||
<span class="mr-2">Löschen</span>
|
||||
<Trash :strokeWidth="1.5" class="text-current" />
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<div class="flex gap-2 items-center">
|
||||
<TooltipProvider>
|
||||
<!-- Save -->
|
||||
<Button v-if="invoice && invoice.id > 0 && isDirty" class="grow md:grow-0" size="sm"
|
||||
@click="saveChanges">
|
||||
<Check stroke-width="1.5" />
|
||||
Speichern
|
||||
</Button>
|
||||
|
||||
<!-- Issue -->
|
||||
<Tooltip v-if="invoice && invoice.paymentStatus == 'draft'">
|
||||
<TooltipTrigger>
|
||||
<Button size="sm" variant="action" @click="issueInvoice">
|
||||
Rechnung stellen
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
Bearbeitung sperren und Rechnung erstellen
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
|
||||
<!-- Paid -->
|
||||
<Tooltip v-if="invoice && ['issued', 'due', 'reminded'].includes(invoice.paymentStatus)">
|
||||
<TooltipTrigger>
|
||||
<Button size="sm" variant="success" @click="invoice.paymentStatus = 'paid'">
|
||||
<FileCheck stroke-width="1.5" /> Bezahlt
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
Als bezahlt markieren
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<!-- Remind -->
|
||||
<Tooltip v-if="invoice && ['due', 'reminded'].includes(invoice.paymentStatus)">
|
||||
<TooltipTrigger>
|
||||
<Button size="sm" variant="destructive" @click="openReminderDialog"
|
||||
:disabled="reminderLoading" class="gap-0">
|
||||
<Loader2 class="h-4 w-4 transition-[width] ease-in-out animate-spin"
|
||||
stroke-width="1.5"
|
||||
:class="{ 'w-0!': !reminderLoading, 'mr-2': reminderLoading }" />
|
||||
Erinnern
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
Zahlungserinnerung per E-Mail senden
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
|
||||
<!-- Ellipsis menu -->
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="ghost" size="sm" class="px-0! w-7 ml-2">
|
||||
<Ellipsis class="size-4" stroke-width="1.5" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent align="end">
|
||||
<!-- Preview -->
|
||||
<DropdownMenuItem v-if="invoice?.paymentStatus == 'draft'"
|
||||
class="flex items-center justify-between" @click="preview">
|
||||
<div class="flex items-center gap-4">
|
||||
<Eye :strokeWidth="1.5" class="text-current" />
|
||||
<span class="mr-4">Vorschau</span>
|
||||
</div>
|
||||
<KbdGroup>
|
||||
<Kbd class="visible-mac">⌘</Kbd>
|
||||
<Kbd class="visible-pc">Ctrl</Kbd>
|
||||
<Kbd>P</Kbd>
|
||||
</KbdGroup>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<!-- PDF -->
|
||||
<DropdownMenuItem v-if="invoice && invoice.paymentStatus != 'draft'" class="flex justify-between"
|
||||
@click="downloadPdf">
|
||||
<div class="flex items-center gap-4">
|
||||
<FileText stroke-width="1.5" class="text-muted-foreground" />
|
||||
<div class="mr-4 flex flex-col">
|
||||
<span>PDF exportieren</span>
|
||||
<span class="text-xs text-muted-foreground">(ZUGFeRD)</span>
|
||||
</div>
|
||||
</div>
|
||||
<KbdGroup>
|
||||
<Kbd class="visible-mac">⌘</Kbd>
|
||||
<Kbd class="visible-pc">Ctrl</Kbd>
|
||||
<Kbd>E</Kbd>
|
||||
</KbdGroup>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<!-- XML -->
|
||||
<DropdownMenuItem v-if="invoice && invoice.paymentStatus != 'draft'" class="flex justify-between"
|
||||
@click="downloadXml">
|
||||
<div class="flex items-center gap-4">
|
||||
<CodeXml stroke-width="1.5" class="text-muted-foreground" />
|
||||
<div class="mr-4 flex flex-col">
|
||||
<span>XML exportieren</span>
|
||||
<span class="text-xs text-muted-foreground">(XRechnung)</span>
|
||||
</div>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<!-- Cancel -->
|
||||
<DropdownMenuItem
|
||||
v-if="invoice && ['issued', 'due', 'reminded'].includes(invoice.paymentStatus)"
|
||||
class="flex justify-between" @click="deleteInvoice">
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- <FileX stroke-width="1.5" class="text-muted-foreground"/> -->
|
||||
<Ban :strokeWidth="1.5" class="text-current" />
|
||||
<span class="mr-2">Stornieren</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<!-- Delete -->
|
||||
<DropdownMenuItem
|
||||
class="flex justify-between text-destructive! hover:bg-red-100! dark:hover:bg-red-950!"
|
||||
@click="deleteInvoice">
|
||||
<div class="flex items-center gap-2">
|
||||
<Trash2 :strokeWidth="1.5" class="text-current" />
|
||||
<span class="mr-2">Löschen</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TooltipProvider>
|
||||
|
||||
<DialogClose as-child>
|
||||
<DialogCloseButton />
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogHeader>
|
||||
|
||||
<div class="overflow-y-auto px-6" v-if="invoice">
|
||||
<div class="overflow-y-auto p-4 md:p-6 lg:p-12 pt-0!" v-if="invoice">
|
||||
|
||||
<div id="document">
|
||||
<div id="document-header"
|
||||
class="sticky top-0 py-4 bg-white dark:bg-neutral-800 z-1 flex items-end gap-12">
|
||||
<div class="grow">
|
||||
class="h-7 mb-12 sticky top-0 bg-background z-1 flex flex-col md:flex-row justify-between items-center">
|
||||
|
||||
<h1 class="text-xl text-primary-foreground font-bold" v-if="invoice.id > 0">
|
||||
Rechnung {{ invoice.nr
|
||||
}}</h1>
|
||||
<h1 class="text-xl text-primary-foreground font-bold" v-else>Neue
|
||||
Rechnung
|
||||
</h1>
|
||||
|
||||
<Input
|
||||
class="md:text-xl px-0 bg-transparent dark:bg-transparent hover:bg-accent dark:hover:bg-accent/30 border-none shadow-none"
|
||||
type="text" v-model="invoice.title" placeholder="Titel" />
|
||||
<!-- Status -->
|
||||
<div>
|
||||
<StatusBadge size="lg" :variant="invoice.paymentStatus">{{
|
||||
statusBadgeLabels[invoice.paymentStatus] }}
|
||||
</StatusBadge>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col m-0 items-end gap-0">
|
||||
<span class="text-md text-muted-foreground">{{ toCurrency(invoice.totalAmount) }}</span>
|
||||
<span class="text-2xl font-bold">{{ toCurrency(toFixedRounded(Number(invoice.totalAmount *
|
||||
1.19), 2)) }}</span>
|
||||
|
||||
<!-- <div class="flex gap-4 mr-6 w-33" v-if="invoice && invoice.paymentStatus == 'draft'">
|
||||
</div>
|
||||
|
||||
<Select v-model="invoice.paymentStatus" v-else>
|
||||
<SelectTrigger class="bg-transparent! shadow-none! outline-0 border-0 pr-8 w-41 pl-0">
|
||||
<StatusBadge size="lg" :variant="invoice.paymentStatus">{{
|
||||
statusBadgeLabels[invoice.paymentStatus] }}
|
||||
</StatusBadge>
|
||||
<!-- <SelectValue placeholder="Status" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem v-for="(label, value) in statusBadgeLabels" :value="value">
|
||||
<SelectLabel>{{ label }}</SelectLabel>
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select> -->
|
||||
|
||||
|
||||
<!-- Betrag -->
|
||||
<div class="grid grid-cols-[auto_auto_auto_auto] items-end gap-x-6 gap-y-0">
|
||||
<label class="text-muted-foreground text-xs pb-[0.4rem]">Netto</label>
|
||||
<span class="text-lg text-muted-foreground place-self-end">{{
|
||||
toCurrency(invoice.totalAmount) }}</span>
|
||||
<label class="text-muted-foreground text-xs pb-[0.4rem]">Brutto</label>
|
||||
<span class="text-xl font-bold place-self-end">{{
|
||||
toCurrency(toFixedRounded(Number(invoice.totalAmount *
|
||||
1.19), 2)) }}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="document-meta"
|
||||
class="flex-none md:flex gap-12 mt-6 2 p-6 bg-slate-100 dark:bg-neutral-900 rounded-lg">
|
||||
class="flex-none md:flex gap-12 2 p-6 bg-slate-100 dark:bg-neutral-900 rounded-lg">
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="flex">
|
||||
<Input type="text" v-model="invoice.billingData.companyName" placeholder="Firma"
|
||||
class="bg-transparent dark:bg-transparent hover:bg-background dark:hover:bg-background/40 p-1 shadow-none border-0 border-b-1 border-slate-300 dark:border-neutral-800 placeholder:text-muted-foreground/50 rounded-none hover:rounded-md" />
|
||||
|
||||
@@ -518,38 +578,6 @@ const updateTotalAmount = () => {
|
||||
<Table>
|
||||
<TableBody>
|
||||
|
||||
<!-- Status -->
|
||||
<TableRow>
|
||||
<TableHead class="w-1">Status</TableHead>
|
||||
<TableCell class="flex items-center gap-4">
|
||||
<StatusBadge size="sm" :variant="invoice.paymentStatus">{{
|
||||
statusBadgeLabels[invoice.paymentStatus] }}
|
||||
</StatusBadge>
|
||||
<Select v-model="invoice.paymentStatus">
|
||||
<SelectTrigger
|
||||
class="w-full bg-transparent dark:bg-transparent hover:bg-background dark:hover:bg-background/40 shadow-none border-0 h-8!">
|
||||
<SelectValue placeholder="Status" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem v-for="(label, value) in statusBadgeLabels"
|
||||
:value="value">
|
||||
<SelectLabel>{{ label }}</SelectLabel>
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<Button v-if="['due', 'reminded'].includes(invoice.paymentStatus)"
|
||||
:size="'sm'" :variant="'destructive'" @click="openReminderDialog"
|
||||
:disabled="reminderLoading">
|
||||
<Loader2 class="h-4 w-4 transition-[width] ease-in-out animate-spin"
|
||||
:class="{ 'w-0!': !reminderLoading }" />
|
||||
Mahnen
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<!-- Rechnungsdatum -->
|
||||
<TableRow>
|
||||
<TableHead>Datum</TableHead>
|
||||
@@ -624,48 +652,24 @@ const updateTotalAmount = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="document-text" class="px-4 mt-6">
|
||||
<div id="document-text" class="mt-6 md:mt-8 lg:mt-12">
|
||||
<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" />
|
||||
</div>
|
||||
|
||||
<LineItemTable :lineItems="invoice.items" @update:lineItems="updateTotalAmount" />
|
||||
<LineItemTable :lineItems="invoice.items" @update:lineItems="updateTotalAmount" sticky-top="7"
|
||||
class="mt-4" />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<DialogFooter class="p-6 pt-0 flex-row">
|
||||
<div :size="'sm'" class="hidden md:block flex-grow-4"></div>
|
||||
<Button class="grow md:grow-0" @click="cancelChanges">
|
||||
Abbrechen
|
||||
</Button>
|
||||
<Button class="grow md:grow-0" :variant="'action'" @click="saveChanges"
|
||||
:disabled="!isDirty">Speichern</Button>
|
||||
</DialogFooter>
|
||||
|
||||
</DialogContent>
|
||||
|
||||
</Dialog>
|
||||
<SendMailDialog v-model:open="reminderDialogOpen" title="Zahlungserinnerung senden?" description=""
|
||||
:recipient="invoice?.customer?.contacts[0].email" @send="(recipient) => sendReminder(recipient)" />
|
||||
:recipient="billingContactEmail" @send="(recipient) => sendReminder(recipient)" />
|
||||
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/* Remove close X */
|
||||
[data-slot=dialog-content] button.ring-offset-background {
|
||||
/* display: none; */
|
||||
border-radius: 100%;
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
color: var(--color-destructive);
|
||||
}
|
||||
|
||||
/* Backdrop */
|
||||
[data-slot=dialog-overlay] {
|
||||
backdrop-filter: blur(var(--blur-sm));
|
||||
}
|
||||
</style>
|
||||
<style></style>
|
||||
Reference in New Issue
Block a user