134 lines
4.4 KiB
Vue
134 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
import { router } from '@inertiajs/vue3';
|
|
import { Trash2 } from '@lucide/vue';
|
|
import { ref } from 'vue';
|
|
import { toast } from 'vue-sonner';
|
|
import AttendancePhotoCell from '@/components/admin/hr/attendances/attendance-photo-cell.vue';
|
|
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog';
|
|
import { useCan } from '@/composables/useCan';
|
|
import type { AttendanceListItem } from '@/types/attendance';
|
|
|
|
const open = defineModel<boolean>('open', { required: true });
|
|
|
|
const props = defineProps<{
|
|
attendance: AttendanceListItem | null;
|
|
}>();
|
|
|
|
const { can } = useCan();
|
|
|
|
const deleteConfirmOpen = ref(false);
|
|
const deleteProcessing = ref(false);
|
|
|
|
function destroyAttendance() {
|
|
if (!props.attendance) {
|
|
return;
|
|
}
|
|
|
|
deleteProcessing.value = true;
|
|
|
|
router.delete(`/admin/hr/attendances/${props.attendance.id}`, {
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
deleteConfirmOpen.value = false;
|
|
open.value = false;
|
|
},
|
|
onError: () => {
|
|
toast.error('Gagal menghapus data presensi.');
|
|
},
|
|
onFinish: () => {
|
|
deleteProcessing.value = false;
|
|
},
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Dialog v-model:open="open">
|
|
<DialogContent class="sm:max-w-lg">
|
|
<DialogHeader>
|
|
<DialogTitle>Detail Presensi</DialogTitle>
|
|
<DialogDescription v-if="attendance">
|
|
{{ attendance.attendance_date_formatted }}
|
|
<template v-if="attendance.employee_name">
|
|
— {{ attendance.employee_name }}
|
|
</template>
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div v-if="attendance" class="space-y-4">
|
|
<dl class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
|
<div>
|
|
<dt class="text-muted-foreground">
|
|
Masuk
|
|
</dt>
|
|
<dd class="font-medium">
|
|
{{ attendance.check_in_at_formatted }}
|
|
</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-muted-foreground">
|
|
Pulang
|
|
</dt>
|
|
<dd class="font-medium">
|
|
{{ attendance.check_out_at_formatted ?? '-' }}
|
|
</dd>
|
|
</div>
|
|
|
|
<div class="col-span-2">
|
|
<dt class="text-muted-foreground">
|
|
Durasi
|
|
</dt>
|
|
<dd class="font-medium">
|
|
{{ attendance.work_duration_formatted ?? '-' }}
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
|
|
<div>
|
|
<p class="text-muted-foreground mb-2 text-sm">
|
|
Foto
|
|
</p>
|
|
<AttendancePhotoCell
|
|
:check-in-photo-url="attendance.check_in_photo_url"
|
|
:check-out-photo-url="attendance.check_out_photo_url"
|
|
:check-in-location-tag="attendance.check_in_location_tag"
|
|
:check-out-location-tag="attendance.check_out_location_tag"
|
|
/>
|
|
</div>
|
|
|
|
<div v-if="can('attendances.delete')" class="flex justify-end border-t pt-4">
|
|
<Button
|
|
variant="destructive"
|
|
size="sm"
|
|
@click="deleteConfirmOpen = true"
|
|
>
|
|
<Trash2 class="size-4" />
|
|
Hapus
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
|
|
<ConfirmDialog
|
|
v-if="can('attendances.delete') && attendance"
|
|
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>
|