MIF_E31230910_MP-HRIS-WEB/resources/views/hari_libur/index.blade.php

251 lines
12 KiB
PHP

@extends('layouts.app')
@section('title', 'Data Hari Libur')
@section('style')
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.8/index.global.min.js'></script>
<style>
.fc-toolbar-title { font-size: 1.15rem !important; font-weight: 700; color: #1e293b; }
.fc-col-header-cell { background-color: #f8fafc; padding: 8px 0; border-color: #e2e8f0; }
.fc-daygrid-day-number { color: #64748b; font-weight: 500; font-size: 0.85rem; }
.fc-day-today { background-color: #f0f9ff !important; }
.fc-event { border: none; padding: 2px; }
</style>
@endsection
@section('content')
<div class="space-y-6">
<x-page-header title="Data Hari Libur" subtitle="Kelola tanggal-tanggal libur nasional atau perusahaan.">
<div class="flex gap-2">
<form method="GET" action="{{ route('hari-libur.index') }}" class="flex items-center gap-2">
<x-filter-select name="id_kantor" onchange="this.form.submit()" class="py-1.5 text-xs w-48">
<option value="">Semua Kantor (Global)</option>
@foreach($kantors as $k)
<option value="{{ $k->id_kantor }}" request('id_kantor') == $k->id_kantor ? 'selected' : ''>{{ $k->nama_kantor }}</option>
@endforeach
</x-filter-select>
</form>
<form action="{{ route('hari-libur.sync') }}" method="POST">
@csrf
<x-button type="submit" variant="secondary" class="flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>
Sinkronisasi ({{ date('Y') }})
</x-button>
</form>
<x-button x-data @click="$dispatch('open-modal', 'create-harilibur')" class="flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
</svg>
Tambah Hari Libur
</x-button>
</div>
</x-page-header>
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
<h3 class="text-sm font-bold text-slate-800 mb-4 flex items-center gap-2">
<svg class="w-5 h-5 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
Kalender Libur Nasional & Perusahaan
</h3>
<div id="calendar" class="min-h-[450px]"></div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<x-table>
<x-slot:header>
<th class="px-6 py-5 text-xs font-bold text-slate-500 uppercase tracking-wider text-left w-10">No</th>
<th class="px-6 py-5 text-xs font-bold text-slate-500 uppercase tracking-wider text-left">Tanggal</th>
<th class="px-6 py-5 text-xs font-bold text-slate-500 uppercase tracking-wider text-left">Kantor</th>
<th class="px-6 py-5 text-xs font-bold text-slate-500 uppercase tracking-wider text-left">Keterangan</th>
<th class="px-6 py-5 text-xs font-bold text-slate-500 uppercase tracking-wider text-right">Aksi</th>
</x-slot:header>
@forelse($hariLiburs as $key => $hl)
<tr class="hover:bg-slate-50 transition border-b border-slate-50 last:border-b-0">
<td class="px-6 py-4 text-slate-500">
{{ $hariLiburs->firstItem() + $key }}
</td>
<td class="px-6 py-4 font-medium text-slate-800">
{{ \Carbon\Carbon::parse($hl->tanggal)->translatedFormat('d F Y') }}
</td>
<td class="px-6 py-4 text-sm text-slate-600">
{!! $hl->id_kantor ? '<span class="inline-flex px-2 py-1 rounded-md text-xs font-semibold bg-blue-50 text-blue-700">Khusus: ' . $hl->kantor->nama_kantor . '</span>' : '<span class="inline-flex px-2 py-1 rounded-md text-xs font-semibold bg-slate-100 text-slate-600">Global</span>' !!}
</td>
<td class="px-6 py-4 font-medium text-slate-800">
{{ $hl->keterangan }}
</td>
<td class="px-6 py-4 text-right">
<div class="flex items-center justify-end gap-2">
<x-button-edit onclick="openEditModal(this)" data-id="{{ $hl->id }}"
data-tanggal="{{ $hl->tanggal }}" data-keterangan="{{ $hl->keterangan }}" data-kantor="{{ $hl->id_kantor }}" />
<form id="delete-form-{{ $hl->id }}" action="{{ route('hari-libur.destroy', $hl->id) }}"
method="POST" style="display: none;">
@csrf
@method('DELETE')
</form>
<x-delete-button :id="$hl->id" />
</div>
</td>
</tr>
@empty
<x-empty-state colspan="4" message="Belum ada data hari libur" hint="Silakan tambahkan data baru." />
@endforelse
</x-table>
<x-pagination :paginator="$hariLiburs" />
</div>
</div>
<x-modal name="create-harilibur" title="Tambah Hari Libur">
<form action="{{ route('hari-libur.store') }}" method="POST" class="space-y-4">
@csrf
<div>
<x-input type="date" label="Tanggal Libur" name="tanggal" required />
</div>
<div>
<x-select label="Kantor (Opsional)" name="id_kantor">
<option value="">Semua Kantor (Global)</option>
@foreach($kantors as $k)
<option value="{{ $k->id_kantor }}">{{ $k->nama_kantor }}</option>
@endforeach
</x-select>
</div>
<div>
<x-input label="Keterangan" name="keterangan" placeholder="Contoh: Idul Fitri" required />
</div>
<div class="flex justify-end gap-3 pt-4">
<x-button type="button" x-data @click="$dispatch('close-modal', 'create-harilibur')" variant="secondary">Batal</x-button>
<x-button type="submit">Simpan</x-button>
</div>
</form>
</x-modal>
<x-modal name="edit-harilibur" title="Edit Hari Libur">
<form id="form-edit" action="#" method="POST" class="space-y-4">
@csrf
@method('PUT')
<input type="hidden" id="edit-id" name="id">
<div>
<x-input type="date" id="edit-tanggal" label="Tanggal Libur" name="tanggal" required />
</div>
<div>
<x-select id="edit-kantor" label="Kantor (Opsional)" name="id_kantor">
<option value="">Semua Kantor (Global)</option>
@foreach($kantors as $k)
<option value="{{ $k->id_kantor }}">{{ $k->nama_kantor }}</option>
@endforeach
</x-select>
</div>
<div>
<x-input id="edit-keterangan" label="Keterangan" name="keterangan" required />
</div>
<div class="flex justify-end gap-3 pt-4">
<x-button type="button" x-data @click="$dispatch('close-modal', 'edit-harilibur')" variant="secondary">Batal</x-button>
<x-button type="submit" variant="warning">Update</x-button>
</div>
</form>
</x-modal>
<script>
window.openEditModal = function (btn) {
const id = btn.dataset.id;
const tanggal = btn.dataset.tanggal;
const keterangan = btn.dataset.keterangan;
const kantorId = btn.dataset.kantor;
document.getElementById('edit-id').value = id;
document.getElementById('edit-tanggal').value = tanggal;
document.getElementById('edit-keterangan').value = keterangan;
document.getElementById('edit-kantor').value = kantorId || '';
let form = document.getElementById('form-edit');
let baseUrl = "{{ route('hari-libur.update', ':id') }}";
form.action = baseUrl.replace(':id', id);
window.dispatchEvent(new CustomEvent('open-modal', { detail: 'edit-harilibur' }));
}
window.holidayCalendar = window.holidayCalendar || null;
function initHolidayCalendar() {
var calendarEl = document.getElementById('calendar');
if (!calendarEl) return;
if (window.holidayCalendar) {
window.holidayCalendar.destroy();
window.holidayCalendar = null;
}
const rawData = @json($hariLiburs->items() ?? $hariLiburs);
const calendarEvents = rawData.map(function(hl) {
return {
title: hl.keterangan,
start: hl.tanggal,
allDay: true,
color: '#ef4444',
display: 'block'
};
});
window.holidayCalendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
locale: 'id',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth'
},
events: calendarEvents,
height: 'auto',
eventContent: function(arg) {
return {
html: `<div style="background:#fef2f2; color:#dc2626; padding: 2px 4px; border-radius: 4px; border-left: 3px solid #ef4444; font-weight:700; font-size: 10px; white-space: normal; line-height: 1.2;">
${arg.event.title}
</div>`
};
}
});
window.holidayCalendar.render();
}
if (!window.__holidayEventAttached) {
window.__holidayEventAttached = true;
document.addEventListener('turbo:load', function () {
if (document.getElementById('calendar') && typeof initHolidayCalendar === 'function') {
initHolidayCalendar();
}
});
document.addEventListener('turbo:before-cache', function () {
if (window.holidayCalendar) {
window.holidayCalendar.destroy();
window.holidayCalendar = null;
}
});
}
if (document.readyState === 'complete' || document.readyState === 'interactive') {
if (document.getElementById('calendar') && !window.holidayCalendar) {
setTimeout(initHolidayCalendar, 50);
}
} else {
document.addEventListener('DOMContentLoaded', function () {
if (document.getElementById('calendar') && !window.holidayCalendar) {
setTimeout(initHolidayCalendar, 50);
}
});
}
</script>
@endsection