Commit d2ba5fbc by Samuel Taniel Mulyadi

Fix Absen

1 parent cb4ae055
Showing with 101 additions and 85 deletions
<script setup lang="ts"> <script setup lang="ts">
import { useKeycloakStore } from "@/@core/stores/keycloakStore"; import { onMounted, ref, watchEffect } from 'vue'
import { onMounted, ref, watchEffect } from "vue"; import { useKeycloakStore } from '@/@core/stores/keycloakStore'
// Store Keycloak // Store Keycloak
const keycloakStore = useKeycloakStore(); const keycloakStore = useKeycloakStore()
// Data dan state // Data dan state
const items = ref<any[]>([]); const items = ref<any[]>([])
const loading = ref(false); const loading = ref(false)
const searchQuery = ref(""); const searchQuery = ref('')
// Fungsi ambil tanggal dari shift_start atau shift_end // Fungsi ambil tanggal dari shift_start atau shift_end
const getTanggal = (waktu: string) => (waktu ? waktu.split(" ")[0] : "-"); const getTanggal = (waktu: string) => (waktu ? waktu.split(' ')[0] : '-')
// Fungsi ambil jam dari start_time atau end_time, kasih "-" kalau kosong // Fungsi ambil jam dari start_time atau end_time, kasih "-" kalau kosong
const getJam = (waktu: string) => (waktu ? waktu.split(" ")[1].slice(0, 5) : "-"); const getJam = (waktu: string) => {
if (!waktu)
return '-'
return waktu.length >= 5 ? waktu.slice(0, 5) : waktu
}
// Fungsi ambil nama hari dari tanggal // Fungsi ambil nama hari dari tanggal
const getNamaHari = (tanggal: string) => { const getNamaHari = (tanggal: string) => {
if (!tanggal || tanggal === "-") return "-"; if (!tanggal || tanggal === '-')
const date = new Date(tanggal); return '-'
if (isNaN(date.getTime())) return "-"; const date = new Date(tanggal)
return new Intl.DateTimeFormat("id-ID", { weekday: "long" }).format(date); if (isNaN(date.getTime()))
}; return '-'
return new Intl.DateTimeFormat('id-ID', { weekday: 'long' }).format(date)
}
const getJadwalShift = (start: string, end: string) => { const getJadwalShift = (start: string, end: string) => {
const jamStart = start ? start.split(" ")[1].slice(0, 5) : "-"; const jamStart = start && start.length >= 5 ? start.slice(0, 5) : '-'
const jamEnd = end ? end.split(" ")[1].slice(0, 5) : "-"; const jamEnd = end && end.length >= 5 ? end.slice(0, 5) : '-'
return `${jamStart} - ${jamEnd}`;
}; return `${jamStart} - ${jamEnd}`
}
const getStatus = (start: string | undefined, end: string | undefined) => { const getStatus = (start: string | undefined, end: string | undefined) => {
if (!start && !end) return "Tidak Ada"; if (!start && !end)
if (!start || !end) return "Belum Hitung"; return 'Tidak Ada'
return "On Time"; if (!start || !end)
}; return 'Belum Hitung'
return 'On Time'
}
// Header tabel // Header tabel
const logHeaders = [ const logHeaders = [
{ title: "TANGGAL", key: "tanggal" }, { title: 'TANGGAL', key: 'tanggal' },
{ title: "NAMA HARI", key: "namaHari" }, { title: 'NAMA HARI', key: 'namaHari' },
{ title: "SHIFT", key: "shift" }, { title: 'SHIFT', key: 'shift' },
{ title: "JADWAL SHIFT", key: "jadwalShift" }, { title: 'JADWAL SHIFT', key: 'jadwalShift' },
{ title: "MULAI AKTUAL", key: "start_time" }, { title: 'MULAI AKTUAL', key: 'start_time' },
{ title: "SELESAI AKTUAL", key: "end_time" }, { title: 'SELESAI AKTUAL', key: 'end_time' },
{ title: "STATUS", key: "status" }, { title: 'STATUS', key: 'status' },
]; ]
// Fungsi ambil data dari API // Fungsi ambil data dari API
async function getData() { async function getData() {
loading.value = true; loading.value = true
items.value = []; items.value = []
try { try {
const apiEndpoint = "https://api.ui.ac.id/my/hr/attendance"; const apiEndpoint = 'https://api.ui.ac.id/my/hr/attendance'
const response = await fetch(apiEndpoint, { const response = await fetch(apiEndpoint, {
headers: { headers: {
Authorization: `Bearer ${keycloakStore.accessToken}`, Authorization: `Bearer ${keycloakStore.accessToken}`,
}, },
}); })
if (!response.ok) throw new Error("Gagal mengambil data"); if (!response.ok)
const dataku = await response.json(); throw new Error('Gagal mengambil data')
const dataku = await response.json()
// Tambahkan properti tanggal, namaHari, mulai aktual, dan selesai aktual ke setiap item // Tambahkan properti tanggal, namaHari, mulai aktual, dan selesai aktual ke setiap item
items.value = dataku.map((item: any) => { items.value = dataku.map((item: any) => {
const tanggal = getTanggal(item.shift_start) || getTanggal(item.shift_end); const tanggal = getTanggal(item.shift_start) || getTanggal(item.shift_end)
return { return {
...item, ...item,
tanggal: tanggal, tanggal,
namaHari: getNamaHari(tanggal), namaHari: getNamaHari(tanggal),
jadwalShift: getJadwalShift(item.shift_start, item.shift_end), jadwalShift: getJadwalShift(item.shift_start, item.shift_end),
start_time: getJam(item.start_time), start_time: getJam(item.start_time),
end_time: getJam(item.end_time), end_time: getJam(item.end_time),
status: getStatus(item.start_time, item.end_time), status: getStatus(item.start_time, item.end_time),
}; }
}); })
} catch (err) { }
console.error("Gagal mengambil data:", err); catch (err) {
} finally { console.error('Gagal mengambil data:', err)
loading.value = false; }
finally {
loading.value = false
} }
} }
// Fetch data saat mounted // Fetch data saat mounted
onMounted(() => { onMounted(() => {
keycloakStore.refresh(); keycloakStore.refresh()
getData(); getData()
}); })
// Auto refresh data saat token berubah // Auto refresh data saat token berubah
watchEffect(async () => { watchEffect(async () => {
if (!keycloakStore.accessToken) return; if (!keycloakStore.accessToken)
await getData(); return
}); await getData()
})
const filteredItems = computed(() => { const filteredItems = computed(() => {
if (!searchQuery.value) return items.value; if (!searchQuery.value)
return items.value
const query = searchQuery.value.toLowerCase(); const query = searchQuery.value.toLowerCase()
return items.value.filter((item) => return items.value.filter(item =>
logHeaders.some( logHeaders.some(
(header) => item[header.key] && String(item[header.key]).toLowerCase().includes(query) header => item[header.key] && String(item[header.key]).toLowerCase().includes(query),
) ),
); )
}); })
</script> </script>
<template> <template>
<VCard title="Log Absen" class="recentnamaHariCard"> <VCard
title="Log Absen"
class="recentnamaHariCard"
>
<div class="search-container mb-4 pl-2 pr-2"> <div class="search-container mb-4 pl-2 pr-2">
<VTextField <VTextField
v-model="searchQuery" v-model="searchQuery"
...@@ -133,32 +154,27 @@ const filteredItems = computed(() => { ...@@ -133,32 +154,27 @@ const filteredItems = computed(() => {
:sort-by="['tanggal']" :sort-by="['tanggal']"
:sort-asc="[true]" :sort-asc="[true]"
> >
<template #item.namaHari="{ item }">
<template #item.namaHari="{ item }"> <VChip
<VChip :color="item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'"
:color="item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'" :class="`text-${item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'}`"
:class="`text-${item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'}`" size="small"
size="small" class="font-weight-medium"
class="font-weight-medium" >
> {{ item.namaHari }}
{{ item.namaHari }} </VChip>
</VChip> </template>
</template>
<template #item.status="{ item }">
<template #item.status="{ item }"> <VChip
<VChip :color="item.status === 'Tidak Ada' ? 'error' : 'primary'"
:color="item.status === 'Tidak Ada' ? 'error' : 'primary'" :class="`text-${item.status === 'Tidak Ada' ? 'error' : 'primary'}`"
:class="`text-${item.status === 'Tidak Ada' ? 'error' : 'primary'}`" size="small"
size="small" class="font-weight-medium"
class="font-weight-medium" >
> {{ item.status }}
{{ item.status }} </VChip>
</VChip> </template>
</template> </VDataTable>
</VDataTable>
</VCard> </VCard>
</template> </template>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!