107 lines
4.1 KiB
Vue
107 lines
4.1 KiB
Vue
<script setup lang="ts">
|
|
import { Trash2 } from '@lucide/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 { useDestroy } from '@/composables/useDestroy';
|
|
import { destroy } from '@/routes/admin/hr/attendances';
|
|
import type { AttendanceListItem } from '@/types/attendance';
|
|
import AttendancePhotoCell from './attendance-photo-cell.vue';
|
|
import AttendanceMap from './AttendanceMap.vue';
|
|
|
|
const open = defineModel<boolean>('open', { required: true });
|
|
|
|
const props = defineProps<{
|
|
attendance: AttendanceListItem | null;
|
|
}>();
|
|
|
|
const { can } = useCan();
|
|
|
|
const { open: deleteConfirmOpen, processing: deleteProcessing, destroy: destroyAttendance } = useDestroy({
|
|
url: destroy.url(props.attendance?.id ?? 0),
|
|
errorMessage: 'Gagal menghapus data presensi.',
|
|
onSuccess: () => {
|
|
open.value = false;
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<Dialog v-model:open="open">
|
|
<DialogContent class="sm:max-w-xl max-h-[90vh] overflow-y-auto scrollbar-thin">
|
|
<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 pb-2">
|
|
<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>
|
|
|
|
<AttendanceMap :check-in-lat="attendance.check_in_latitude"
|
|
:check-in-lng="attendance.check_in_longitude" :check-out-lat="attendance.check_out_latitude"
|
|
:check-out-lng="attendance.check_out_longitude" />
|
|
|
|
<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" />
|
|
</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>
|