diff --git a/app/Invoice/Actions/InvoiceStoreAction.php b/app/Invoice/Actions/InvoiceStoreAction.php index 3869cb90..03977ab4 100644 --- a/app/Invoice/Actions/InvoiceStoreAction.php +++ b/app/Invoice/Actions/InvoiceStoreAction.php @@ -7,6 +7,7 @@ use App\Invoice\Enums\InvoiceStatus; use Lorisleiva\Actions\ActionRequest; use Lorisleiva\Actions\Concerns\AsAction; use App\Invoice\Models\Invoice; +use App\Lib\Events\Succeeded; use Illuminate\Validation\Rule; class InvoiceStoreAction @@ -56,5 +57,7 @@ class InvoiceStoreAction foreach ($request->validated('positions') as $position) { $invoice->positions()->create($position); } + + Succeeded::message('Rechnung erstellt.')->dispatch(); } } diff --git a/app/Lib/Events/Succeeded.php b/app/Lib/Events/Succeeded.php new file mode 100644 index 00000000..93acd277 --- /dev/null +++ b/app/Lib/Events/Succeeded.php @@ -0,0 +1,40 @@ + + */ + public function broadcastOn() + { + return [ + new Channel('jobs'), + ]; + } +} diff --git a/resources/js/composables/useInertiaApiIndex.js b/resources/js/composables/useInertiaApiIndex.js new file mode 100644 index 00000000..d8edbd4e --- /dev/null +++ b/resources/js/composables/useInertiaApiIndex.js @@ -0,0 +1,108 @@ +import {computed, ref, inject, onBeforeUnmount} from 'vue'; +import {router} from '@inertiajs/vue3'; +import useQueueEvents from './useQueueEvents.js'; + +export function useIndex(props, siteName) { + const axios = inject('axios'); + const {startListener, stopListener} = useQueueEvents(siteName, () => reload(false)); + const single = ref(null); + const rawProps = JSON.parse(JSON.stringify(props)); + const inner = { + data: ref(rawProps.data), + meta: ref(rawProps.meta), + }; + + function toFilterString(data) { + return btoa(encodeURIComponent(JSON.stringify(data))); + } + + const filterString = computed(() => toFilterString(inner.meta.value.filter)); + + function reload(resetPage = true, withMeta = true, data) { + data = { + filter: filterString.value, + page: resetPage ? 1 : inner.meta.value.current_page, + ...data, + }; + + router.visit(window.location.pathname, { + data, + preserveState: true, + only: ['data'], + onSuccess: (page) => { + inner.data.value = page.props.data.data; + if (withMeta) { + inner.meta.value = { + ...inner.meta.value, + ...page.props.data.meta, + }; + } + }, + }); + } + + function reloadPage(page) { + reload(false, true, {page: page}); + } + + function can(permission) { + return inner.meta.value.can[permission]; + } + + function create() { + single.value = JSON.parse(JSON.stringify(inner.meta.value.default)); + } + + function edit(model) { + single.value = JSON.parse(JSON.stringify(model)); + } + + async function submit() { + single.value.id ? await axios.patch(single.value.links.update, single.value) : await axios.post(inner.meta.value.links.store, single.value); + reload(); + single.value = null; + } + + async function remove(model) { + await axios.delete(model.links.destroy); + reload(); + } + + function can(permission) { + return inner.meta.value.can[permission]; + } + + function cancel() { + single.value = null; + } + + startListener(); + onBeforeUnmount(() => stopListener()); + + return { + data: inner.data, + meta: inner.meta, + single, + create, + edit, + reload, + reloadPage, + can, + router, + submit, + remove, + cancel, + axios, + }; +} + +const indexProps = { + data: { + default: () => { + return {data: [], meta: {}}; + }, + type: Object, + }, +}; + +export {indexProps}; diff --git a/resources/js/views/invoice/Index.vue b/resources/js/views/invoice/Index.vue index b54b83a7..b2ed2b77 100644 --- a/resources/js/views/invoice/Index.vue +++ b/resources/js/views/invoice/Index.vue @@ -1,8 +1,7 @@