refactor: abstract delete logic into useDestroy composable to reduce code duplication in data table actions

This commit is contained in:
Yoga Pangestu 2026-06-23 11:07:16 +07:00
parent dfd2c5560b
commit 18650f1cbf
18 changed files with 147 additions and 354 deletions

View File

@ -0,0 +1,46 @@
import { router } from '@inertiajs/vue3';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
interface UseDestroyOptions {
url: string;
preserveScroll?: boolean;
errorMessage?: string;
onSuccess?: () => void;
onError?: (errors: Record<string, string>) => string | void;
}
export function useDestroy({ url, preserveScroll = true, errorMessage, onSuccess, onError }: UseDestroyOptions) {
const open = ref(false);
const processing = ref(false);
function destroy() {
processing.value = true;
router.delete(url, {
preserveScroll,
onSuccess: () => {
open.value = false;
onSuccess?.();
},
onError: (errors) => {
if (onError) {
const result = onError(errors);
if (typeof result === 'string') {
toast.error(result);
return;
}
}
if (errorMessage) {
toast.error(errorMessage);
}
},
onFinish: () => {
processing.value = false;
},
});
}
return { open, processing, destroy };
}

View File

@ -1,12 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { computed, ref } from 'vue'; import { computed } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { CashTransactionListItem } from '@/types/cash'; import type { CashTransactionListItem } from '@/types/cash';
import { destroy } from '@/routes/admin/finance/cash/transactions'; import { destroy } from '@/routes/admin/finance/cash/transactions';
@ -22,25 +21,10 @@ const { can } = useCan();
const showActions = computed(() => props.transaction.reference_type === null); const showActions = computed(() => props.transaction.reference_type === null);
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyTransaction } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.transaction.id),
onError: (errors) => errors.amount || errors.transaction || 'Gagal menghapus setor kas.',
function destroyTransaction() { });
deleteProcessing.value = true;
router.delete(destroy.url(props.transaction.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: (errors) => {
toast.error(errors.amount || errors.transaction || 'Gagal menghapus setor kas.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -7,6 +7,7 @@ import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { EmployeeAdvanceListItem } from '@/types/employee-advance'; import type { EmployeeAdvanceListItem } from '@/types/employee-advance';
import { destroy, approve, pay } from '@/routes/admin/finance/employee_advances'; import { destroy, approve, pay } from '@/routes/admin/finance/employee_advances';
@ -41,29 +42,15 @@ const canDelete = computed(() => (
&& can('employee_advances.delete') && can('employee_advances.delete')
)); ));
const deleteConfirmOpen = ref(false);
const approveConfirmOpen = ref(false); const approveConfirmOpen = ref(false);
const payConfirmOpen = ref(false); const payConfirmOpen = ref(false);
const deleteProcessing = ref(false);
const approveProcessing = ref(false); const approveProcessing = ref(false);
const payProcessing = ref(false); const payProcessing = ref(false);
function destroyEmployeeAdvance() { const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyEmployeeAdvance } = useDestroy({
deleteProcessing.value = true; url: destroy.url(props.employeeAdvance.id),
errorMessage: 'Gagal menghapus kasbon.',
router.delete(destroy.url(props.employeeAdvance.id), { });
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus kasbon.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
function approveEmployeeAdvance() { function approveEmployeeAdvance() {
approveProcessing.value = true; approveProcessing.value = true;

View File

@ -1,12 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { ExpenseListItem } from '@/types/expense'; import type { ExpenseListItem } from '@/types/expense';
import { destroy } from '@/routes/admin/finance/expenses'; import { destroy } from '@/routes/admin/finance/expenses';
@ -21,25 +19,10 @@ const emit = defineEmits<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyExpense } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.expense.id),
onError: (errors) => errors.amount || errors.transaction || 'Gagal menghapus pengeluaran.',
function destroyExpense() { });
deleteProcessing.value = true;
router.delete(destroy.url(props.expense.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: (errors) => {
toast.error(errors.amount || errors.transaction || 'Gagal menghapus pengeluaran.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -1,8 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { Trash2 } from '@lucide/vue'; import { Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import AttendanceMap from './AttendanceMap.vue'; import AttendanceMap from './AttendanceMap.vue';
import AttendancePhotoCell from './attendance-photo-cell.vue'; import AttendancePhotoCell from './attendance-photo-cell.vue';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
@ -15,6 +12,7 @@ import {
DialogTitle, DialogTitle,
} from '@/components/ui/dialog'; } from '@/components/ui/dialog';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { AttendanceListItem } from '@/types/attendance'; import type { AttendanceListItem } from '@/types/attendance';
import { destroy } from '@/routes/admin/hr/attendances'; import { destroy } from '@/routes/admin/hr/attendances';
@ -26,30 +24,13 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyAttendance } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.attendance?.id ?? 0),
errorMessage: 'Gagal menghapus data presensi.',
function destroyAttendance() { onSuccess: () => {
if (!props.attendance) { open.value = false;
return; },
} });
deleteProcessing.value = true;
router.delete(destroy.url(props.attendance.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
open.value = false;
},
onError: () => {
toast.error('Gagal menghapus data presensi.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -1,12 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { Trash2 } from '@lucide/vue'; import { Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { AttendanceListItem } from '@/types/attendance'; import type { AttendanceListItem } from '@/types/attendance';
import { destroy } from '@/routes/admin/hr/attendances'; import { destroy } from '@/routes/admin/hr/attendances';
@ -16,25 +14,10 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyAttendance } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.attendance.id),
errorMessage: 'Gagal menghapus data presensi.',
function destroyAttendance() { });
deleteProcessing.value = true;
router.delete(destroy.url(props.attendance.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus data presensi.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -7,6 +7,7 @@ import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { EmployeeListItem } from '@/types/employee'; import type { EmployeeListItem } from '@/types/employee';
import { edit, destroy, reset_password } from '@/routes/admin/hr/employees'; import { edit, destroy, reset_password } from '@/routes/admin/hr/employees';
@ -18,26 +19,14 @@ const { can } = useCan();
const page = usePage(); const page = usePage();
const defaultPassword = page.props.auth.password_default as string; const defaultPassword = page.props.auth.password_default as string;
const deleteConfirmOpen = ref(false);
const resetPasswordConfirmOpen = ref(false); const resetPasswordConfirmOpen = ref(false);
const deleteProcessing = ref(false);
const resetPasswordProcessing = ref(false); const resetPasswordProcessing = ref(false);
function destroyEmployee() { const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyEmployee } = useDestroy({
deleteProcessing.value = true; url: destroy.url(props.employee.id),
preserveScroll: false,
router.delete(destroy.url(props.employee.id), { errorMessage: 'Gagal menghapus pegawai.',
onSuccess: () => { });
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus pegawai.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
function resetPassword() { function resetPassword() {
resetPasswordProcessing.value = true; resetPasswordProcessing.value = true;

View File

@ -7,6 +7,7 @@ import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { LeaveRequestListItem } from '@/types/leave-request'; import type { LeaveRequestListItem } from '@/types/leave-request';
import { destroy, approve } from '@/routes/admin/hr/leave_requests'; import { destroy, approve } from '@/routes/admin/hr/leave_requests';
@ -41,27 +42,13 @@ const canDelete = computed(() => (
&& can('leave_requests.delete') && can('leave_requests.delete')
)); ));
const deleteConfirmOpen = ref(false);
const approveConfirmOpen = ref(false); const approveConfirmOpen = ref(false);
const deleteProcessing = ref(false);
const approveProcessing = ref(false); const approveProcessing = ref(false);
function destroyLeaveRequest() { const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyLeaveRequest } = useDestroy({
deleteProcessing.value = true; url: destroy.url(props.leaveRequest.id),
errorMessage: 'Gagal menghapus pengajuan cuti.',
router.delete(destroy.url(props.leaveRequest.id), { });
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus pengajuan cuti.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
function approveLeaveRequest() { function approveLeaveRequest() {
approveProcessing.value = true; approveProcessing.value = true;

View File

@ -30,6 +30,7 @@ import {
TooltipTrigger, TooltipTrigger,
} from '@/components/ui/tooltip'; } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import { CuttingStatus } from '@/constants/cutting-status'; import { CuttingStatus } from '@/constants/cutting-status';
import { RupiahInput } from '@/components/form/rupiah-input'; import { RupiahInput } from '@/components/form/rupiah-input';
import { parseRupiah } from '@/lib/rupiah'; import { parseRupiah } from '@/lib/rupiah';
@ -47,8 +48,6 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false);
const deleteProcessing = ref(false);
const statusConfirmOpen = ref(false); const statusConfirmOpen = ref(false);
const statusProcessing = ref(false); const statusProcessing = ref(false);
const rejectDialogOpen = ref(false); const rejectDialogOpen = ref(false);
@ -56,6 +55,11 @@ const verifyDialogOpen = ref(false);
const allMatches = ref(true); const allMatches = ref(true);
const pendingAction = ref<CuttingStatusAction | null>(null); const pendingAction = ref<CuttingStatusAction | null>(null);
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyCutting } = useDestroy({
url: destroy.url(props.cutting.id),
errorMessage: 'Gagal menghapus cutting.',
});
const rejectForm = useForm({ const rejectForm = useForm({
status: CuttingStatus.REJECTED, status: CuttingStatus.REJECTED,
reason: '', reason: '',
@ -284,23 +288,6 @@ watch(rejectDialogOpen, (isOpen) => {
} }
}); });
function destroyCutting() {
deleteProcessing.value = true;
router.delete(destroy.url(props.cutting.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus cutting.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
function actionIcon(status: string) { function actionIcon(status: string) {
if (status === CuttingStatus.COMPLETED) { if (status === CuttingStatus.COMPLETED) {
return Scissors; return Scissors;

View File

@ -30,6 +30,7 @@ import {
TableRow, TableRow,
} from '@/components/ui/table'; } from '@/components/ui/table';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import { MarketplaceFeeScope } from '@/constants/marketplace-fee-scope'; import { MarketplaceFeeScope } from '@/constants/marketplace-fee-scope';
import { MarketplaceFeeValueType } from '@/constants/marketplace-fee-value-type'; import { MarketplaceFeeValueType } from '@/constants/marketplace-fee-value-type';
import { OrderStatus } from '@/constants/order-status'; import { OrderStatus } from '@/constants/order-status';
@ -44,8 +45,6 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false);
const deleteProcessing = ref(false);
const statusConfirmOpen = ref(false); const statusConfirmOpen = ref(false);
const statusProcessing = ref(false); const statusProcessing = ref(false);
const pendingAction = ref<OrderStatusAction | null>(null); const pendingAction = ref<OrderStatusAction | null>(null);
@ -53,6 +52,12 @@ const pendingAction = ref<OrderStatusAction | null>(null);
const canEdit = computed(() => props.order.is_editable && can('orders.update')); const canEdit = computed(() => props.order.is_editable && can('orders.update'));
const canDelete = computed(() => can('orders.delete')); const canDelete = computed(() => can('orders.delete'));
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyOrder } = useDestroy({
url: destroy.url(props.order.id),
preserveScroll: false,
errorMessage: 'Gagal menghapus pesanan.',
});
const creatorName = computed(() => { const creatorName = computed(() => {
return props.order.created_by?.profile?.full_name ?? props.order.created_by?.username ?? '-'; return props.order.created_by?.profile?.full_name ?? props.order.created_by?.username ?? '-';
}); });
@ -115,22 +120,6 @@ function transitionStatus() {
}); });
} }
function destroyOrder() {
deleteProcessing.value = true;
router.delete(destroy.url(props.order.id), {
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus pesanan.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
const items = computed(() => props.order.items ?? []); const items = computed(() => props.order.items ?? []);
const summaryRows = computed(() => { const summaryRows = computed(() => {

View File

@ -8,6 +8,7 @@ import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import { OrderStatus } from '@/constants/order-status'; import { OrderStatus } from '@/constants/order-status';
import type { OrderListItem, OrderStatusAction } from '@/types/order'; import type { OrderListItem, OrderStatusAction } from '@/types/order';
import { show, edit, destroy, transition_status } from '@/routes/admin/manage/orders'; import { show, edit, destroy, transition_status } from '@/routes/admin/manage/orders';
@ -18,8 +19,6 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false);
const deleteProcessing = ref(false);
const statusConfirmOpen = ref(false); const statusConfirmOpen = ref(false);
const statusProcessing = ref(false); const statusProcessing = ref(false);
const pendingAction = ref<OrderStatusAction | null>(null); const pendingAction = ref<OrderStatusAction | null>(null);
@ -29,6 +28,11 @@ const availableActions = computed(() => props.order.available_actions ?? []);
const canEdit = computed(() => props.order.is_editable && can('orders.update')); const canEdit = computed(() => props.order.is_editable && can('orders.update'));
const canDelete = computed(() => can('orders.delete')); const canDelete = computed(() => can('orders.delete'));
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyOrder } = useDestroy({
url: destroy.url(props.order.id),
errorMessage: 'Gagal menghapus pesanan.',
});
function canPerformAction(action: OrderStatusAction): boolean { function canPerformAction(action: OrderStatusAction): boolean {
return can(action.permission); return can(action.permission);
} }
@ -76,23 +80,6 @@ function transitionStatus() {
}); });
} }
function destroyOrder() {
deleteProcessing.value = true;
router.delete(destroy.url(props.order.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus pesanan.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
function actionIcon(status: string) { function actionIcon(status: string) {
if (status === OrderStatus.PROCESSING) { if (status === OrderStatus.PROCESSING) {
return Send; return Send;

View File

@ -1,12 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { Link, router } from '@inertiajs/vue3'; import { Link } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { PurchaseListItem } from '@/types/purchase'; import type { PurchaseListItem } from '@/types/purchase';
import { edit, destroy } from '@/routes/admin/manage/purchases'; import { edit, destroy } from '@/routes/admin/manage/purchases';
@ -16,25 +15,10 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyPurchase } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.purchase.id),
errorMessage: 'Gagal menghapus belanja.',
function destroyPurchase() { });
deleteProcessing.value = true;
router.delete(destroy.url(props.purchase.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus belanja.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -1,12 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { CategoryListItem } from '@/types/category'; import type { CategoryListItem } from '@/types/category';
import { destroy } from '@/routes/admin/master/categories'; import { destroy } from '@/routes/admin/master/categories';
@ -20,25 +18,10 @@ const emit = defineEmits<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyCategory } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.category.id),
errorMessage: 'Gagal menghapus kategori.',
function destroyCategory() { });
deleteProcessing.value = true;
router.delete(destroy.url(props.category.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus kategori.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -1,12 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { CustomerListItem } from '@/types/customer'; import type { CustomerListItem } from '@/types/customer';
import { destroy } from '@/routes/admin/master/customers'; import { destroy } from '@/routes/admin/master/customers';
@ -20,25 +18,10 @@ const emit = defineEmits<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyCustomer } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.customer.id),
errorMessage: 'Gagal menghapus customer.',
function destroyCustomer() { });
deleteProcessing.value = true;
router.delete(destroy.url(props.customer.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus customer.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -1,12 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { Link, router } from '@inertiajs/vue3'; import { Link } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { ProductListItem } from '@/types/product'; import type { ProductListItem } from '@/types/product';
import { edit, destroy } from '@/routes/admin/master/products'; import { edit, destroy } from '@/routes/admin/master/products';
@ -16,24 +15,11 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyProduct } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.product.id),
preserveScroll: false,
function destroyProduct() { errorMessage: 'Gagal menghapus produk.',
deleteProcessing.value = true; });
router.delete(destroy.url(props.product.id), {
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus produk.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -1,12 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { Link, router } from '@inertiajs/vue3'; import { Link } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { RawMaterialListItem } from '@/types/raw-material'; import type { RawMaterialListItem } from '@/types/raw-material';
import { edit, destroy } from '@/routes/admin/master/raw_materials'; import { edit, destroy } from '@/routes/admin/master/raw_materials';
@ -16,24 +15,11 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyRawMaterial } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.material.id),
preserveScroll: false,
function destroyRawMaterial() { errorMessage: 'Gagal menghapus bahan baku.',
deleteProcessing.value = true; });
router.delete(destroy.url(props.material.id), {
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus bahan baku.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -1,12 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { router } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { SupplierListItem } from '@/types/supplier'; import type { SupplierListItem } from '@/types/supplier';
import { destroy } from '@/routes/admin/master/suppliers'; import { destroy } from '@/routes/admin/master/suppliers';
@ -20,25 +18,10 @@ const emit = defineEmits<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false); const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroySupplier } = useDestroy({
const deleteProcessing = ref(false); url: destroy.url(props.supplier.id),
errorMessage: 'Gagal menghapus supplier.',
function destroySupplier() { });
deleteProcessing.value = true;
router.delete(destroy.url(props.supplier.id), {
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus supplier.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { Link, router } from '@inertiajs/vue3'; import { Link } from '@inertiajs/vue3';
import { Pencil, Trash2 } from '@lucide/vue'; import { Pencil, Trash2 } from '@lucide/vue';
import { computed, ref } from 'vue'; import { computed } from 'vue';
import { toast } from 'vue-sonner';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useCan } from '@/composables/useCan'; import { useCan } from '@/composables/useCan';
import { useDestroy } from '@/composables/useDestroy';
import type { RoleListItem } from './columns'; import type { RoleListItem } from './columns';
import { edit, destroy } from '@/routes/admin/system/roles'; import { edit, destroy } from '@/routes/admin/system/roles';
@ -16,29 +16,14 @@ const props = defineProps<{
const { can } = useCan(); const { can } = useCan();
const deleteConfirmOpen = ref(false);
const deleteProcessing = ref(false);
const isSystemRole = computed(() => { const isSystemRole = computed(() => {
return ['developer', 'owner', 'admin-toko', 'admin-bahan-baku', 'direktur', 'marketing', 'cashier', 'non-operator'].includes(props.role.name); return ['developer', 'owner', 'admin-toko', 'admin-bahan-baku', 'direktur', 'marketing', 'cashier', 'non-operator'].includes(props.role.name);
}); });
function destroyRole() { const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyRole } = useDestroy({
deleteProcessing.value = true; url: destroy.url(props.role.id),
errorMessage: 'Gagal menghapus role.',
router.delete(destroy.url(props.role.id), { });
preserveScroll: true,
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus role.');
},
onFinish: () => {
deleteProcessing.value = false;
},
});
}
</script> </script>
<template> <template>