refactor: replace inline action buttons with standardized component-based row actions across data tables and forms
This commit is contained in:
parent
4414f2c050
commit
9f75a4416a
22
resources/js/components/button/RowAdjustAction.vue
Normal file
22
resources/js/components/button/RowAdjustAction.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { SlidersHorizontal } from '@lucide/vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
||||
defineProps<{
|
||||
tooltip?: string;
|
||||
disabled?: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" :disabled="disabled">
|
||||
<SlidersHorizontal class="size-4" />
|
||||
<span class="sr-only">{{ tooltip || 'Sesuaikan' }}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ tooltip || 'Sesuaikan' }}</TooltipContent>
|
||||
</Tooltip>
|
||||
</template>
|
||||
@ -6,14 +6,16 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
|
||||
defineProps<{
|
||||
tooltip?: string;
|
||||
disabled?: boolean;
|
||||
size?: 'default' | 'sm';
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8 text-green-600 hover:text-green-700" :disabled="disabled">
|
||||
<Check class="size-4" />
|
||||
<Button variant="ghost" :size="size === 'sm' ? 'sm' : 'icon'"
|
||||
:class="size === 'sm' ? '' : 'size-8'" class="text-green-600 hover:text-green-700" :disabled="disabled">
|
||||
<Check :class="size === 'sm' ? 'size-3.5' : 'size-4'" />
|
||||
<span class="sr-only">{{ tooltip || 'Setujui' }}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
|
||||
@ -1,61 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import { Trash2 } from '@lucide/vue';
|
||||
import { ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
|
||||
const props = defineProps<{
|
||||
actionUrl: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
actionUrl?: string; // If provided, handles the deletion request automatically.
|
||||
errorMessage?: string;
|
||||
tooltip?: string;
|
||||
tooltipClass?: string;
|
||||
buttonClass?: string;
|
||||
onSuccess?: () => void;
|
||||
onError?: (errors: Record<string, string>) => string | void;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
confirm: [];
|
||||
}>();
|
||||
|
||||
const deleteConfirmOpen = ref(false);
|
||||
const deleteProcessing = ref(false);
|
||||
|
||||
function handleConfirm() {
|
||||
if (props.actionUrl) {
|
||||
deleteProcessing.value = true;
|
||||
router.delete(props.actionUrl, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
},
|
||||
onError: (errors) => {
|
||||
const firstError = Object.values(errors)[0];
|
||||
toast.error(firstError || props.errorMessage || 'Gagal menghapus data.');
|
||||
},
|
||||
onFinish: () => {
|
||||
deleteProcessing.value = false;
|
||||
},
|
||||
});
|
||||
} else {
|
||||
emit('confirm');
|
||||
}
|
||||
}
|
||||
const { open, processing, destroy } = useDestroy({
|
||||
url: props.actionUrl,
|
||||
errorMessage: props.errorMessage ?? 'Gagal menghapus data.',
|
||||
onSuccess: props.onSuccess,
|
||||
onError: props.onError,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
:class="buttonClass" @click="open = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
<span class="sr-only">{{ tooltip || 'Hapus' }}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
<TooltipContent :class="tooltipClass">{{ tooltip || 'Hapus' }}</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<ConfirmDialog v-model:open="deleteConfirmOpen" :title="title || 'Hapus data?'"
|
||||
<ConfirmDialog v-model:open="open" :title="title || 'Hapus data?'"
|
||||
:description="description || 'Data akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.'"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="handleConfirm" />
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="processing" @confirm="destroy" />
|
||||
</template>
|
||||
|
||||
@ -6,23 +6,31 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
|
||||
|
||||
defineProps<{
|
||||
href?: string;
|
||||
tooltip?: string;
|
||||
tooltipClass?: string;
|
||||
buttonClass?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
click: [];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" :as-child="!!href">
|
||||
<Button variant="ghost" size="icon" class="size-8" :class="buttonClass" :as-child="!!href"
|
||||
@click="!href && emit('click')">
|
||||
<Link v-if="href" :href="href">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
<span class="sr-only">{{ tooltip || 'Ubah' }}</span>
|
||||
</Link>
|
||||
<template v-else>
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
<span class="sr-only">{{ tooltip || 'Ubah' }}</span>
|
||||
</template>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
<TooltipContent :class="tooltipClass">{{ tooltip || 'Ubah' }}</TooltipContent>
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
||||
22
resources/js/components/button/RowPayAction.vue
Normal file
22
resources/js/components/button/RowPayAction.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { Banknote } from '@lucide/vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
||||
defineProps<{
|
||||
tooltip?: string;
|
||||
disabled?: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" :disabled="disabled">
|
||||
<Banknote class="size-4" />
|
||||
<span class="sr-only">{{ tooltip || 'Bayar' }}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ tooltip || 'Bayar' }}</TooltipContent>
|
||||
</Tooltip>
|
||||
</template>
|
||||
37
resources/js/components/button/RowPrintAction.vue
Normal file
37
resources/js/components/button/RowPrintAction.vue
Normal file
@ -0,0 +1,37 @@
|
||||
<script setup lang="ts">
|
||||
import { Printer } from '@lucide/vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Popover from '@/components/ui/popover/Popover.vue';
|
||||
import PopoverContent from '@/components/ui/popover/PopoverContent.vue';
|
||||
import PopoverTrigger from '@/components/ui/popover/PopoverTrigger.vue';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
||||
defineProps<{
|
||||
tooltip?: string;
|
||||
disabled?: boolean;
|
||||
popoverAlign?: 'start' | 'center' | 'end';
|
||||
}>();
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<Popover v-model:open="open">
|
||||
<TooltipTrigger as-child>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" :disabled="disabled">
|
||||
<Printer class="size-4" />
|
||||
<span class="sr-only">{{ tooltip || 'Cetak' }}</span>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent>{{ tooltip || 'Cetak' }}</TooltipContent>
|
||||
|
||||
<PopoverContent :align="popoverAlign || 'end'" class="w-40 space-y-2 p-3">
|
||||
<slot name="popover-content" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Tooltip>
|
||||
</template>
|
||||
@ -6,14 +6,16 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
|
||||
defineProps<{
|
||||
tooltip?: string;
|
||||
disabled?: boolean;
|
||||
size?: 'default' | 'sm';
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8 text-destructive hover:text-destructive" :disabled="disabled">
|
||||
<X class="size-4" />
|
||||
<Button variant="ghost" :size="size === 'sm' ? 'sm' : 'icon'"
|
||||
:class="size === 'sm' ? '' : 'size-8'" class="text-destructive hover:text-destructive" :disabled="disabled">
|
||||
<X :class="size === 'sm' ? 'size-3.5' : 'size-4'" />
|
||||
<span class="sr-only">{{ tooltip || 'Tolak' }}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
|
||||
32
resources/js/components/button/RowStatusAction.vue
Normal file
32
resources/js/components/button/RowStatusAction.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import type { Component } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
||||
defineProps<{
|
||||
icon: Component;
|
||||
label: string;
|
||||
destructive?: boolean;
|
||||
size?: 'default' | 'sm';
|
||||
disabled?: boolean;
|
||||
tooltipClass?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
click: [];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" :size="size === 'sm' ? 'sm' : 'icon'"
|
||||
:class="[size === 'sm' ? '' : 'size-8', destructive ? 'text-destructive hover:text-destructive' : '']"
|
||||
:disabled="disabled" @click="emit('click')">
|
||||
<component :is="icon" :class="size === 'sm' ? 'size-3.5' : 'size-4'" />
|
||||
<span class="sr-only">{{ label }}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent :class="tooltipClass">{{ label }}</TooltipContent>
|
||||
</Tooltip>
|
||||
</template>
|
||||
@ -2,6 +2,10 @@ export { default as RowEditAction } from './RowEditAction.vue';
|
||||
export { default as RowDeleteAction } from './RowDeleteAction.vue';
|
||||
export { default as RowApproveAction } from './RowApproveAction.vue';
|
||||
export { default as RowRejectAction } from './RowRejectAction.vue';
|
||||
export { default as RowPayAction } from './RowPayAction.vue';
|
||||
export { default as RowAdjustAction } from './RowAdjustAction.vue';
|
||||
export { default as RowStatusAction } from './RowStatusAction.vue';
|
||||
export { default as RowPrintAction } from './RowPrintAction.vue';
|
||||
export { default as RowDetailAction } from './RowDetailAction.vue';
|
||||
export { default as CreateButton } from './CreateButton.vue';
|
||||
export { default as BackButton } from './BackButton.vue';
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import { computed } from 'vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { CashTransactionListItem } from '@/types/cash';
|
||||
import { destroy } from '@/routes/admin/finance/cash/transactions';
|
||||
|
||||
@ -20,41 +16,15 @@ const emit = defineEmits<{
|
||||
const { can } = useCan();
|
||||
|
||||
const showActions = computed(() => props.transaction.reference_type === null);
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyTransaction } = useDestroy({
|
||||
url: destroy.url(props.transaction.id),
|
||||
onError: (errors) => errors.amount || errors.transaction || 'Gagal menghapus setor kas.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="showActions">
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('cash.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="emit('edit', transaction)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('cash.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('cash.update')" @click="emit('edit', transaction)" />
|
||||
<RowDeleteAction v-if="can('cash.delete')" :action-url="destroy.url(transaction.id)" title="Hapus setor kas?"
|
||||
:description="`Setor kas sebesar ${transaction.amount_formatted} akan dihapus. Saldo kas akan disesuaikan.`"
|
||||
:on-error="(errors) => errors.amount || errors.transaction || 'Gagal menghapus setor kas.'" />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('cash.delete')" v-model:open="deleteConfirmOpen" title="Hapus setor kas?"
|
||||
:description="`Setor kas sebesar ${transaction.amount_formatted} akan dihapus. Saldo kas akan disesuaikan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing"
|
||||
@confirm="destroyTransaction" />
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import { Banknote, Check, Pencil, Trash2, X } from '@lucide/vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { RowApproveAction, RowDeleteAction, RowEditAction, RowPayAction, RowRejectAction } from '@/components/button';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { EmployeeAdvanceListItem } from '@/types/employee-advance';
|
||||
import { destroy, approve, pay } from '@/routes/admin/finance/employee_advances';
|
||||
|
||||
@ -47,11 +44,6 @@ const payConfirmOpen = ref(false);
|
||||
const approveProcessing = ref(false);
|
||||
const payProcessing = ref(false);
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyEmployeeAdvance } = useDestroy({
|
||||
url: destroy.url(props.employeeAdvance.id),
|
||||
errorMessage: 'Gagal menghapus kasbon.',
|
||||
});
|
||||
|
||||
function approveEmployeeAdvance() {
|
||||
approveProcessing.value = true;
|
||||
|
||||
@ -89,58 +81,22 @@ function payEmployeeAdvance() {
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="canEdit">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="emit('edit', employeeAdvance)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="canEdit" @click="emit('edit', employeeAdvance)" />
|
||||
|
||||
<Tooltip v-if="employeeAdvance.can_verify && can('employee_advances.verify')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8 text-green-600 hover:text-green-600"
|
||||
@click="approveConfirmOpen = true">
|
||||
<Check class="size-4" />
|
||||
<span class="sr-only">Setujui</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Setujui</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowApproveAction v-if="employeeAdvance.can_verify && can('employee_advances.verify')" tooltip="Setujui"
|
||||
@click="approveConfirmOpen = true" />
|
||||
|
||||
<Tooltip v-if="employeeAdvance.can_verify && can('employee_advances.verify')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="emit('reject', employeeAdvance)">
|
||||
<X class="size-4" />
|
||||
<span class="sr-only">Tolak</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Tolak</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowRejectAction v-if="employeeAdvance.can_verify && can('employee_advances.verify')" tooltip="Tolak"
|
||||
@click="emit('reject', employeeAdvance)" />
|
||||
|
||||
<Tooltip v-if="employeeAdvance.can_pay && can('employee_advances.pay')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="payConfirmOpen = true">
|
||||
<Banknote class="size-4" />
|
||||
<span class="sr-only">Lunasi</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Lunasi Kasbon</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowPayAction v-if="employeeAdvance.can_pay && can('employee_advances.pay')" tooltip="Lunasi Kasbon"
|
||||
@click="payConfirmOpen = true" />
|
||||
|
||||
<Tooltip v-if="canDelete">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<template v-if="canDelete">
|
||||
<RowDeleteAction :action-url="destroy.url(employeeAdvance.id)" title="Hapus kasbon?"
|
||||
:description="`Pengajuan kasbon ${employeeAdvance.amount_formatted} akan dihapus.`"
|
||||
error-message="Gagal menghapus kasbon." />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('employee_advances.verify')" v-model:open="approveConfirmOpen" title="Setujui kasbon?"
|
||||
@ -150,8 +106,4 @@ function payEmployeeAdvance() {
|
||||
<ConfirmDialog v-if="can('employee_advances.pay')" v-model:open="payConfirmOpen" title="Lunasi kasbon?"
|
||||
:description="`Pelunasan kasbon ${employeeAdvance.amount_formatted} dari ${employeeAdvance.employee_name}. Saldo kas akan bertambah.`"
|
||||
confirm-label="Lunasi" cancel-label="Batal" :loading="payProcessing" @confirm="payEmployeeAdvance" />
|
||||
|
||||
<ConfirmDialog v-if="canDelete" v-model:open="deleteConfirmOpen" title="Hapus kasbon?"
|
||||
:description="`Pengajuan kasbon ${employeeAdvance.amount_formatted} akan dihapus.`" confirm-label="Hapus"
|
||||
cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroyEmployeeAdvance" />
|
||||
</template>
|
||||
|
||||
@ -1,15 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { ExpenseListItem } from '@/types/expense';
|
||||
|
||||
import { destroy } from '@/routes/admin/finance/expenses';
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
expense: ExpenseListItem;
|
||||
}>();
|
||||
|
||||
@ -18,38 +13,13 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const { can } = useCan();
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyExpense } = useDestroy({
|
||||
url: destroy.url(props.expense.id),
|
||||
onError: (errors) => errors.amount || errors.transaction || 'Gagal menghapus pengeluaran.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('expenses.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="emit('edit', expense)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('expenses.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('expenses.update')" @click="emit('edit', expense)" />
|
||||
<RowDeleteAction v-if="can('expenses.delete')" :action-url="destroy.url(expense.id)" title="Hapus pengeluaran?"
|
||||
:description="`Pengeluaran ${expense.amount_formatted} akan dihapus. Saldo kas akan disesuaikan.`"
|
||||
:on-error="(errors) => errors.amount || errors.transaction || 'Gagal menghapus pengeluaran.'" />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('expenses.delete')" v-model:open="deleteConfirmOpen" title="Hapus pengeluaran?"
|
||||
:description="`Pengeluaran ${expense.amount_formatted} akan dihapus. Saldo kas akan disesuaikan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroyExpense" />
|
||||
</template>
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { useForm, router } from '@inertiajs/vue3';
|
||||
import { Pencil, Save, Trash2 } from '@lucide/vue';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
import { Save } from '@lucide/vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { RupiahInput } from '@/components/form/rupiah-input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@ -22,11 +23,6 @@ import {
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import { parseRupiah } from '@/lib/rupiah';
|
||||
@ -47,8 +43,6 @@ const form = useForm<PayrollAdjustmentFormData>({
|
||||
});
|
||||
|
||||
const editingAdjustment = ref<PayrollAdjustmentItem | null>(null);
|
||||
const deleteConfirmOpen = ref(false);
|
||||
const deleteTarget = ref<PayrollAdjustmentItem | null>(null);
|
||||
|
||||
function resetForm() {
|
||||
form.reset();
|
||||
@ -76,18 +70,6 @@ function cancelEdit() {
|
||||
resetForm();
|
||||
}
|
||||
|
||||
function deleteAdj(adjustment: PayrollAdjustmentItem) {
|
||||
router.delete(destroy.url(adjustment.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
toast.success('Penyesuaian berhasil dihapus.');
|
||||
},
|
||||
onError: () => {
|
||||
toast.error('Gagal menghapus penyesuaian.');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function submit() {
|
||||
if (!props.payroll) {
|
||||
return;
|
||||
@ -150,30 +132,13 @@ function submit() {
|
||||
<p class="text-xs text-muted-foreground">{{ adj.description }}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon"
|
||||
class="size-8 text-muted-foreground hover:text-foreground"
|
||||
@click="startEdit(adj)">
|
||||
<Pencil class="size-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent class="z-210">
|
||||
<p>Ubah</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon"
|
||||
class="size-8 text-destructive hover:bg-destructive/10"
|
||||
@click="deleteTarget = adj; deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent class="z-210">
|
||||
<p>Hapus</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction button-class="text-muted-foreground hover:text-foreground"
|
||||
tooltip-class="z-210" @click="startEdit(adj)" />
|
||||
<RowDeleteAction :action-url="destroy.url(adj.id)" tooltip="Hapus"
|
||||
button-class="hover:bg-destructive/10" tooltip-class="z-210"
|
||||
title="Hapus penyesuaian?" :description="`Penyesuaian ${adj.type_label} ${adj.amount_formatted} akan dihapus.`"
|
||||
error-message="Gagal menghapus penyesuaian."
|
||||
:on-success="() => toast.success('Penyesuaian berhasil dihapus.')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -231,8 +196,4 @@ function submit() {
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<ConfirmDialog v-model:open="deleteConfirmOpen" title="Hapus Penyesuaian?"
|
||||
:description="`Penyesuaian ${deleteTarget?.type_label} ${deleteTarget?.amount_formatted} akan dihapus.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive @confirm="deleteAdj(deleteTarget!)" />
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { SlidersHorizontal } from '@lucide/vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowAdjustAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { PayrollListItem } from '@/types/payroll';
|
||||
|
||||
@ -18,14 +16,7 @@ const { can } = useCan();
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="payroll.can_adjust && can('payroll.adjust')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="emit('adjust', payroll)">
|
||||
<SlidersHorizontal class="size-4" />
|
||||
<span class="sr-only">Sesuaikan</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Sesuaikan Gaji</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowAdjustAction v-if="payroll.can_adjust && can('payroll.adjust')" tooltip="Sesuaikan Gaji"
|
||||
@click="emit('adjust', payroll)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1,52 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { Trash2 } from '@lucide/vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { AttendanceListItem } from '@/types/attendance';
|
||||
import { destroy } from '@/routes/admin/hr/attendances';
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
attendance: AttendanceListItem;
|
||||
}>();
|
||||
|
||||
const { can } = useCan();
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyAttendance } = useDestroy({
|
||||
url: destroy.url(props.attendance.id),
|
||||
errorMessage: 'Gagal menghapus data presensi.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('attendances.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true"
|
||||
>
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowDeleteAction v-if="can('attendances.delete')" :action-url="destroy.url(attendance.id)" title="Hapus data presensi?"
|
||||
:description="`Presensi tanggal ${attendance.attendance_date_formatted} akan dihapus secara permanen.`"
|
||||
error-message="Gagal menghapus data presensi." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
v-if="can('attendances.delete')"
|
||||
v-model:open="deleteConfirmOpen"
|
||||
title="Hapus data presensi?"
|
||||
:description="`Presensi tanggal ${attendance.attendance_date_formatted} akan dihapus secara permanen.`"
|
||||
confirm-label="Hapus"
|
||||
cancel-label="Batal"
|
||||
destructive
|
||||
:loading="deleteProcessing"
|
||||
@confirm="destroyAttendance"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { Link, router, usePage } from '@inertiajs/vue3';
|
||||
import { KeyRound, Pencil, Trash2 } from '@lucide/vue';
|
||||
import { router, usePage } from '@inertiajs/vue3';
|
||||
import { KeyRound } from '@lucide/vue';
|
||||
import { ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { RowDeleteAction, RowEditAction, RowStatusAction } from '@/components/button';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { EmployeeListItem } from '@/types/employee';
|
||||
import { edit, destroy, reset_password } from '@/routes/admin/hr/employees';
|
||||
|
||||
@ -22,12 +20,6 @@ const defaultPassword = page.props.auth.password_default as string;
|
||||
const resetPasswordConfirmOpen = ref(false);
|
||||
const resetPasswordProcessing = ref(false);
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyEmployee } = useDestroy({
|
||||
url: destroy.url(props.employee.id),
|
||||
preserveScroll: false,
|
||||
errorMessage: 'Gagal menghapus pegawai.',
|
||||
});
|
||||
|
||||
function resetPassword() {
|
||||
resetPasswordProcessing.value = true;
|
||||
|
||||
@ -48,38 +40,14 @@ function resetPassword() {
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('employees.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="edit.url(employee.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('employees.update')" :href="edit.url(employee.id)" />
|
||||
|
||||
<Tooltip v-if="can('employees.reset_password')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="resetPasswordConfirmOpen = true">
|
||||
<KeyRound class="size-4" />
|
||||
<span class="sr-only">Reset Kata Sandi</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Reset Kata Sandi</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowStatusAction v-if="can('employees.reset_password')" :icon="KeyRound" label="Reset Kata Sandi"
|
||||
@click="resetPasswordConfirmOpen = true" />
|
||||
|
||||
<Tooltip v-if="can('employees.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowDeleteAction v-if="can('employees.delete')" :action-url="destroy.url(employee.id)" title="Hapus pegawai?"
|
||||
:description="`Data pegawai ${employee.profile?.full_name ?? ''} akan dihapus secara permanen beserta akun pengguna terkait. Tindakan ini tidak dapat dibatalkan.`"
|
||||
error-message="Gagal menghapus pegawai." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
@ -89,11 +57,4 @@ function resetPassword() {
|
||||
:description="`Kata sandi ${employee.profile?.full_name ?? 'pegawai'} akan direset ke kata sandi default sistem (${defaultPassword}). Pengguna akan otomatis logout dari semua sesi aktif.`"
|
||||
confirm-label="Reset Kata Sandi" cancel-label="Batal" :loading="resetPasswordProcessing"
|
||||
@confirm="resetPassword" />
|
||||
|
||||
<ConfirmDialog
|
||||
v-if="can('employees.delete')"
|
||||
v-model:open="deleteConfirmOpen"
|
||||
title="Hapus pegawai?"
|
||||
:description="`Data pegawai ${employee.profile?.full_name ?? ''} akan dihapus secara permanen beserta akun pengguna terkait. Tindakan ini tidak dapat dibatalkan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroyEmployee" />
|
||||
</template>
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import { Check, Pencil, Trash2, X } from '@lucide/vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { RowApproveAction, RowDeleteAction, RowEditAction, RowRejectAction } from '@/components/button';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { LeaveRequestListItem } from '@/types/leave-request';
|
||||
import { destroy, approve } from '@/routes/admin/hr/leave_requests';
|
||||
|
||||
@ -45,11 +42,6 @@ const canDelete = computed(() => (
|
||||
const approveConfirmOpen = ref(false);
|
||||
const approveProcessing = ref(false);
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyLeaveRequest } = useDestroy({
|
||||
url: destroy.url(props.leaveRequest.id),
|
||||
errorMessage: 'Gagal menghapus pengajuan cuti.',
|
||||
});
|
||||
|
||||
function approveLeaveRequest() {
|
||||
approveProcessing.value = true;
|
||||
|
||||
@ -70,55 +62,22 @@ function approveLeaveRequest() {
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="canEdit">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="emit('edit', leaveRequest)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="canEdit" @click="emit('edit', leaveRequest)" />
|
||||
|
||||
<Tooltip v-if="leaveRequest.can_verify && can('leave_requests.verify')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8 text-green-600 hover:text-green-600"
|
||||
@click="approveConfirmOpen = true">
|
||||
<Check class="size-4" />
|
||||
<span class="sr-only">Setujui</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Setujui</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowApproveAction v-if="leaveRequest.can_verify && can('leave_requests.verify')" tooltip="Setujui"
|
||||
@click="approveConfirmOpen = true" />
|
||||
|
||||
<Tooltip v-if="leaveRequest.can_verify && can('leave_requests.verify')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="emit('reject', leaveRequest)">
|
||||
<X class="size-4" />
|
||||
<span class="sr-only">Tolak</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Tolak</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowRejectAction v-if="leaveRequest.can_verify && can('leave_requests.verify')" tooltip="Tolak"
|
||||
@click="emit('reject', leaveRequest)" />
|
||||
|
||||
<Tooltip v-if="canDelete">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<template v-if="canDelete">
|
||||
<RowDeleteAction :action-url="destroy.url(leaveRequest.id)" title="Hapus pengajuan cuti?"
|
||||
:description="`Pengajuan cuti ${leaveRequest.employee_name} akan dihapus.`"
|
||||
error-message="Gagal menghapus pengajuan cuti." />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('leave_requests.verify')" v-model:open="approveConfirmOpen" title="Setujui cuti?"
|
||||
:description="`Cuti ${leaveRequest.employee_name} (${leaveRequest.start_date_formatted} - ${leaveRequest.end_date_formatted}, ${leaveRequest.total_days} hari) akan disetujui.`"
|
||||
confirm-label="Setujui" cancel-label="Batal" :loading="approveProcessing" @confirm="approveLeaveRequest" />
|
||||
|
||||
<ConfirmDialog v-if="canDelete" v-model:open="deleteConfirmOpen" title="Hapus pengajuan cuti?"
|
||||
:description="`Pengajuan cuti ${leaveRequest.employee_name} akan dihapus.`" confirm-label="Hapus"
|
||||
cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroyLeaveRequest" />
|
||||
</template>
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { Link, router, useForm } from '@inertiajs/vue3';
|
||||
import { Check, Pencil, RotateCcw, Scissors, Trash2, X } from '@lucide/vue';
|
||||
import { Check, RotateCcw, Scissors, X } from '@lucide/vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { RowDeleteAction, RowEditAction, RowStatusAction } from '@/components/button';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@ -24,13 +25,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import { CuttingStatus } from '@/constants/cutting-status';
|
||||
import { RupiahInput } from '@/components/form/rupiah-input';
|
||||
import { parseRupiah } from '@/lib/rupiah';
|
||||
@ -55,11 +50,6 @@ const verifyDialogOpen = ref(false);
|
||||
const allMatches = ref(true);
|
||||
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({
|
||||
status: CuttingStatus.REJECTED,
|
||||
reason: '',
|
||||
@ -308,58 +298,17 @@ function actionIcon(status: string) {
|
||||
<template>
|
||||
<div class="flex flex-wrap items-center justify-end gap-1">
|
||||
<template v-for="action in availableActions" :key="action.status">
|
||||
<Tooltip v-if="canPerformAction(action)">
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
:class="
|
||||
action.destructive
|
||||
? 'text-destructive hover:text-destructive'
|
||||
: ''
|
||||
"
|
||||
@click="openStatusConfirm(action)"
|
||||
>
|
||||
<component
|
||||
:is="actionIcon(action.status)"
|
||||
class="size-3.5"
|
||||
/>
|
||||
<span class="sr-only">{{ action.label }}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent>
|
||||
{{ action.label }}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowStatusAction v-if="canPerformAction(action)" :size="'sm'"
|
||||
:icon="actionIcon(action.status)" :label="action.label" :destructive="action.destructive"
|
||||
@click="openStatusConfirm(action)" />
|
||||
</template>
|
||||
|
||||
<Tooltip v-if="canEdit">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="edit.url(cutting.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="canEdit" :href="edit.url(cutting.id)" />
|
||||
|
||||
<Tooltip v-if="canDelete">
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="size-8 text-destructive hover:text-destructive"
|
||||
@click="deleteConfirmOpen = true"
|
||||
>
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<template v-if="canDelete">
|
||||
<RowDeleteAction :action-url="destroy.url(cutting.id)" title="Hapus cutting?"
|
||||
description="Data cutting ini akan dihapus permanen." error-message="Gagal menghapus cutting." />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
@ -379,18 +328,6 @@ function actionIcon(status: string) {
|
||||
@confirm="transitionStatus"
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
v-if="canDelete"
|
||||
v-model:open="deleteConfirmOpen"
|
||||
title="Hapus cutting?"
|
||||
description="Data cutting ini akan dihapus permanen."
|
||||
confirm-label="Hapus"
|
||||
cancel-label="Batal"
|
||||
destructive
|
||||
:loading="deleteProcessing"
|
||||
@confirm="destroyCutting"
|
||||
/>
|
||||
|
||||
<Dialog v-model:open="rejectDialogOpen">
|
||||
<DialogContent class="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
|
||||
@ -1,15 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { usePage } from '@inertiajs/vue3';
|
||||
import { Printer } from '@lucide/vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { RowPrintAction } from '@/components/button';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Popover from '@/components/ui/popover/Popover.vue';
|
||||
import PopoverContent from '@/components/ui/popover/PopoverContent.vue';
|
||||
import PopoverTrigger from '@/components/ui/popover/PopoverTrigger.vue';
|
||||
import Tooltip from '@/components/ui/tooltip/Tooltip.vue';
|
||||
import TooltipContent from '@/components/ui/tooltip/TooltipContent.vue';
|
||||
import TooltipTrigger from '@/components/ui/tooltip/TooltipTrigger.vue';
|
||||
import { useThermalPrinter, getPaperSizeLabel } from '@/composables/useThermalPrinter';
|
||||
import type { PaperSize } from '@/lib/thermal-printer/types';
|
||||
import type { OrderListItem } from '@/types/order';
|
||||
@ -69,32 +63,17 @@ async function handlePrint(paperSize: PaperSize) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip>
|
||||
<Popover v-model:open="open">
|
||||
<TooltipTrigger as-child>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" :disabled="processing">
|
||||
<Printer class="size-4" />
|
||||
<span class="sr-only">Cetak struk</span>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
</TooltipTrigger>
|
||||
|
||||
<TooltipContent>
|
||||
Cetak struk
|
||||
</TooltipContent>
|
||||
|
||||
<PopoverContent align="end" class="w-40 space-y-2 p-3">
|
||||
<p class="text-sm font-medium">
|
||||
Ukuran kertas
|
||||
</p>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<Button v-for="paperSize in paperSizes" :key="paperSize" variant="outline" size="sm" class="h-8"
|
||||
:disabled="processing" @click="handlePrint(paperSize)">
|
||||
{{ paperSize }}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Tooltip>
|
||||
<RowPrintAction v-model:open="open" tooltip="Cetak struk" :disabled="processing">
|
||||
<template #popover-content>
|
||||
<p class="text-sm font-medium">
|
||||
Ukuran kertas
|
||||
</p>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<Button v-for="paperSize in paperSizes" :key="paperSize" variant="outline" size="sm" class="h-8"
|
||||
:disabled="processing" @click="handlePrint(paperSize)">
|
||||
{{ paperSize }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</RowPrintAction>
|
||||
</template>
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { Link, router } from '@inertiajs/vue3';
|
||||
import { Check, Eye, Pencil, Send, Trash2, X } from '@lucide/vue';
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import { Check, Send, X } from '@lucide/vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import OrderPrintButton from '../form/OrderPrintButton.vue';
|
||||
import { RowDeleteAction, RowDetailAction, RowEditAction, RowStatusAction } from '@/components/button';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import { OrderStatus } from '@/constants/order-status';
|
||||
import type { OrderListItem, OrderStatusAction } from '@/types/order';
|
||||
import { show, edit, destroy, transition_status } from '@/routes/admin/manage/orders';
|
||||
@ -28,11 +27,6 @@ const availableActions = computed(() => props.order.available_actions ?? []);
|
||||
const canEdit = computed(() => props.order.is_editable && can('orders.update'));
|
||||
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 {
|
||||
return can(action.permission);
|
||||
}
|
||||
@ -98,21 +92,9 @@ function actionIcon(status: string) {
|
||||
<OrderPrintButton :order="order" />
|
||||
|
||||
<template v-for="action in availableActions" :key="action.status">
|
||||
<Tooltip v-if="action.icon_only && canPerformAction(action)">
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="size-8"
|
||||
:class="action.destructive ? 'text-destructive hover:text-destructive' : ''"
|
||||
@click="openStatusConfirm(action)"
|
||||
>
|
||||
<component :is="actionIcon(action.status)" class="size-4" />
|
||||
<span class="sr-only">{{ action.label }}</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ action.label }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowStatusAction v-if="action.icon_only && canPerformAction(action)"
|
||||
:icon="actionIcon(action.status)" :label="action.label" :destructive="action.destructive"
|
||||
@click="openStatusConfirm(action)" />
|
||||
|
||||
<Button
|
||||
v-else-if="canPerformAction(action)"
|
||||
@ -126,44 +108,15 @@ function actionIcon(status: string) {
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="show.url(props.order.id)">
|
||||
<Eye class="size-4" />
|
||||
<span class="sr-only">Detail</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Detail</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowDetailAction :href="show.url(order.id)" tooltip="Detail" />
|
||||
|
||||
<Tooltip v-if="canEdit">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="edit.url(props.order.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="canEdit" :href="edit.url(order.id)" />
|
||||
|
||||
<Tooltip v-if="canDelete">
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true"
|
||||
>
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<template v-if="canDelete">
|
||||
<RowDeleteAction :action-url="destroy.url(order.id)" title="Hapus pesanan?"
|
||||
:description="`Pesanan ${order.order_number} akan dihapus.${order.is_editable ? ' Stok produk akan dikembalikan.' : ''}`"
|
||||
error-message="Gagal menghapus pesanan." />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
@ -176,16 +129,4 @@ function actionIcon(status: string) {
|
||||
:loading="statusProcessing"
|
||||
@confirm="transitionStatus"
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
v-if="canDelete"
|
||||
v-model:open="deleteConfirmOpen"
|
||||
title="Hapus pesanan?"
|
||||
:description="`Pesanan ${order.order_number} akan dihapus.${order.is_editable ? ' Stok produk akan dikembalikan.' : ''}`"
|
||||
confirm-label="Hapus"
|
||||
cancel-label="Batal"
|
||||
destructive
|
||||
:loading="deleteProcessing"
|
||||
@confirm="destroyOrder"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { router, useForm } from '@inertiajs/vue3';
|
||||
import { Check, X } from '@lucide/vue';
|
||||
import { X } from '@lucide/vue';
|
||||
import { ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { RowApproveAction, RowRejectAction } from '@/components/button';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
@ -17,11 +18,6 @@ import {
|
||||
FieldLabel,
|
||||
} from '@/components/ui/field';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { CuttingListItem } from '@/types/cutting';
|
||||
import { approve, reject } from '@/routes/admin/manage/owner_verifications';
|
||||
@ -69,36 +65,9 @@ function submitReject() {
|
||||
|
||||
<template>
|
||||
<div v-if="can('owner_verifications.verify')" class="flex items-center gap-1">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
class="text-green-600 hover:text-green-700"
|
||||
:disabled="approveForm.processing"
|
||||
@click="submitApprove"
|
||||
>
|
||||
<Check class="size-3.5" />
|
||||
<span class="sr-only">Setujui</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Setujui Verifikasi</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
class="text-red-600 hover:text-red-700"
|
||||
@click="rejectDialogOpen = true"
|
||||
>
|
||||
<X class="size-3.5" />
|
||||
<span class="sr-only">Tolak</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Tolak Verifikasi</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowApproveAction size="sm" tooltip="Setujui Verifikasi" :disabled="approveForm.processing"
|
||||
@click="submitApprove" />
|
||||
<RowRejectAction size="sm" tooltip="Tolak Verifikasi" @click="rejectDialogOpen = true" />
|
||||
</div>
|
||||
|
||||
<!-- Reject Dialog -->
|
||||
|
||||
@ -1,65 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { PurchaseListItem } from '@/types/purchase';
|
||||
import { edit, destroy } from '@/routes/admin/manage/purchases';
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
purchase: PurchaseListItem;
|
||||
}>();
|
||||
|
||||
const { can } = useCan();
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyPurchase } = useDestroy({
|
||||
url: destroy.url(props.purchase.id),
|
||||
errorMessage: 'Gagal menghapus belanja.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('purchases.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="edit.url(props.purchase.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('purchases.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true"
|
||||
>
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('purchases.update')" :href="edit.url(purchase.id)" />
|
||||
<RowDeleteAction v-if="can('purchases.delete')" :action-url="destroy.url(purchase.id)" title="Hapus belanja?"
|
||||
:description="`Belanja ${purchase.total_formatted} dari ${purchase.supplier_name} akan dihapus. Stok bahan baku akan dikurangi.`"
|
||||
error-message="Gagal menghapus belanja." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
v-if="can('purchases.delete')"
|
||||
v-model:open="deleteConfirmOpen"
|
||||
title="Hapus belanja?"
|
||||
:description="`Belanja ${purchase.total_formatted} dari ${purchase.supplier_name} akan dihapus. Stok bahan baku akan dikurangi.`"
|
||||
confirm-label="Hapus"
|
||||
cancel-label="Batal"
|
||||
destructive
|
||||
:loading="deleteProcessing"
|
||||
@confirm="destroyPurchase"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -3,6 +3,7 @@ import { router, useForm } from '@inertiajs/vue3';
|
||||
import { Check } from '@lucide/vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { RowApproveAction } from '@/components/button';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
@ -165,20 +166,8 @@ function submitVerify() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tooltip v-if="can('cuttings.verify')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
class="text-green-600 hover:text-green-700"
|
||||
@click="verifyDialogOpen = true"
|
||||
>
|
||||
<Check class="size-3.5" />
|
||||
<span class="sr-only">Verifikasi</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Verifikasi & Tambah Stok</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowApproveAction v-if="can('cuttings.verify')" size="sm" tooltip="Verifikasi & Tambah Stok"
|
||||
@click="verifyDialogOpen = true" />
|
||||
|
||||
<Dialog v-model:open="verifyDialogOpen">
|
||||
<DialogContent class="sm:max-w-lg">
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { CategoryListItem } from '@/types/category';
|
||||
import { destroy } from '@/routes/admin/master/categories';
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
category: CategoryListItem;
|
||||
}>();
|
||||
|
||||
@ -17,38 +13,13 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const { can } = useCan();
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyCategory } = useDestroy({
|
||||
url: destroy.url(props.category.id),
|
||||
errorMessage: 'Gagal menghapus kategori.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('categories.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="emit('edit', category)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('categories.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('categories.update')" @click="emit('edit', category)" />
|
||||
<RowDeleteAction v-if="can('categories.delete')" :action-url="destroy.url(category.id)" title="Hapus kategori?"
|
||||
:description="`Kategori ${category.name} akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.`"
|
||||
error-message="Gagal menghapus kategori." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('categories.delete')" v-model:open="deleteConfirmOpen" title="Hapus kategori?"
|
||||
:description="`Kategori ${category.name} akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroyCategory" />
|
||||
</template>
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { CustomerListItem } from '@/types/customer';
|
||||
import { destroy } from '@/routes/admin/master/customers';
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
customer: CustomerListItem;
|
||||
}>();
|
||||
|
||||
@ -17,38 +13,13 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const { can } = useCan();
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyCustomer } = useDestroy({
|
||||
url: destroy.url(props.customer.id),
|
||||
errorMessage: 'Gagal menghapus customer.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('customers.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="emit('edit', customer)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('customers.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('customers.update')" @click="emit('edit', customer)" />
|
||||
<RowDeleteAction v-if="can('customers.delete')" :action-url="destroy.url(customer.id)" title="Hapus customer?"
|
||||
:description="`Customer ${customer.name} akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.`"
|
||||
error-message="Gagal menghapus customer." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('customers.delete')" v-model:open="deleteConfirmOpen" title="Hapus customer?"
|
||||
:description="`Customer ${customer.name} akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroyCustomer" />
|
||||
</template>
|
||||
|
||||
@ -1,54 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { ProductListItem } from '@/types/product';
|
||||
import { edit, destroy } from '@/routes/admin/master/products';
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
product: ProductListItem;
|
||||
}>();
|
||||
|
||||
const { can } = useCan();
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyProduct } = useDestroy({
|
||||
url: destroy.url(props.product.id),
|
||||
preserveScroll: false,
|
||||
errorMessage: 'Gagal menghapus produk.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('products.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="edit.url(props.product.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('products.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('products.update')" :href="edit.url(product.id)" />
|
||||
<RowDeleteAction v-if="can('products.delete')" :action-url="destroy.url(product.id)" title="Hapus produk?"
|
||||
:description="`Produk ${product.name} akan dihapus beserta seluruh variannya. Tindakan ini tidak dapat dibatalkan.`"
|
||||
error-message="Gagal menghapus produk." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('products.delete')" v-model:open="deleteConfirmOpen" title="Hapus produk?"
|
||||
:description="`Produk ${product.name} akan dihapus beserta seluruh variannya. Tindakan ini tidak dapat dibatalkan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroyProduct" />
|
||||
</template>
|
||||
|
||||
@ -1,55 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { RawMaterialListItem } from '@/types/raw-material';
|
||||
import { edit, destroy } from '@/routes/admin/master/raw_materials';
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
material: RawMaterialListItem;
|
||||
}>();
|
||||
|
||||
const { can } = useCan();
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyRawMaterial } = useDestroy({
|
||||
url: destroy.url(props.material.id),
|
||||
preserveScroll: false,
|
||||
errorMessage: 'Gagal menghapus bahan baku.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('raw_materials.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="edit.url(props.material.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('raw_materials.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('raw_materials.update')" :href="edit.url(material.id)" />
|
||||
<RowDeleteAction v-if="can('raw_materials.delete')" :action-url="destroy.url(material.id)" title="Hapus bahan baku?"
|
||||
:description="`Bahan baku ${material.name} akan dihapus beserta seluruh variannya. Tindakan ini tidak dapat dibatalkan.`"
|
||||
error-message="Gagal menghapus bahan baku." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('raw_materials.delete')" v-model:open="deleteConfirmOpen" title="Hapus bahan baku?"
|
||||
:description="`Bahan baku ${material.name} akan dihapus beserta seluruh variannya. Tindakan ini tidak dapat dibatalkan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing"
|
||||
@confirm="destroyRawMaterial" />
|
||||
</template>
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { SupplierListItem } from '@/types/supplier';
|
||||
import { destroy } from '@/routes/admin/master/suppliers';
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
supplier: SupplierListItem;
|
||||
}>();
|
||||
|
||||
@ -17,38 +13,13 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const { can } = useCan();
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroySupplier } = useDestroy({
|
||||
url: destroy.url(props.supplier.id),
|
||||
errorMessage: 'Gagal menghapus supplier.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('suppliers.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" @click="emit('edit', supplier)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('suppliers.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Hapus</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('suppliers.update')" @click="emit('edit', supplier)" />
|
||||
<RowDeleteAction v-if="can('suppliers.delete')" :action-url="destroy.url(supplier.id)" title="Hapus supplier?"
|
||||
:description="`Supplier ${supplier.name} akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.`"
|
||||
error-message="Gagal menghapus supplier." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('suppliers.delete')" v-model:open="deleteConfirmOpen" title="Hapus supplier?"
|
||||
:description="`Supplier ${supplier.name} akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroySupplier" />
|
||||
</template>
|
||||
|
||||
@ -1,12 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import { computed } from 'vue';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { useDestroy } from '@/composables/useDestroy';
|
||||
import type { RoleListItem } from './columns';
|
||||
import { edit, destroy } from '@/routes/admin/system/roles';
|
||||
|
||||
@ -19,44 +14,13 @@ const { can } = useCan();
|
||||
const isSystemRole = computed(() => {
|
||||
return ['developer', 'owner', 'admin-toko', 'admin-bahan-baku', 'direktur', 'marketing', 'cashier', 'non-operator'].includes(props.role.name);
|
||||
});
|
||||
|
||||
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyRole } = useDestroy({
|
||||
url: destroy.url(props.role.id),
|
||||
errorMessage: 'Gagal menghapus role.',
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<Tooltip v-if="can('roles.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="edit.url(props.role.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Ubah</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip v-if="can('roles.delete')">
|
||||
<TooltipTrigger as-child>
|
||||
<span>
|
||||
<Button variant="ghost" size="icon" class="text-destructive hover:text-destructive size-8"
|
||||
@click="deleteConfirmOpen = true">
|
||||
<Trash2 class="size-4" />
|
||||
<span class="sr-only">Hapus</span>
|
||||
</Button>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
Hapus
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<RowEditAction v-if="can('roles.update')" :href="edit.url(role.id)" />
|
||||
<RowDeleteAction v-if="can('roles.delete') && !isSystemRole" :action-url="destroy.url(role.id)" title="Hapus role?"
|
||||
:description="`Role ${role.name} akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.`"
|
||||
error-message="Gagal menghapus role." />
|
||||
</div>
|
||||
|
||||
<ConfirmDialog v-if="can('roles.delete') && !isSystemRole" v-model:open="deleteConfirmOpen" title="Hapus role?"
|
||||
:description="`Role ${role.name} akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.`"
|
||||
confirm-label="Hapus" cancel-label="Batal" destructive :loading="deleteProcessing" @confirm="destroyRole" />
|
||||
</template>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user