Move alertDialog to AppLayout fixes #33

This commit is contained in:
2025-10-29 18:04:09 +01:00
parent 69695e88aa
commit 9439d14b59
7 changed files with 200 additions and 41 deletions
+3
View File
@@ -4,6 +4,7 @@ import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import type { DefineComponent } from 'vue';
import { createApp, h } from 'vue';
import { createPinia } from 'pinia';
import { initializeTheme } from './composables/useAppearance';
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
@@ -12,8 +13,10 @@ createInertiaApp({
title: (title) => (title ? `${title} - ${appName}` : appName),
resolve: (name) => resolvePageComponent(`./pages/${name}.vue`, import.meta.glob<DefineComponent>('./pages/**/*.vue')),
setup({ el, App, props, plugin }) {
let pinia = createPinia()
createApp({ render: () => h(App, props) })
.use(plugin)
.use(pinia)
.mount(el);
},
progress: {
@@ -12,7 +12,7 @@
import { ref, computed, watch, onMounted, onUpdated, useTemplateRef } from "vue"
import { Customer, Invoice, Contact, PaymentTerms, Address } from "@/types"
import { newCustomer, newContact, newBillingData } from '@/types/index.d'
import { toCurrency, toLocalDate, toShortISOString, cn, calcDueDate, toFixedRounded } from '@/lib/utils';
import { toCurrency, toLocalDate, toShortISOString, cn, calcDueDate, toFixedRounded } from '@/lib/utils'
import axios from 'axios'
import { type DateValue, DateFormatter, getLocalTimeZone, parseDate, fromDate } from "@internationalized/date"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"
@@ -24,13 +24,13 @@ import { Input } from '@/components/ui/input';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'
import { StatusBadge, statusBadgeLabels, statusBadgeTextColor, StatusBadgeVariants } from '@/components/ui/status-badge'
import LineItemTable from '@/components/documents/LineItemTable.vue'
import { Eye, FileText, CircleEllipsis, Trash, BookUser, User, CodeXml, CalendarIcon, MessageCircleQuestion, X, CircleX, Logs, ListCheck, ClipboardCheck, ClipboardList } from "lucide-vue-next"
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog'
import { Eye, FileText, CircleEllipsis, Trash, Trash2, BookUser, User, CodeXml, CalendarIcon, MessageCircleQuestion, X, CircleX, Logs, ListCheck, ClipboardCheck, ClipboardList } 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 { exportPdf, exportXml } from "@/routes/invoice"
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, } from '@/components/ui/sheet'
import { GrowingTextarea } from '../ui/growing-textarea';
import { GrowingTextarea } from '../ui/growing-textarea'
const props = defineProps<{
invoiceData: Invoice | null,
@@ -46,8 +46,7 @@ const isDirty = ref(false);
const isLoading = ref(false);
const importContact = ref(newContact() as Contact)
const importCustomer = ref(newCustomer() as Customer)
const alert = ref({ open: false, title: "", message: "", cancelText: "", onCancel: () => { }, confirmText: "", onConfirm: () => { } })
const alert = alertStore()
onMounted(async () => {
const response = await axios.get('/api/paymentterms')
@@ -191,31 +190,30 @@ const saveChanges = () => {
const cancelChanges = (event: Event | null) => {
if (isDirty.value) {
alert.value.title = "Wirklich schließen?"
alert.value.message = "Es gibt ungespeicherte Änderungen, die dann verloren gehen."
alert.value.cancelText = "Abbrechen"
alert.value.onCancel = () => {
alert.title = "Wirklich schließen?"
alert.message = "Es gibt ungespeicherte Änderungen, die dann verloren gehen."
alert.cancelText = "Abbrechen"
alert.onCancel = () => {
console.log('cancel')
event?.preventDefault()
event.returnValue = true
alert.value.open = false
alert.open = false
}
alert.value.confirmText = "Schließen"
alert.value.onConfirm = () => {
alert.actionText = "Schließen"
// alert.actionVariant = "destructive"
alert.onAction = () => {
console.log('action')
emit('cancel')
isOpen.value = false
alert.value.open = false
alert.open = false
}
alert.value.open = true
alert.open = true
} else {
emit('cancel')
isOpen.value = false
}
}
const confirmCancel = () => {
return window.confirm('Es gibt ungespeicherte Änderungen. Möchtest Du die Seite wirklich verlassen?');
}
const preview = function () {
if (!invoice.value) return;
window?.open('/invoice/' + invoice.value.id, '_blank')?.focus();
@@ -383,7 +381,8 @@ const updateTotalAmount = () => {
<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>
<span class="text-2xl font-bold">{{ toCurrency(toFixedRounded(Number(invoice.totalAmount *
1.19), 2)) }}</span>
</div>
</div>
@@ -582,23 +581,6 @@ const updateTotalAmount = () => {
:disabled="!isDirty">Speichern</Button>
</DialogFooter>
<AlertDialog v-model:open="alert.open" :asChild="true">
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{{ alert.title }}</AlertDialogTitle>
<AlertDialogDescription>
{{ alert.message }}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<Button v-if="alert.onCancel" @click="alert.onCancel">{{ alert.cancelText }}</Button>
<Button variant="destructive" v-if="alert.onConfirm" @click="alert.onConfirm">{{
alert.confirmText
}}</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</DialogContent>
</Dialog>
@@ -28,7 +28,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
v-bind="forwarded"
:class="
cn(
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-bottom-[5%] data-[state=open]:slide-in-from-bottom-[5%] sm:rounded-lg',
props.class,
)
"
+22 -2
View File
@@ -2,14 +2,18 @@
import AppLayout from '@/layouts/app/AppSidebarLayout.vue';
// import AppLayout from '@/layouts/app/AppHeaderLayout.vue';
import type { BreadcrumbItemType } from '@/types';
import { computed, onMounted } from 'vue';
import { ref, onMounted } from 'vue';
import 'vue-sonner/style.css'
import { Toaster } from 'vue-sonner'
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog'
import { Info, CircleAlert, CircleCheck, LoaderCircle, Ban } from "lucide-vue-next"
import { Button } from '@/components/ui/button'
import { alertStore } from '@/stores/alertStore';
interface Props {
breadcrumbs?: BreadcrumbItemType[];
}
const alert = alertStore()
withDefaults(defineProps<Props>(), {
breadcrumbs: () => [],
@@ -24,7 +28,6 @@ onMounted(() => {
</script>
<template>
<!-- :duration="120000" -->
<Toaster position="top-right" :expand="true" closeButton :visible-toasts="6" :offset="'1rem'" :toastOptions="{
unstyled: true,
classes: {
@@ -63,4 +66,21 @@ onMounted(() => {
<slot />
</AppLayout>
<AlertDialog v-model:open="alert.open">
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{{ alert.title }}</AlertDialogTitle>
<AlertDialogDescription>{{ alert.message }}</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<Button v-if="alert.onCancel" @click="alert.onCancel">{{ alert.cancelText }}</Button>
<Button :variant="alert.actionVariant" v-if="alert.onAction" @click="alert.onAction">{{
alert.actionText
}}</Button>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</template>
+17
View File
@@ -0,0 +1,17 @@
import { defineStore } from 'pinia'
export const alertStore = defineStore('alert', {
state: () => {
return {
open: false,
title: "",
message: "",
cancelText: "Abbrechen",
onCancel: () => { },
actionText: "Ok",
actionVariant: "action" as "action" | "destructive",
onAction: () => { }
}
},
actions: {}
})