SIPDAM/samooapk/resources/views/Admin/KelolaPekerjaan/Penugasan.blade.php

809 lines
46 KiB
PHP

<x-app-layout>
@push('styles')
<link rel="stylesheet" href="{{ asset('css/tugas.css') }}">
@endpush
<div class="pug-wrap">
<div class="pug-inner">
{{-- ── PAGE HEADER ── --}}
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:24px;">
<div style="display:flex; align-items:center; gap:12px;">
<div class="pug-icon-wrap">
<i class="fas fa-tasks"></i>
</div>
<div>
<div class="pug-page-title">Data Penugasan</div>
<div class="pug-page-sub">Manajemen penugasan teknisi lapangan</div>
</div>
</div>
<button onclick="openCreateModal()" class="pug-btn-primary">
<i class="fas fa-plus"></i> Tambah Penugasan
</button>
</div>
<div class="pug-wrap">
<div class="pug-inner">
@if(session('success'))
<div class="pug-alert pug-alert-ok" role="alert">
<i class="fas fa-check-circle"></i>
<span>{{ session('success') }}</span>
</div>
@endif
@if(session('error'))
<div class="pug-alert pug-alert-err" role="alert">
<i class="fas fa-exclamation-circle"></i>
<span>{{ session('error') }}</span>
</div>
@endif
{{-- ── ABANDONED TASKS ALERT ── --}}
@if(isset($abandonedTasks) && $abandonedTasks->count() > 0)
<div class="alert alert-danger" style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 16px 20px; margin-bottom: 24px; display: flex; align-items: flex-start; gap: 15px;">
<div style="color: #ef4444; font-size: 24px; margin-top: 2px;">
<i class="fas fa-exclamation-triangle"></i>
</div>
<div style="flex: 1;">
<h4 style="color: #991b1b; font-size: 15px; font-weight: 700; margin: 0 0 5px 0;">PERHATIAN: Ada Personel Tim yang Sakit/Izin Hari Ini!</h4>
<p style="color: #7f1d1d; font-size: 13px; margin: 0 0 10px 0;">
Terdapat <strong>{{ $abandonedTasks->count() }} Penugasan</strong> (Belum Mulai / Dalam Proses) yang anggotanya hari ini berstatus <strong>Sakit / Izin</strong>. Segera cek dan sesuaikan formasi tim berikut:
</p>
<div style="display: flex; flex-wrap: wrap; gap: 10px;">
@foreach($abandonedTasks as $task)
<div style="background: #fff; border: 1px solid #fca5a5; padding: 8px 12px; border-radius: 8px; font-size: 12px; display: flex; flex-direction: column; gap: 4px;">
<span style="font-weight: 700; color: #991b1b;"><i class="fas fa-clipboard-list"></i> {{ \Illuminate\Support\Str::limit($task->jenis_pekerjaan, 20) }}</span>
<span style="color: #64748b;"><i class="fas fa-map-marker-alt"></i> {{ \Illuminate\Support\Str::limit($task->alamat_lokasi, 25) }}</span>
<button onclick="editPenugasan({{ $task->id_penugasan }})" style="margin-top: 4px; background: #ef4444; color: white; border: none; padding: 4px 8px; border-radius: 4px; cursor: pointer; font-size: 11px; font-weight: 600;">
<i class="fas fa-exchange-alt"></i> Sesuaikan Tim
</button>
</div>
@endforeach
</div>
</div>
</div>
@endif
<!-- Stats -->
<div class="pug-stats">
<div class="pug-stat pug-stat-total" onclick="setStatus('')" style="cursor: pointer;" title="Klik untuk melihat semua">
<div class="pug-stat-icon"><i class="fas fa-clipboard-list"></i></div>
<div class="pug-stat-label">Total</div>
<div class="pug-stat-val">{{ $totalPenugasan ?? 0 }}</div>
<div style="font-size:11px;color:var(--t3);">Semua penugasan</div>
</div>
<div class="pug-stat pug-stat-belum" onclick="setStatus('belum_mulai')" style="cursor: pointer;" title="Klik untuk filter: Belum Mulai">
<div class="pug-stat-icon"><i class="fas fa-clock"></i></div>
<div class="pug-stat-label">Belum Mulai</div>
<div class="pug-stat-val">{{ $belumMulai ?? 0 }}</div>
<div style="font-size:11px;color:var(--t3);">Menunggu eksekusi</div>
</div>
<div class="pug-stat pug-stat-proses" onclick="setStatus('dalam_proses')" style="cursor: pointer;" title="Klik untuk filter: Dalam Proses">
<div class="pug-stat-icon"><i class="fas fa-spinner"></i></div>
<div class="pug-stat-label">Dalam Proses</div>
<div class="pug-stat-val">{{ $dalamProses ?? 0 }}</div>
<div style="font-size:11px;color:var(--t3);">Sedang dikerjakan</div>
</div>
<div class="pug-stat pug-stat-selesai" onclick="setStatus('selesai')" style="cursor: pointer;" title="Klik untuk filter: Selesai">
<div class="pug-stat-icon"><i class="fas fa-check-circle"></i></div>
<div class="pug-stat-label">Selesai</div>
<div class="pug-stat-val">{{ $selesai ?? 0 }}</div>
<div style="font-size:11px;color:var(--t3);">Pekerjaan rampung</div>
</div>
<div class="pug-stat pug-stat-batal" onclick="setStatus('dibatalkan')" style="cursor: pointer;" title="Klik untuk filter: Dibatalkan">
<div class="pug-stat-icon"><i class="fas fa-times-circle"></i></div>
<div class="pug-stat-label">Dibatalkan</div>
<div class="pug-stat-val">{{ $dibatalkan ?? 0 }}</div>
<div style="font-size:11px;color:var(--t3);">Penugasan dibatalkan</div>
</div>
<div class="pug-stat pug-stat-garansi" onclick="setStatus('garansi_aktif')" style="cursor: pointer;" title="Filter Pekerjaan Selesai (Garansi)">
<div class="pug-stat-icon"><i class="fas fa-shield-alt"></i></div>
<div class="pug-stat-label">Garansi Aktif</div>
<div class="pug-stat-val">{{ $garansiAktif ?? 0 }}</div>
<div style="font-size:11px;color:var(--t3);">Dalam periode garansi</div>
</div>
</div>
<!-- Content layout -->
<div class="pug-main-content">
<!-- Toolbar Filter -->
<div class="pug-toolbar">
<form method="GET" action="{{ route('pekerjaan.penugasan.index') }}" id="filterForm" class="pug-toolbar-form">
<!-- Date Range -->
<div class="pug-toolbar-item" style="flex: 0 0 auto; min-width: 340px;">
<label class="pug-field-label">Rentang Tanggal</label>
<div class="d-flex align-items-center gap-2">
<input type="date" name="start_date" class="pug-input" value="{{ request('start_date') }}" onchange="this.form.submit()" style="width: 145px; padding: 10px 10px;">
<span style="font-size: 10px; color: var(--pug-t3); font-weight: 800;">S/D</span>
<input type="date" name="end_date" class="pug-input" value="{{ request('end_date') }}" onchange="this.form.submit()" style="width: 145px; padding: 10px 10px;">
</div>
</div>
<!-- Search Technician (Direct Select like Monitoring) -->
<div class="pug-toolbar-item" style="flex: 1; min-width: 240px;">
<label class="pug-field-label">Pilih Teknisi (Cari Langsung)</label>
<div class="pug-input-icon">
<i class="fas fa-user-tie"></i>
<select name="id_teknisi" class="pug-input" onchange="this.form.submit()">
<option value="">Semua Teknisi</option>
@foreach($teknisis as $t)
<option value="{{ $t->id_teknisi }}" {{ request('id_teknisi') == $t->id_teknisi ? 'selected' : '' }}>{{ $t->nama }}</option>
@endforeach
</select>
</div>
</div>
<!-- Hidden Status (digunakan oleh filter card di atas) -->
<input type="hidden" name="status" id="hiddenStatus" value="{{ request('status') }}">
<!-- Buttons -->
<div class="pug-toolbar-item item-btn d-flex align-items-end gap-2" style="flex: 0 0 auto;">
<button type="button" class="pug-reset-btn" onclick="window.location.href='{{ route('pekerjaan.penugasan.index') }}'" style="height: 44px; white-space: nowrap;">
<i class="fas fa-redo"></i> Reset Filter
</button>
</div>
</form>
</div>
<!-- Table -->
<div class="pug-panel">
<div class="pug-panel-head">
<div class="pug-panel-head-left">
<i class="fas fa-list-ul" style="color:var(--green);margin-right:8px;"></i>
Daftar Penugasan
</div>
<div class="pug-panel-head-right">
{{ isset($penugasan) ? $penugasan->total() : 0 }} data ditemukan
</div>
</div>
<div style="overflow-x:auto;">
<table class="pug-table">
<thead>
<tr>
<th>#</th>
<th>Teknisi</th>
<th>Surat</th>
<th>Tanggal</th>
<th>Status Pekerjaan</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse($penugasan ?? [] as $index => $item)
<tr>
<td>
<span class="pug-rownum">{{ str_pad($penugasan->firstItem() + $index, 2, '0', STR_PAD_LEFT) }}</span>
</td>
<td>
<div style="display:flex; flex-wrap:wrap; gap:4px; max-width:280px;">
@foreach($item->timTeknisi as $tt)
<span class="pug-tech-badge">
<i class="fas fa-user"></i> {{ $tt->teknisi->nama ?? 'N/A' }}
</span>
@endforeach
</div>
</td>
<td>
@if($item->foto_surat)
<img src="{{ 'https://ta.myhost.id/E31230906/laravel/public/storage/'.$item->foto_surat }}" class="pug-thumb"
alt="Surat" onclick="previewFoto('{{ 'https://ta.myhost.id/E31230906/laravel/public/storage/'.$item->foto_surat }}')">
@else
<span style="color:var(--t3);font-size:11px;">N/A</span>
@endif
</td>
<td>
<div class="pug-date">{{ \Carbon\Carbon::parse($item->tanggal_diberikan)->format('d/m/Y') }}</div>
</td>
<td>
@php
$bMap = [
'belum_mulai' => ['class'=>'pug-badge-muted', 'icon'=>'fa-clock', 'label'=>'Belum Mulai'],
'dalam_proses'=> ['class'=>'pug-badge-violet', 'icon'=>'fa-spinner', 'label'=>'Dalam Proses'],
'selesai' => ['class'=>'pug-badge-green', 'icon'=>'fa-check-circle', 'label'=>'Selesai'],
'dibatalkan' => ['class'=>'pug-badge-rose', 'icon'=>'fa-times-circle', 'label'=>'Dibatalkan'],
];
$bCfg = $bMap[$item->status_pekerjaan] ?? $bMap['belum_mulai'];
@endphp
<span class="pug-badge {{ $bCfg['class'] }}">
<i class="fas {{ $bCfg['icon'] }}"></i> {{ $bCfg['label'] }}
</span>
</td>
<td>
<div class="pug-actions">
<button class="pug-action-btn pug-action-view" onclick="viewDetail({{ $item->id_penugasan }})" title="Lihat Detail">
<i class="fas fa-eye"></i>
</button>
<button class="pug-action-btn pug-action-edit" onclick="editPenugasan({{ $item->id_penugasan }})" title="Edit Info Tugas">
<i class="fas fa-pen"></i>
</button>
<button class="pug-action-btn pug-action-del" onclick="deletePenugasan({{ $item->id_penugasan }})" title="Hapus">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="7">
<div class="pug-empty">
<div class="pug-empty-icon"><i class="fas fa-inbox"></i></div>
<div class="pug-empty-title">Belum ada penugasan</div>
<div class="pug-empty-sub">Klik "Tambah Penugasan" untuk membuat penugasan baru</div>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if(isset($penugasan) && $penugasan->hasPages())
<div class="pug-pag">{{ $penugasan->links() }}</div>
@endif
</div>
</div><!-- /content-layout -->
</div>
</div>
<!-- ── Modal Tambah/Edit ── -->
<div id="createModal" class="pug-overlay">
<div class="pug-modal pug-modal-sm">
<div class="pug-modal-header">
<div class="pug-modal-title"><i class="fas fa-user-plus"></i><span id="modalTitle">Tambah Penugasan Baru</span></div>
<button class="pug-close-btn" onclick="closeModal('createModal')"><i class="fas fa-times"></i></button>
</div>
<div class="pug-info-box">
<i class="fas fa-info-circle"></i>
<p><strong>Metode Foto:</strong> Silakan unggah foto daftar tugas/surat tugas dari kantor. Teknisi akan melihat foto ini di aplikasi mereka.</p>
</div>
<form id="penugasanForm" method="POST" action="{{ route('pekerjaan.penugasan.store') }}" enctype="multipart/form-data">
@csrf
<input type="hidden" id="formMethod" name="_method" value="POST">
<input type="hidden" id="penugasanId" name="id">
<div class="pug-form-grid">
<!-- Teknisi -->
<div class="pug-form-field pug-form-full">
<label class="pug-form-label"><i class="fas fa-user-tie"></i> Pilih Tim Teknisi <span class="req">*</span></label>
<div class="pug-tag-select">
<div class="pug-tag-input-wrapper" id="tagWrapper">
<div id="selectedTags" class="pug-tags-container"></div>
<input type="text" id="techSearch" placeholder="Ketik nama teknisi..." class="pug-tag-input">
</div>
<div class="pug-tag-dropdown" id="techDropdown">
@foreach($teknisiList ?? [] as $teknisi)
<div class="pug-tag-option"
data-id="{{ $teknisi->id_teknisi }}"
data-name="{{ $teknisi->nama }}"
data-sub="{{ $teknisi->spesialisasi }}">
<strong>{{ $teknisi->nama }}</strong>
<span>{{ $teknisi->spesialisasi }}</span>
</div>
@endforeach
<div class="pug-tag-no-results">Tidak ada hasil</div>
</div>
</div>
<!-- Hidden inputs for actual form submission -->
<div id="hiddenTechInputs"></div>
</div>
<!-- Tanggal -->
<div class="pug-form-field">
<label class="pug-form-label"><i class="fas fa-calendar-alt"></i> Tanggal <span class="req">*</span></label>
<input type="date" name="tanggal_diberikan" id="tanggal_diberikan" required class="pug-text-input">
</div>
<!-- Jenis Pekerjaan -->
<div class="pug-form-field">
<label class="pug-form-label"><i class="fas fa-tools"></i> Jenis Pekerjaan <span class="req">*</span></label>
<select name="jenis_pekerjaan" id="jenis_pekerjaan_modal" required class="pug-select">
<option value="">Pilih Jenis Pekerjaan</option>
<option value="sr">SR (Sambungan Rumah)</option>
<option value="pengembangan_jaringan_pipa">Pengembangan Jaringan Pipa</option>
<option value="pengangkatan">Pengangkatan</option>
<option value="pemasangan_gate_valve">Pemasangan Gate Valve</option>
<option value="perbaikan_jaringan_pipa">Perbaikan Jaringan Pipa</option>
<option value="pengecatan_pipa_besi">Pengecatan Pipa Besi</option>
<option value="penyempurnaan_jaringan_pipa">Penyempurnaan Jaringan Pipa</option>
</select>
</div>
<!-- No Sambungan -->
<div class="pug-form-field">
<label class="pug-form-label"><i class="fas fa-hashtag"></i> No. Sambungan <span class="opt">(opsional)</span></label>
<input type="text" name="no_sambungan" id="no_sambungan" class="pug-text-input" placeholder="Contoh: 0032 atau -">
</div>
<!-- Nama Pelanggan -->
<div class="pug-form-field pug-form-full">
<label class="pug-form-label"><i class="fas fa-user"></i> Nama Pelanggan <span class="opt">(opsional)</span></label>
<input type="text" name="nama_pelanggan" id="nama_pelanggan" class="pug-text-input" placeholder="Contoh: Bpk. Slamet atau Nama Gedung">
</div>
<!-- Alamat -->
<div class="pug-form-field pug-form-full">
<label class="pug-form-label"><i class="fas fa-map-marked-alt"></i> Alamat Lengkap <span class="req">*</span></label>
<input type="text" name="alamat_lokasi" id="alamat_lokasi" required class="pug-text-input" placeholder="Contoh: Jl. Merdeka No. 123, Desa Sukamaju">
</div>
<!-- Foto Surat -->
<div class="pug-form-field pug-form-full">
<label class="pug-form-label"><i class="fas fa-camera"></i> Unggah Foto Denah / Surat <span class="opt">(opsional)</span></label>
<div class="pug-upload-zone" onclick="document.getElementById('foto_surat').click()">
<input type="file" name="foto_surat" id="foto_surat" accept="image/*" style="display:none" onchange="previewSelectedFile(this)">
<div id="filePlaceholder">
<i class="fas fa-cloud-upload-alt"></i>
<p>Klik untuk unggah denah lokasi atau surat tugas</p>
<span>Format: JPG, PNG, WEBP (Boleh dikosongkan)</span>
</div>
<img id="filePreview" class="pug-preview-img" src="" style="display:none;">
</div>
</div>
<!-- Catatan Admin -->
<div class="pug-form-field pug-form-full">
<label class="pug-form-label"><i class="fas fa-sticky-note"></i> Instruksi Tambahan <span class="opt">(opsional)</span></label>
<textarea name="catatan_admin" id="catatan_admin" class="pug-text-input" rows="2" placeholder="Contoh: Pipa bocor di bawah pohon mangga, dst..."></textarea>
</div>
</div>
<div class="pug-modal-footer">
<button type="button" class="pug-btn-cancel" onclick="closeModal('createModal')">
<i class="fas fa-times"></i> Batal
</button>
<button type="submit" class="pug-btn-submit">
<i class="fas fa-paper-plane"></i> Kirim Penugasan ke Teknisi
</button>
</div>
</form>
</div>
</div>
<!-- ── Modal Detail ── -->
<div id="detailModal" class="pug-overlay">
<div class="pug-modal pug-modal-lg">
<div class="pug-modal-header">
<div class="pug-modal-title"><i class="fas fa-info-circle"></i> Detail Penugasan</div>
<button class="pug-close-btn" onclick="closeModal('detailModal')"><i class="fas fa-times"></i></button>
</div>
<div id="detailContent"></div>
</div>
</div>
<!-- ── Preview Foto ── -->
<div id="previewModal" class="pug-preview-overlay" onclick="closeModal('previewModal')">
<img id="previewImg" src="" alt="Preview">
<button class="pug-preview-x" onclick="closeModal('previewModal')"><i class="fas fa-times"></i></button>
</div>
<script>
const appUrl = "{{ url('/') }}";
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('tanggal_diberikan').value = new Date().toISOString().split('T')[0];
let t;
const searchInput = document.getElementById('searchInput');
if (searchInput) {
searchInput.addEventListener('input', function () {
clearTimeout(t);
t = setTimeout(() => document.getElementById('filterForm').submit(), 600);
});
}
document.getElementById('tanggal_diberikan').addEventListener('change', function () {
updateTechDropdown(this.value);
});
setTimeout(() => {
document.querySelectorAll('[role="alert"]').forEach(el => {
el.style.transition = 'opacity .5s'; el.style.opacity = '0';
setTimeout(() => el.style.display = 'none', 500);
});
}, 5000);
});
function setStatus(val) {
document.getElementById('hiddenStatus').value = val;
document.getElementById('filterForm').submit();
}
function openCreateModal() {
document.getElementById('modalTitle').textContent = 'Tambah Penugasan';
document.getElementById('penugasanForm').action = "{{ route('pekerjaan.penugasan.store') }}";
document.getElementById('formMethod').value = 'POST';
document.getElementById('penugasanForm').reset();
// Reset preview
document.getElementById('filePreview').style.display = 'none';
document.getElementById('filePlaceholder').style.display = 'block';
const todayDate = new Date().toISOString().split('T')[0];
document.getElementById('tanggal_diberikan').value = todayDate;
updateTechDropdown(todayDate);
document.getElementById('createModal').classList.add('show');
}
function previewSelectedFile(input) {
const preview = document.getElementById('filePreview');
const placeholder = document.getElementById('filePlaceholder');
if (input.files && input.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
preview.src = e.target.result;
preview.style.display = 'block';
placeholder.style.display = 'none';
}
reader.readAsDataURL(input.files[0]);
}
}
function closeModal(id) {
const el = document.getElementById(id);
el.classList.remove('show');
if (id === 'previewModal') el.style.display = 'none'; // fallback for preview overlay
}
function previewFoto(url) {
document.getElementById('previewImg').src = url;
document.getElementById('previewModal').style.display = 'flex';
document.getElementById('previewModal').classList.add('show');
}
function viewDetail(id) {
fetch(`${appUrl}/pekerjaan/penugasan/${id}`)
.then(r => r.json())
.then(data => {
if (!data.success) return alert('Gagal memuat detail');
const d = data.data;
const formatRp = v => 'Rp ' + parseInt(v||0).toLocaleString('id-ID');
const formatDate = v => v ? new Date(v).toLocaleDateString('id-ID',{day:'2-digit',month:'long',year:'numeric'}) : '';
let html = `
<div class="pug-detail-section">
<div class="pug-detail-section-title"><i class="fas fa-users" style="color:var(--cyan);"></i> Tim Teknisi Lapangan</div>
<div style="display:grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap:10px; margin-top:10px;">
${d.tim_teknisi.map(tt => `
<div style="display:flex; align-items:center; gap:8px; background:var(--bg); padding:8px 12px; border-radius:8px; border:1px solid var(--line);">
<div class="pug-av" style="width:28px;height:28px;font-size:11px;flex-shrink:0;">${(tt.teknisi?.nama||'NA').substring(0,2).toUpperCase()}</div>
<div style="overflow:hidden;">
<div style="font-size:12px; font-weight:600; color:var(--t1); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">${tt.teknisi?.nama || 'N/A'}</div>
<div style="font-size:10px; color:var(--t3);">${tt.teknisi?.spesialisasi || '—'}</div>
</div>
</div>
`).join('')}
</div>
<div style="margin-top:20px; padding-top:16px; border-top:1px solid var(--line);">
<div style="color:var(--t3); font-size:11px; font-weight:700; text-transform:uppercase; margin-bottom:12px;">Informasi Lokasi & Pelanggan</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:16px;">
<div>
<div class="pug-detail-item-label"><i class="fas fa-user" style="margin-right:4px;"></i> Nama Pelanggan</div>
<div class="pug-detail-item-val">${d.nama_pelanggan || ''}</div>
</div>
<div>
<div class="pug-detail-item-label"><i class="fas fa-hashtag" style="margin-right:4px;"></i> No. Sambungan</div>
<div class="pug-detail-item-val">${d.no_sambungan || ''}</div>
</div>
</div>
<div style="margin-top:12px;">
<div class="pug-detail-item-label"><i class="fas fa-map-marker-alt" style="margin-right:4px;"></i> Alamat Lokasi</div>
<div class="pug-detail-item-val" style="color:var(--pug-green);">${d.alamat_lokasi || ''}</div>
</div>
</div>
</div>
${d.foto_surat_url ? `
<div style="margin-bottom:14px;">
<div class="pug-detail-item-label" style="margin-bottom:8px;"><i class="fas fa-camera" style="color:var(--green);margin-right:5px;"></i>Denah / Surat Tugas</div>
<img src="${d.foto_surat_url}" style="width:100%;max-height:260px;object-fit:contain;border-radius:10px;border:1px solid var(--line2);cursor:pointer;" onclick="previewFoto('${d.foto_surat_url}')">
<div style="font-size:11px;color:var(--t3);text-align:center;margin-top:5px;">Klik untuk perbesar</div>
</div>` : ''}
${d.catatan_admin ? `
<div style="background:var(--amber-dim);border:1px solid rgba(255,181,71,.2);border-radius:12px;padding:14px 16px;margin-bottom:14px;">
<div style="color:var(--amber);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;margin-bottom:7px;">
<i class="fas fa-map-marker-alt" style="margin-right:5px;"></i>Instruksi Mandor
</div>
<div style="color:var(--t1);font-size:13.5px;font-weight:600;line-height:1.5;">${d.catatan_admin}</div>
</div>` : ''}`;
if (d.items && d.items.length > 0) {
html += `
<div class="pug-detail-section">
<div class="pug-detail-section-title"><i class="fas fa-tools" style="color:var(--violet);"></i> Rincian Pekerjaan (${d.items.length} Item)</div>
<table class="pug-table" style="margin-bottom:14px; font-size:12px;">
<thead>
<tr style="background:var(--line);">
<th style="padding:8px;">Jenis Pekerjaan</th>
<th style="padding:8px;">Detail</th>
<th style="padding:8px; text-align:right;">Subtotal</th>
</tr>
</thead>
<tbody>
${d.items.map(it => `
<tr>
<td style="padding:8px;">
<strong>${it.label_jenis_pekerjaan || it.jenis_pekerjaan}</strong>
</td>
<td style="padding:8px; color:var(--t3);">
${it.dimensi_pipa ? `Dim: ${it.dimensi_pipa}<br>` : ''}
${it.jarak_meter ? `Jarak: ${it.jarak_meter}m<br>` : ''}
${it.jumlah_unit ? `Unit: ${it.jumlah_unit}<br>` : ''}
${it.jumlah_titik ? `Titik: ${it.jumlah_titik}<br>` : ''}
${it.jenis_pengangkatan ? `Tipe: ${it.jenis_pengangkatan}<br>` : ''}
${it.pakai_pipa_besi !== null ? `Pipa Besi: ${it.pakai_pipa_besi ? 'Ya' : 'Tidak'}` : ''}
</td>
<td style="padding:8px; text-align:right; font-weight:700; color:var(--green);">
${formatRp(it.total_nilai_pekerjaan)}
</td>
</tr>
`).join('')}
</tbody>
<tfoot>
<tr style="background:var(--pug-green-l);">
<td colspan="2" style="padding:8px; text-align:right; font-weight:700;">TOTAL NILAI</td>
<td style="padding:8px; text-align:right; font-weight:800; color:var(--green); font-size:14px;">${formatRp(d.total_nilai_pekerjaan)}</td>
</tr>
</tfoot>
</table>
<div style="font-size:11px; color:var(--t3); margin-bottom:5px;">Status Pekerjaan: <strong>${(d.status_pekerjaan||'').replace(/_/g,' ').toUpperCase()}</strong></div>
${d.detail_pekerjaan?`<div style="margin-top:14px;padding-top:14px;border-top:1px solid var(--line);"><div class="pug-detail-item-label" style="margin-bottom:7px;">Catatan Teknisi</div><div style="color:var(--t1);font-size:13px;background:var(--bg);padding:12px;border-radius:9px;border:1px solid var(--line);line-height:1.6;">${d.detail_pekerjaan}</div></div>`:''}
</div>`;
if (d.tanggal_garansi_mulai) {
html += `<div class="pug-garansi-box">
<i class="fas fa-shield-alt"></i>
<div>
<div style="color:var(--violet);font-size:12px;font-weight:700;margin-bottom:3px;">Garansi Aktif</div>
<div style="color:var(--t2);font-size:12px;">${new Date(d.tanggal_garansi_mulai).toLocaleDateString('id-ID')} s/d ${new Date(d.tanggal_garansi_selesai).toLocaleDateString('id-ID')}</div>
</div>
</div>`;
}
if (d.foto_sebelum_url || d.foto_sesudah_url) {
html += `
<div class="pug-detail-section" style="background:var(--bg); border:1px dashed var(--line);">
<div class="pug-detail-section-title"><i class="fas fa-camera" style="color:var(--green);"></i> Dokumentasi Pekerjaan</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-top:10px;">
${d.foto_sebelum_url ? `
<div class="pug-photo-container">
<div class="pug-photo-label"><i class="fas fa-history"></i> Sebelum Pekerjaan</div>
<img src="${d.foto_sebelum_url}" class="pug-photo-item" onclick="window.open('${d.foto_sebelum_url}', '_blank')">
</div>
` : `
<div class="pug-photo-empty">Belum ada foto sebelum</div>
`}
${d.foto_sesudah_url ? `
<div class="pug-photo-container">
<div class="pug-photo-label"><i class="fas fa-check-double"></i> Sesudah Pekerjaan</div>
<img src="${d.foto_sesudah_url}" class="pug-photo-item" onclick="window.open('${d.foto_sesudah_url}', '_blank')">
</div>
` : `
<div class="pug-photo-empty">Belum ada foto sesudah</div>
`}
</div>
</div>`;
}
} else {
html += `<div class="pug-waiting-box">
<i class="fas fa-hourglass-half"></i>
<div style="color:var(--t2);font-size:13px;"><strong style="color:var(--amber);">Menunggu:</strong> Teknisi belum mengisi detail pekerjaan via aplikasi mobile.</div>
</div>`;
}
document.getElementById('detailContent').innerHTML = html;
document.getElementById('detailModal').classList.add('show');
})
.catch(() => alert('Gagal memuat detail penugasan'));
}
function editPenugasan(id) {
fetch(`${appUrl}/pekerjaan/penugasan/${id}/edit`)
.then(r => r.json())
.then(data => {
if (!data.success) return alert(data.message || 'Gagal memuat data');
const item = data.data;
document.getElementById('modalTitle').textContent = 'Edit Penugasan';
document.getElementById('penugasanForm').action = `/pekerjaan/penugasan/${id}`;
document.getElementById('formMethod').value = 'PUT';
document.getElementById('penugasanId').value = id;
// Handle Tag Selection for Team
clearTags();
item.tim_teknisi.forEach(tt => {
addTag(tt.id_teknisi, tt.teknisi.nama);
});
const targetDate = item.tanggal_diberikan || '';
document.getElementById('tanggal_diberikan').value = targetDate;
updateTechDropdown(targetDate);
document.getElementById('catatan_admin').value = item.catatan_admin || '';
document.getElementById('alamat_lokasi').value = item.alamat_lokasi || '';
document.getElementById('nama_pelanggan').value = item.nama_pelanggan || '';
document.getElementById('no_sambungan').value = item.no_sambungan || '';
document.getElementById('jenis_pekerjaan_modal').value = item.jenis_pekerjaan || '';
// Show existing image preview if available
const preview = document.getElementById('filePreview');
const placeholder = document.getElementById('filePlaceholder');
if (item.foto_surat_url) {
preview.src = item.foto_surat_url;
preview.style.display = 'block';
placeholder.style.display = 'none';
} else {
preview.style.display = 'none';
placeholder.style.display = 'block';
}
document.getElementById('createModal').classList.add('show');
})
.catch(() => alert('Gagal memuat data penugasan'));
}
function deletePenugasan(id) {
if (!confirm('Apakah Anda yakin ingin menghapus penugasan ini?')) return;
fetch(`${appUrl}/pekerjaan/penugasan/${id}`, {
method: 'DELETE',
headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), 'Accept': 'application/json' }
})
.then(r => r.json())
.then(data => { data.success ? (alert(data.message), location.reload()) : alert('Gagal: '+(data.message||'Terjadi kesalahan')); })
.catch(() => alert('Terjadi kesalahan saat menghapus'));
}
document.getElementById('penugasanForm').addEventListener('submit', function (e) {
if (document.getElementById('formMethod').value === 'PUT') {
e.preventDefault();
const id = document.getElementById('penugasanId').value;
const formData = new FormData(this);
fetch(`${appUrl}/pekerjaan/penugasan/${id}`, {
method: 'POST',
headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), 'Accept': 'application/json' },
body: formData
})
.then(r => r.json())
.then(data => { data.success ? (alert(data.message), location.reload()) : alert('Gagal: '+(data.message||'Terjadi kesalahan')); })
.catch(() => alert('Terjadi kesalahan saat menyimpan'));
}
});
function resetFilter() { window.location.href = "{{ route('pekerjaan.penugasan.index') }}"; }
window.addEventListener('click', e => {
['createModal','detailModal'].forEach(id => {
const el = document.getElementById(id);
if (e.target === el) closeModal(id);
});
if (e.target === document.getElementById('previewModal')) closeModal('previewModal');
});
// ── Logic Searchable Tag Multi-Select ──
const techSearch = document.getElementById('techSearch');
const techDropdown = document.getElementById('techDropdown');
const selectedTags = document.getElementById('selectedTags');
const hiddenInputs = document.getElementById('hiddenTechInputs');
let selectedIds = new Set();
function addTag(id, name) {
if (selectedIds.has(id.toString())) return;
selectedIds.add(id.toString());
// Create Tag UI
const tag = document.createElement('div');
tag.className = 'pug-tag';
tag.innerHTML = `${name} <i class="fas fa-times" onclick="removeTag('${id}', this)"></i>`;
selectedTags.appendChild(tag);
// Create Hidden Input
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'id_teknisi[]';
input.value = id;
input.id = `input-tech-${id}`;
hiddenInputs.appendChild(input);
techSearch.value = '';
techDropdown.classList.remove('show');
}
window.removeTag = function(id, el) {
selectedIds.delete(id.toString());
el.parentElement.remove();
const input = document.getElementById(`input-tech-${id}`);
if (input) input.remove();
};
function clearTags() {
selectedIds.clear();
selectedTags.innerHTML = '';
hiddenInputs.innerHTML = '';
}
techSearch.addEventListener('focus', () => {
techDropdown.classList.add('show');
});
techSearch.addEventListener('input', (e) => {
const q = e.target.value.toLowerCase();
let hasResults = false;
document.querySelectorAll('.pug-tag-option').forEach(opt => {
const match = opt.dataset.name.toLowerCase().includes(q);
opt.style.display = match ? 'block' : 'none';
if (match) hasResults = true;
});
document.querySelector('.pug-tag-no-results').style.display = hasResults ? 'none' : 'block';
techDropdown.classList.add('show');
});
document.querySelectorAll('.pug-tag-option').forEach(opt => {
opt.addEventListener('click', function() {
addTag(this.dataset.id, this.dataset.name);
});
});
function updateTechDropdown(date) {
const dropdown = document.getElementById('techDropdown');
dropdown.innerHTML = '<div style="padding: 12px; text-align: center; color: var(--pug-t3); font-size: 11.5px;"><i class="fas fa-spinner fa-spin" style="color: #10b981; margin-right: 5px;"></i> Memuat teknisi...</div>';
fetch(`${appUrl}/pekerjaan/penugasan/get-teknisi?date=${date}`)
.then(r => r.json())
.then(res => {
if (res.success) {
let html = '';
if (res.data.length === 0) {
html = '<div style="padding: 12px; text-align: center; color: #ef4444; font-size: 11.5px; font-weight: 600;"><i class="fas fa-exclamation-circle"></i> Tidak ada teknisi yang Hadir hari ini!</div>';
} else {
res.data.forEach(t => {
html += `
<div class="pug-tag-option"
data-id="${t.id_teknisi}"
data-name="${t.nama}"
data-sub="${t.spesialisasi || 'Teknisi'}">
<strong>${t.nama}</strong>
<span>${t.spesialisasi || 'Teknisi'}</span>
</div>
`;
});
html += '<div class="pug-tag-no-results" style="display:none;">Tidak ada hasil</div>';
}
dropdown.innerHTML = html;
// Re-bind click event to newly created elements
document.querySelectorAll('#techDropdown .pug-tag-option').forEach(opt => {
opt.addEventListener('click', function() {
addTag(this.dataset.id, this.dataset.name);
});
});
} else {
dropdown.innerHTML = '<div style="padding: 12px; text-align: center; color: #ef4444; font-size: 11.5px;"><i class="fas fa-times-circle"></i> Gagal memuat data</div>';
}
})
.catch(() => {
dropdown.innerHTML = '<div style="padding: 12px; text-align: center; color: #ef4444; font-size: 11.5px;"><i class="fas fa-exclamation-triangle"></i> Terjadi kesalahan koneksi</div>';
});
}
// Close dropdown on outside click
document.addEventListener('click', (e) => {
if (!e.target.closest('.pug-tag-select')) {
techDropdown.classList.remove('show');
}
});
</script>
</x-app-layout>