Move alertDialog to AppLayout fixes #33

This commit is contained in:
2025-10-29 18:04:09 +01:00
parent 9cf5db37bc
commit 4701efddd8
7 changed files with 200 additions and 41 deletions
+136
View File
@@ -16,6 +16,7 @@
"fuse.js": "^7.1.0", "fuse.js": "^7.1.0",
"laravel-vite-plugin": "^2.0.0", "laravel-vite-plugin": "^2.0.0",
"lucide-vue-next": "^0.468.0", "lucide-vue-next": "^0.468.0",
"pinia": "^3.0.3",
"reka-ui": "^2.6.0", "reka-ui": "^2.6.0",
"tailwind-merge": "^3.2.0", "tailwind-merge": "^3.2.0",
"tailwindcss": "^4.1.1", "tailwindcss": "^4.1.1",
@@ -1978,6 +1979,39 @@
"he": "^1.2.0" "he": "^1.2.0"
} }
}, },
"node_modules/@vue/devtools-api": {
"version": "7.7.7",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.7.tgz",
"integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==",
"license": "MIT",
"dependencies": {
"@vue/devtools-kit": "^7.7.7"
}
},
"node_modules/@vue/devtools-kit": {
"version": "7.7.7",
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz",
"integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==",
"license": "MIT",
"dependencies": {
"@vue/devtools-shared": "^7.7.7",
"birpc": "^2.3.0",
"hookable": "^5.5.3",
"mitt": "^3.0.1",
"perfect-debounce": "^1.0.0",
"speakingurl": "^14.0.1",
"superjson": "^2.2.2"
}
},
"node_modules/@vue/devtools-shared": {
"version": "7.7.7",
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz",
"integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==",
"license": "MIT",
"dependencies": {
"rfdc": "^1.4.1"
}
},
"node_modules/@vue/eslint-config-typescript": { "node_modules/@vue/eslint-config-typescript": {
"version": "14.6.0", "version": "14.6.0",
"resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.6.0.tgz", "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-14.6.0.tgz",
@@ -2231,6 +2265,15 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/birpc": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.6.1.tgz",
"integrity": "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/boolbase": { "node_modules/boolbase": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -2482,6 +2525,21 @@
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1" "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
} }
}, },
"node_modules/copy-anything": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz",
"integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==",
"license": "MIT",
"dependencies": {
"is-what": "^5.2.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -3406,6 +3464,12 @@
"he": "bin/he" "he": "bin/he"
} }
}, },
"node_modules/hookable": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
"license": "MIT"
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -3486,6 +3550,18 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/is-what": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz",
"integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/isexe": { "node_modules/isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -3968,6 +4044,12 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
"license": "MIT"
},
"node_modules/mkdirp": { "node_modules/mkdirp": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
@@ -4144,6 +4226,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/perfect-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
"license": "MIT"
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -4162,6 +4250,27 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pinia": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.3.tgz",
"integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^7.7.2"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"typescript": ">=4.4.4",
"vue": "^2.7.0 || ^3.5.11"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.6", "version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
@@ -4450,6 +4559,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"license": "MIT"
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.50.2", "version": "4.50.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz",
@@ -4673,6 +4788,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/speakingurl": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
"integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/string-width": { "node_modules/string-width": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -4714,6 +4838,18 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/superjson": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.5.tgz",
"integrity": "sha512-zWPTX96LVsA/eVYnqOM2+ofcdPqdS1dAF1LN4TS2/MWuUpfitd9ctTa87wt4xrYnZnkLtS69xpBdSxVBP5Rm6w==",
"license": "MIT",
"dependencies": {
"copy-anything": "^4"
},
"engines": {
"node": ">=16"
}
},
"node_modules/supports-color": { "node_modules/supports-color": {
"version": "8.1.1", "version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+1
View File
@@ -40,6 +40,7 @@
"fuse.js": "^7.1.0", "fuse.js": "^7.1.0",
"laravel-vite-plugin": "^2.0.0", "laravel-vite-plugin": "^2.0.0",
"lucide-vue-next": "^0.468.0", "lucide-vue-next": "^0.468.0",
"pinia": "^3.0.3",
"reka-ui": "^2.6.0", "reka-ui": "^2.6.0",
"tailwind-merge": "^3.2.0", "tailwind-merge": "^3.2.0",
"tailwindcss": "^4.1.1", "tailwindcss": "^4.1.1",
+3
View File
@@ -4,6 +4,7 @@ import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import type { DefineComponent } from 'vue'; import type { DefineComponent } from 'vue';
import { createApp, h } from 'vue'; import { createApp, h } from 'vue';
import { createPinia } from 'pinia';
import { initializeTheme } from './composables/useAppearance'; import { initializeTheme } from './composables/useAppearance';
const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
@@ -12,8 +13,10 @@ createInertiaApp({
title: (title) => (title ? `${title} - ${appName}` : appName), title: (title) => (title ? `${title} - ${appName}` : appName),
resolve: (name) => resolvePageComponent(`./pages/${name}.vue`, import.meta.glob<DefineComponent>('./pages/**/*.vue')), resolve: (name) => resolvePageComponent(`./pages/${name}.vue`, import.meta.glob<DefineComponent>('./pages/**/*.vue')),
setup({ el, App, props, plugin }) { setup({ el, App, props, plugin }) {
let pinia = createPinia()
createApp({ render: () => h(App, props) }) createApp({ render: () => h(App, props) })
.use(plugin) .use(plugin)
.use(pinia)
.mount(el); .mount(el);
}, },
progress: { progress: {
@@ -12,7 +12,7 @@
import { ref, computed, watch, onMounted, onUpdated, useTemplateRef } from "vue" import { ref, computed, watch, onMounted, onUpdated, useTemplateRef } from "vue"
import { Customer, Invoice, Contact, PaymentTerms, Address } from "@/types" import { Customer, Invoice, Contact, PaymentTerms, Address } from "@/types"
import { newCustomer, newContact, newBillingData } from '@/types/index.d' 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 axios from 'axios'
import { type DateValue, DateFormatter, getLocalTimeZone, parseDate, fromDate } from "@internationalized/date" import { type DateValue, DateFormatter, getLocalTimeZone, parseDate, fromDate } from "@internationalized/date"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" 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 { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'
import { StatusBadge, statusBadgeLabels, statusBadgeTextColor, StatusBadgeVariants } from '@/components/ui/status-badge' import { StatusBadge, statusBadgeLabels, statusBadgeTextColor, StatusBadgeVariants } from '@/components/ui/status-badge'
import LineItemTable from '@/components/documents/LineItemTable.vue' 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 { Eye, FileText, CircleEllipsis, Trash, Trash2, 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 { alertStore } from "@/stores/alertStore"
import { Calendar } from "@/components/ui/calendar" import { Calendar } from "@/components/ui/calendar"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" 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 { 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<{ const props = defineProps<{
invoiceData: Invoice | null, invoiceData: Invoice | null,
@@ -46,8 +46,7 @@ const isDirty = ref(false);
const isLoading = ref(false); const isLoading = ref(false);
const importContact = ref(newContact() as Contact) const importContact = ref(newContact() as Contact)
const importCustomer = ref(newCustomer() as Customer) const importCustomer = ref(newCustomer() as Customer)
const alert = ref({ open: false, title: "", message: "", cancelText: "", onCancel: () => { }, confirmText: "", onConfirm: () => { } }) const alert = alertStore()
onMounted(async () => { onMounted(async () => {
const response = await axios.get('/api/paymentterms') const response = await axios.get('/api/paymentterms')
@@ -191,31 +190,30 @@ const saveChanges = () => {
const cancelChanges = (event: Event | null) => { const cancelChanges = (event: Event | null) => {
if (isDirty.value) { if (isDirty.value) {
alert.value.title = "Wirklich schließen?" alert.title = "Wirklich schließen?"
alert.value.message = "Es gibt ungespeicherte Änderungen, die dann verloren gehen." alert.message = "Es gibt ungespeicherte Änderungen, die dann verloren gehen."
alert.value.cancelText = "Abbrechen" alert.cancelText = "Abbrechen"
alert.value.onCancel = () => { alert.onCancel = () => {
console.log('cancel')
event?.preventDefault() event?.preventDefault()
event.returnValue = true event.returnValue = true
alert.value.open = false alert.open = false
} }
alert.value.confirmText = "Schließen" alert.actionText = "Schließen"
alert.value.onConfirm = () => { // alert.actionVariant = "destructive"
alert.onAction = () => {
console.log('action')
emit('cancel') emit('cancel')
isOpen.value = false isOpen.value = false
alert.value.open = false alert.open = false
} }
alert.value.open = true alert.open = true
} else { } else {
emit('cancel') emit('cancel')
isOpen.value = false isOpen.value = false
} }
} }
const confirmCancel = () => {
return window.confirm('Es gibt ungespeicherte Änderungen. Möchtest Du die Seite wirklich verlassen?');
}
const preview = function () { const preview = function () {
if (!invoice.value) return; if (!invoice.value) return;
window?.open('/invoice/' + invoice.value.id, '_blank')?.focus(); 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"> <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-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>
</div> </div>
@@ -582,23 +581,6 @@ const updateTotalAmount = () => {
:disabled="!isDirty">Speichern</Button> :disabled="!isDirty">Speichern</Button>
</DialogFooter> </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> </DialogContent>
</Dialog> </Dialog>
@@ -28,7 +28,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
v-bind="forwarded" v-bind="forwarded"
:class=" :class="
cn( 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, props.class,
) )
" "
+22 -2
View File
@@ -2,14 +2,18 @@
import AppLayout from '@/layouts/app/AppSidebarLayout.vue'; import AppLayout from '@/layouts/app/AppSidebarLayout.vue';
// import AppLayout from '@/layouts/app/AppHeaderLayout.vue'; // import AppLayout from '@/layouts/app/AppHeaderLayout.vue';
import type { BreadcrumbItemType } from '@/types'; import type { BreadcrumbItemType } from '@/types';
import { computed, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import 'vue-sonner/style.css' import 'vue-sonner/style.css'
import { Toaster } from 'vue-sonner' 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 { Info, CircleAlert, CircleCheck, LoaderCircle, Ban } from "lucide-vue-next"
import { Button } from '@/components/ui/button'
import { alertStore } from '@/stores/alertStore';
interface Props { interface Props {
breadcrumbs?: BreadcrumbItemType[]; breadcrumbs?: BreadcrumbItemType[];
} }
const alert = alertStore()
withDefaults(defineProps<Props>(), { withDefaults(defineProps<Props>(), {
breadcrumbs: () => [], breadcrumbs: () => [],
@@ -24,7 +28,6 @@ onMounted(() => {
</script> </script>
<template> <template>
<!-- :duration="120000" -->
<Toaster position="top-right" :expand="true" closeButton :visible-toasts="6" :offset="'1rem'" :toastOptions="{ <Toaster position="top-right" :expand="true" closeButton :visible-toasts="6" :offset="'1rem'" :toastOptions="{
unstyled: true, unstyled: true,
classes: { classes: {
@@ -63,4 +66,21 @@ onMounted(() => {
<slot /> <slot />
</AppLayout> </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> </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: {}
})