store/resources/js/pages/admin/hr/attendances/Index.vue

155 lines
5.3 KiB
Vue

<script setup lang="ts">
import { Head } from '@inertiajs/vue3';
import { Clock, LogIn, LogOut } from '@lucide/vue';
import { computed, ref } from 'vue';
import AttendanceCalendar from '@/components/admin/hr/attendances/AttendanceCalendar.vue';
import AttendanceWebcamModal from '@/components/admin/hr/attendances/AttendanceWebcamModal.vue';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import AdminLayout from '@/layouts/AdminLayout.vue';
import type { AttendanceListItem, CalendarRange, TodayAttendance } from '@/types/attendance';
const props = defineProps<{
attendances: AttendanceListItem[];
todayAttendance: TodayAttendance;
isOnLeave: boolean;
canCheckIn: boolean;
canManageAll: boolean;
calendarRange: CalendarRange;
}>();
const webcamModalOpen = ref(false);
const webcamMode = ref<'check-in' | 'check-out'>('check-in');
const canCheckInToday = computed(() => props.canCheckIn && props.todayAttendance === null && !props.isOnLeave);
const canCheckOutToday = computed(() => (
props.canCheckIn
&& !props.isOnLeave
&& props.todayAttendance !== null
&& props.todayAttendance.check_out_at === null
));
const todayStatusLabel = computed(() => {
if (props.isOnLeave) {
return 'Sedang cuti';
}
if (!props.todayAttendance) {
return 'Belum presensi';
}
if (props.todayAttendance.check_out_at) {
return 'Selesai';
}
return 'Sudah masuk';
});
const todayStatusVariant = computed(() => {
if (props.isOnLeave) {
return 'secondary' as const;
}
if (!props.todayAttendance) {
return 'secondary' as const;
}
if (props.todayAttendance.check_out_at) {
return 'default' as const;
}
return 'outline' as const;
});
function openCheckInModal() {
webcamMode.value = 'check-in';
webcamModalOpen.value = true;
}
function openCheckOutModal() {
webcamMode.value = 'check-out';
webcamModalOpen.value = true;
}
</script>
<template>
<Head title="Presensi" />
<AdminLayout>
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div class="space-y-1">
<h2 class="text-2xl font-bold tracking-tight">
Presensi
</h2>
</div>
</div>
<Card v-if="canCheckIn">
<CardHeader>
<CardTitle class="flex items-center gap-2">
<Clock class="size-5" />
Presensi Hari Ini
</CardTitle>
<CardDescription>
Gunakan kamera perangkat untuk presensi masuk dan pulang.
</CardDescription>
</CardHeader>
<CardContent class="space-y-4">
<div class="flex flex-wrap items-center gap-3">
<Badge :variant="todayStatusVariant">
{{ todayStatusLabel }}
</Badge>
<span v-if="isOnLeave" class="text-muted-foreground text-sm">
Anda sedang dalam masa cuti. Presensi tidak diperlukan.
</span>
<span v-if="todayAttendance?.check_in_at_formatted" class="text-muted-foreground text-sm">
Masuk: {{ todayAttendance.check_in_at_formatted }}
</span>
<span v-if="todayAttendance?.check_out_at_formatted" class="text-muted-foreground text-sm">
Pulang: {{ todayAttendance.check_out_at_formatted }}
</span>
<span v-if="todayAttendance?.work_duration_formatted" class="text-muted-foreground text-sm">
Durasi: {{ todayAttendance.work_duration_formatted }}
</span>
</div>
<div class="flex flex-wrap gap-2">
<Button :disabled="!canCheckInToday" @click="openCheckInModal">
<LogIn class="size-4" />
Presensi Masuk
</Button>
<Button variant="outline" :disabled="!canCheckOutToday" @click="openCheckOutModal">
<LogOut class="size-4" />
Presensi Pulang
</Button>
</div>
</CardContent>
</Card>
<Card class="min-w-0 overflow-hidden">
<CardHeader class="border-b">
<CardTitle>Riwayat Presensi</CardTitle>
<CardDescription v-if="canManageAll">
Kalender presensi seluruh pegawai. Klik entri untuk melihat detail.
</CardDescription>
<CardDescription v-else>
Kalender riwayat presensi Anda. Klik entri untuk melihat detail.
</CardDescription>
</CardHeader>
<CardContent class="min-w-0">
<AttendanceCalendar :attendances="attendances" :calendar-range="calendarRange"
:can-manage-all="canManageAll" />
</CardContent>
</Card>
<AttendanceWebcamModal v-if="canCheckIn" v-model:open="webcamModalOpen" :mode="webcamMode" />
</AdminLayout>
</template>