store/resources/js/components/admin/hr/attendances/AttendanceMap.vue

96 lines
3.3 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue';
const props = defineProps<{
checkInLat: number | null;
checkInLng: number | null;
checkOutLat: number | null;
checkOutLng: number | null;
checkInLocationTag: string | null;
checkOutLocationTag: string | null;
checkInAtFormatted: string;
checkOutAtFormatted: string | null;
attendanceDateFormatted: string;
employeeName: string | null;
}>();
const hasCoordinates = computed(() => props.checkInLat != null && props.checkInLng != null);
const checkInSrc = computed(() => {
if (props.checkInLat == null || props.checkInLng == null) return '';
return `https://www.google.com/maps?q=${props.checkInLat},${props.checkInLng}&z=18&t=k&output=embed`;
});
const checkOutSrc = computed(() => {
if (props.checkOutLat == null || props.checkOutLng == null) return '';
return `https://www.google.com/maps?q=${props.checkOutLat},${props.checkOutLng}&z=18&t=k&output=embed`;
});
function escapeHtml(value: string): string {
return value
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&#39;');
}
function buildLabel(
title: string,
color: string,
time: string,
locationTag: string | null,
lat: number | null,
lng: number | null,
): string {
const lines: string[] = [];
lines.push(`<strong style="color:${color}">${title}</strong>`);
if (props.employeeName) lines.push(`<span>Karyawan: <b>${escapeHtml(props.employeeName)}</b></span>`);
lines.push(`<span>Tanggal: ${escapeHtml(props.attendanceDateFormatted)}</span>`);
lines.push(`<span>Jam: <b>${escapeHtml(time)}</b></span>`);
lines.push(`<span>Lokasi: ${escapeHtml(locationTag ?? '-')}</span>`);
lines.push(`<span style="font-family:monospace;font-size:11px">Koordinat: ${lat}, ${lng}</span>`);
return lines.join('<br>');
}
</script>
<template>
<div v-if="hasCoordinates" class="space-y-3">
<p class="text-muted-foreground text-sm">
Lokasi Presensi
</p>
<!-- Check-in map -->
<div class="space-y-1.5">
<div
class="text-xs font-medium"
v-html="buildLabel('Masuk', '#16a34a', checkInAtFormatted, checkInLocationTag, checkInLat, checkInLng)"
/>
<iframe
:src="checkInSrc"
class="h-56 w-full overflow-hidden rounded-lg"
style="border: 0"
allowfullscreen
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
/>
</div>
<!-- Check-out map -->
<div v-if="checkOutLat != null && checkOutLng != null" class="space-y-1.5">
<div
class="text-xs font-medium"
v-html="buildLabel('Pulang', '#dc2626', checkOutAtFormatted ?? '-', checkOutLocationTag, checkOutLat, checkOutLng)"
/>
<iframe
:src="checkOutSrc"
class="h-56 w-full overflow-hidden rounded-lg"
style="border: 0"
allowfullscreen
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
/>
</div>
</div>
</template>