Commit d2ba5fbc by Samuel Taniel Mulyadi

Fix Absen

1 parent cb4ae055
Showing with 82 additions and 66 deletions
<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
const keycloakStore = useKeycloakStore();
const keycloakStore = useKeycloakStore()
// Data dan state
const items = ref<any[]>([]);
const loading = ref(false);
const searchQuery = ref("");
const items = ref<any[]>([])
const loading = ref(false)
const searchQuery = ref('')
// 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
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
const getNamaHari = (tanggal: string) => {
if (!tanggal || tanggal === "-") return "-";
const date = new Date(tanggal);
if (isNaN(date.getTime())) return "-";
return new Intl.DateTimeFormat("id-ID", { weekday: "long" }).format(date);
};
if (!tanggal || tanggal === '-')
return '-'
const date = new Date(tanggal)
if (isNaN(date.getTime()))
return '-'
return new Intl.DateTimeFormat('id-ID', { weekday: 'long' }).format(date)
}
const getJadwalShift = (start: string, end: string) => {
const jamStart = start ? start.split(" ")[1].slice(0, 5) : "-";
const jamEnd = end ? end.split(" ")[1].slice(0, 5) : "-";
return `${jamStart} - ${jamEnd}`;
};
const jamStart = start && start.length >= 5 ? start.slice(0, 5) : '-'
const jamEnd = end && end.length >= 5 ? end.slice(0, 5) : '-'
return `${jamStart} - ${jamEnd}`
}
const getStatus = (start: string | undefined, end: string | undefined) => {
if (!start && !end) return "Tidak Ada";
if (!start || !end) return "Belum Hitung";
return "On Time";
};
if (!start && !end)
return 'Tidak Ada'
if (!start || !end)
return 'Belum Hitung'
return 'On Time'
}
// Header tabel
const logHeaders = [
{ title: "TANGGAL", key: "tanggal" },
{ title: "NAMA HARI", key: "namaHari" },
{ title: "SHIFT", key: "shift" },
{ title: "JADWAL SHIFT", key: "jadwalShift" },
{ title: "MULAI AKTUAL", key: "start_time" },
{ title: "SELESAI AKTUAL", key: "end_time" },
{ title: "STATUS", key: "status" },
];
{ title: 'TANGGAL', key: 'tanggal' },
{ title: 'NAMA HARI', key: 'namaHari' },
{ title: 'SHIFT', key: 'shift' },
{ title: 'JADWAL SHIFT', key: 'jadwalShift' },
{ title: 'MULAI AKTUAL', key: 'start_time' },
{ title: 'SELESAI AKTUAL', key: 'end_time' },
{ title: 'STATUS', key: 'status' },
]
// Fungsi ambil data dari API
async function getData() {
loading.value = true;
items.value = [];
loading.value = true
items.value = []
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, {
headers: {
Authorization: `Bearer ${keycloakStore.accessToken}`,
},
});
})
if (!response.ok) throw new Error("Gagal mengambil data");
const dataku = await response.json();
if (!response.ok)
throw new Error('Gagal mengambil data')
const dataku = await response.json()
// Tambahkan properti tanggal, namaHari, mulai aktual, dan selesai aktual ke setiap item
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 {
...item,
tanggal: tanggal,
tanggal,
namaHari: getNamaHari(tanggal),
jadwalShift: getJadwalShift(item.shift_start, item.shift_end),
start_time: getJam(item.start_time),
end_time: getJam(item.end_time),
status: getStatus(item.start_time, item.end_time),
};
});
} catch (err) {
console.error("Gagal mengambil data:", err);
} finally {
loading.value = false;
}
})
}
catch (err) {
console.error('Gagal mengambil data:', err)
}
finally {
loading.value = false
}
}
// Fetch data saat mounted
onMounted(() => {
keycloakStore.refresh();
getData();
});
keycloakStore.refresh()
getData()
})
// Auto refresh data saat token berubah
watchEffect(async () => {
if (!keycloakStore.accessToken) return;
await getData();
});
if (!keycloakStore.accessToken)
return
await getData()
})
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(
(header) => item[header.key] && String(item[header.key]).toLowerCase().includes(query)
header => item[header.key] && String(item[header.key]).toLowerCase().includes(query),
),
)
);
});
})
</script>
<template>
<VCard title="Log Absen" class="recentnamaHariCard">
<VCard
title="Log Absen"
class="recentnamaHariCard"
>
<div class="search-container mb-4 pl-2 pr-2">
<VTextField
v-model="searchQuery"
......@@ -133,7 +154,6 @@ const filteredItems = computed(() => {
:sort-by="['tanggal']"
:sort-asc="[true]"
>
<template #item.namaHari="{ item }">
<VChip
:color="item.namaHari === 'Sabtu' || item.namaHari === 'Minggu' ? 'error' : 'default'"
......@@ -143,9 +163,9 @@ const filteredItems = computed(() => {
>
{{ item.namaHari }}
</VChip>
</template>
</template>
<template #item.status="{ item }">
<template #item.status="{ item }">
<VChip
:color="item.status === 'Tidak Ada' ? 'error' : 'primary'"
:class="`text-${item.status === 'Tidak Ada' ? 'error' : 'primary'}`"
......@@ -154,11 +174,7 @@ const filteredItems = computed(() => {
>
{{ item.status }}
</VChip>
</template>
</VDataTable>
</template>
</VDataTable>
</VCard>
</template>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!