fix desain

This commit is contained in:
Muzakki Parsaoran Siregar 2025-09-18 14:53:18 +07:00
parent c1848e0493
commit 5fe5273865

View File

@ -110,414 +110,474 @@
</tr> </tr>
@empty @empty
<tr> <tr>
<td colspan="7" class="p-2 text-center text-gray-500 border border-gray-300">Belum ada template</td> <td colspan="7" class="p-2 text-center text-gray-500 border border-gray-300">Belum ada
template</td>
</tr> </tr>
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
<!-- Modal Tambah Template -->
@if (!isset($kategori))
<div id="modalTambah" class="fixed inset-0 hidden items-center justify-center z-50">
<div class="absolute inset-0 bg-black opacity-50" id="closeTambahModal"></div>
<div class="bg-white rounded-lg shadow-lg w-full max-w-md z-50 flex flex-col max-h-[90vh]">
<!-- Header --> <!-- Pagination -->
<div class="p-4 border-b sticky top-0 bg-white z-10"> <div class="p-4 flex justify-center">
<h5 class="text-lg font-medium">Tambah Template</h5> <div class="flex space-x-1">
</div> {{-- Tombol Previous --}}
@if ($templates->onFirstPage())
<span class="px-3 py-1 rounded-lg bg-gray-200 text-gray-500 cursor-not-allowed">Prev</span>
@else
<a href="{{ $templates->previousPageUrl() }}"
class="px-3 py-1 rounded-lg bg-gray-200 text-gray-700 hover:bg-gray-300">Prev</a>
@endif
<!-- Scrollable content --> @php
<div class="p-4 space-y-4 overflow-y-auto flex-1"> $total = $templates->lastPage();
<form action="{{ route('templates.store') }}" method="POST" enctype="multipart/form-data" class="h-full flex flex-col"> $current = $templates->currentPage();
@csrf @endphp
<div class="flex-1 space-y-4">
<div>
<label class="block text-sm font-medium">Nama Template</label>
<input type="text" name="nama_template" class="w-full p-2 border rounded" required
value="{{ old('nama_template') }}">
</div>
<div>
<label class="block text-sm font-medium">Kategori</label>
<select name="kategori_id" id="kategoriSelectTambah" class="w-full p-2 border rounded">
<option value="">-- Pilih Kategori --</option>
@foreach ($kategoris as $kategoriItem)
<option value="{{ $kategoriItem->id }}" @selected(old('kategori_id') == $kategoriItem->id)>
{{ $kategoriItem->nama }}
</option>
@endforeach
</select>
</div>
<!-- FITUR --> {{-- Selalu tampilkan halaman pertama --}}
<div> @if ($current > 2)
<label class="block text-sm font-medium">Fitur</label> <a href="{{ $templates->url(1) }}"
<div id="fiturContainerTambah" class="px-3 py-1 rounded-lg bg-gray-200 text-gray-700 hover:bg-blue-100">1</a>
class="space-y-3 max-h-64 overflow-auto p-2 border rounded"> @if ($current > 3)
@foreach ($kategoriFiturs as $kategoriFitur) <span class="px-3 py-1 text-gray-500">...</span>
<div> @endif
<p class="font-semibold text-gray-700 mb-1"> @endif
{{ $kategoriFitur->deskripsi }}
</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
@foreach ($fiturs->where('kategori_fitur_id', $kategoriFitur->id) as $fitur)
<label class="flex items-center space-x-2">
<input type="radio" name="fitur_id[{{ $kategoriFitur->id }}]"
value="{{ $fitur->id }}" data-harga="{{ $fitur->harga }}"
@checked(old("fitur_id.$kategoriFitur->id") == $fitur->id)>
<span class="text-sm">
{{ \Illuminate\Support\Str::limit($fitur->deskripsi, 80) }}
(Rp {{ number_format($fitur->harga, 0, ',', '.') }})
</span>
</label>
@endforeach
</div>
</div>
@endforeach
@if ($fitursTanpaKategori->count()) {{-- Halaman tengah --}}
<div> @for ($i = max(1, $current - 1); $i <= min($total, $current + 1); $i++)
<p class="font-semibold text-gray-700 mb-1">Fitur Lainnya</p> @if ($i == $current)
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2"> <span
@foreach ($fitursTanpaKategori as $fitur) class="px-3 py-1 rounded-lg bg-blue-600 text-white font-semibold">{{ $i }}</span>
<label class="flex items-center space-x-2"> @else
<input type="checkbox" name="fitur_id[]" <a href="{{ $templates->url($i) }}"
value="{{ $fitur->id }}" data-harga="{{ $fitur->harga }}" class="px-3 py-1 rounded-lg bg-gray-200 text-gray-700 hover:bg-blue-100">{{ $i }}</a>
{{ is_array(old('fitur_id')) && in_array($fitur->id, old('fitur_id')) ? 'checked' : '' }}> @endif
<span class="text-sm"> @endfor
{{ \Illuminate\Support\Str::limit($fitur->deskripsi, 80) }}
(Rp {{ number_format($fitur->harga, 0, ',', '.') }})
</span>
</label>
@endforeach
</div>
</div>
@endif
</div>
</div>
<div> {{-- Selalu tampilkan halaman terakhir --}}
<label class="block text-sm font-medium">Harga</label> @if ($current < $total - 1)
<input type="text" name="harga" class="w-full p-2 border rounded" required @if ($current < $total - 2)
min="0" value="{{ old('harga') }}"> <span class="px-3 py-1 text-gray-500">...</span>
</div> @endif
<div> <a href="{{ $templates->url($total) }}"
<label class="block text-sm font-medium">Foto (opsional)</label> class="px-3 py-1 rounded-lg bg-gray-200 text-gray-700 hover:bg-blue-100">{{ $total }}</a>
<input type="file" name="foto" class="w-full p-2 border rounded" accept="image/*"> @endif
<small class="text-gray-500">Format: JPG, PNG, GIF. Maks 5MB.</small>
</div>
</div>
<!-- Footer --> {{-- Tombol Next --}}
<div class="p-4 border-t flex justify-end space-x-2 sticky bottom-0 bg-white z-10"> @if ($templates->hasMorePages())
<button type="button" id="closeTambahBtn" <a href="{{ $templates->nextPageUrl() }}"
class="bg-gray-300 text-black px-3 py-1 rounded">Batal</button> class="px-3 py-1 rounded-lg bg-gray-200 text-gray-700 hover:bg-gray-300">Next</a>
<button class="bg-blue-600 text-white px-3 py-1 rounded">Simpan</button> @else
</div> <span class="px-3 py-1 rounded-lg bg-gray-200 text-gray-500 cursor-not-allowed">Next</span>
</form> @endif
</div>
</div> </div>
</div> </div>
@endif </div>
</div>
<!-- Modal Edit Template -->
@foreach ($templates as $template)
<div id="modalEdit{{ $template->id }}" class="fixed inset-0 hidden items-center justify-center z-50">
<div class="absolute inset-0 bg-black opacity-50 closeEditOverlay" data-id="{{ $template->id }}"></div>
<div class="bg-white rounded-lg shadow-lg w-full max-w-md z-50 flex flex-col max-h-[90vh]">
<!-- Header -->
<div class="p-4 border-b sticky top-0 bg-white z-10">
<h5 class="text-lg font-medium">Edit Template</h5>
</div>
<!-- Scrollable content --> <!-- Modal Tambah Template -->
<div class="p-4 space-y-4 overflow-y-auto flex-1"> @if (!isset($kategori))
<form action="{{ route('templates.update', $template->id) }}" method="POST" <div id="modalTambah" class="fixed inset-0 hidden items-center justify-center z-50">
enctype="multipart/form-data" class="h-full flex flex-col"> <div class="absolute inset-0 bg-black opacity-50" id="closeTambahModal"></div>
@csrf @method('PUT') <div class="bg-white rounded-lg shadow-lg w-full max-w-md z-50 flex flex-col max-h-[90vh]">
<div class="flex-1 space-y-4">
<div>
<label class="block text-sm font-medium">Nama Template</label>
<input type="text" name="nama_template"
value="{{ old('nama_template', $template->nama_template) }}"
class="w-full p-2 border rounded" required>
</div>
<div>
<label class="block text-sm font-medium">Kategori</label>
<select name="kategori_id" id="kategoriSelectEdit{{ $template->id }}"
class="w-full p-2 border rounded">
<option value="">-- Pilih Kategori --</option>
@foreach ($kategoris as $kategoriItem)
<option value="{{ $kategoriItem->id }}" @selected($kategoriItem->id == old('kategori_id', $template->kategori_id))>
{{ $kategoriItem->nama }}
</option>
@endforeach
</select>
</div>
<!-- FITUR --> <!-- Header -->
<div> <div class="p-4 border-b sticky top-0 bg-white z-10">
<label class="block text-sm font-medium">Fitur</label> <h5 class="text-lg font-medium">Tambah Template</h5>
<div id="fiturContainerEdit{{ $template->id }}" </div>
class="space-y-3 max-h-64 overflow-auto p-2 border rounded">
@foreach ($kategoriFiturs as $kategoriFitur) <!-- Scrollable content -->
<div> <div class="p-4 space-y-4 overflow-y-auto flex-1">
<p class="font-semibold text-gray-700 mb-1"> <form action="{{ route('templates.store') }}" method="POST" enctype="multipart/form-data"
{{ $kategoriFitur->deskripsi }} class="h-full flex flex-col">
</p> @csrf
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2"> <div class="flex-1 space-y-4">
@foreach ($fiturs->where('kategori_fitur_id', $kategoriFitur->id) as $fiturItem) <div>
<label class="flex items-center space-x-2"> <label class="block text-sm font-medium">Nama Template</label>
<input type="radio" name="fitur_id[{{ $kategoriFitur->id }}]" <input type="text" name="nama_template" class="w-full p-2 border rounded" required
value="{{ $fiturItem->id }}" value="{{ old('nama_template') }}">
data-harga="{{ $fiturItem->harga }}" </div>
{{ old("fitur_id.$kategoriFitur->id") == $fiturItem->id || $template->fiturs->contains($fiturItem->id) ? 'checked' : '' }}> <div>
<span class="text-sm"> <label class="block text-sm font-medium">Kategori</label>
{{ \Illuminate\Support\Str::limit($fiturItem->deskripsi, 80) }} <select name="kategori_id" id="kategoriSelectTambah" class="w-full p-2 border rounded">
(Rp {{ number_format($fiturItem->harga, 0, ',', '.') }}) <option value="">-- Pilih Kategori --</option>
</span> @foreach ($kategoris as $kategoriItem)
</label> <option value="{{ $kategoriItem->id }}" @selected(old('kategori_id') == $kategoriItem->id)>
@endforeach {{ $kategoriItem->nama }}
</div> </option>
@endforeach
</select>
</div>
<!-- FITUR -->
<div>
<label class="block text-sm font-medium">Fitur</label>
<div id="fiturContainerTambah" class="space-y-3 max-h-64 overflow-auto p-2 border rounded">
@foreach ($kategoriFiturs as $kategoriFitur)
<div>
<p class="font-semibold text-gray-700 mb-1">
{{ $kategoriFitur->deskripsi }}
</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
@foreach ($fiturs->where('kategori_fitur_id', $kategoriFitur->id) as $fitur)
<label class="flex items-center space-x-2">
<input type="radio" name="fitur_id[{{ $kategoriFitur->id }}]"
value="{{ $fitur->id }}" data-harga="{{ $fitur->harga }}"
@checked(old("fitur_id.$kategoriFitur->id") == $fitur->id)>
<span class="text-sm">
{{ \Illuminate\Support\Str::limit($fitur->deskripsi, 80) }}
(Rp {{ number_format($fitur->harga, 0, ',', '.') }})
</span>
</label>
@endforeach
</div> </div>
@endforeach </div>
@endforeach
@if ($fitursTanpaKategori->count()) @if ($fitursTanpaKategori->count())
<div> <div>
<p class="font-semibold text-gray-700 mb-1">Fitur Lainnya</p> <p class="font-semibold text-gray-700 mb-1">Fitur Lainnya</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2"> <div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
@foreach ($fitursTanpaKategori as $fitur) @foreach ($fitursTanpaKategori as $fitur)
<label class="flex items-center space-x-2"> <label class="flex items-center space-x-2">
<input type="checkbox" name="fitur_id[]" <input type="checkbox" name="fitur_id[]"
value="{{ $fitur->id }}" data-harga="{{ $fitur->harga }}" value="{{ $fitur->id }}" data-harga="{{ $fitur->harga }}"
{{ (is_array(old('fitur_id')) && in_array($fitur->id, old('fitur_id'))) || $template->fiturs->contains($fitur->id) ? 'checked' : '' }}> {{ is_array(old('fitur_id')) && in_array($fitur->id, old('fitur_id')) ? 'checked' : '' }}>
<span class="text-sm"> <span class="text-sm">
{{ \Illuminate\Support\Str::limit($fitur->deskripsi, 80) }} {{ \Illuminate\Support\Str::limit($fitur->deskripsi, 80) }}
(Rp {{ number_format($fitur->harga, 0, ',', '.') }}) (Rp {{ number_format($fitur->harga, 0, ',', '.') }})
</span> </span>
</label> </label>
@endforeach @endforeach
</div>
</div>
@endif
</div>
</div>
<div>
<label class="block text-sm font-medium">Harga</label>
<input type="text" name="harga" value="{{ old('harga', $template->harga) }}"
class="w-full p-2 border rounded" required min="0">
</div>
<div>
<label class="block text-sm font-medium">Foto (opsional)</label>
@if ($template->foto)
<div class="mb-2">
<small class="text-gray-500">Foto saat ini:</small>
<div
class="w-20 h-20 mt-1 overflow-hidden rounded bg-gray-100 flex items-center justify-center border">
<img src="{{ asset('storage/' . $template->foto) }}" alt="foto"
class="max-w-full max-h-full object-contain">
</div> </div>
</div> </div>
@endif @endif
<input type="file" name="foto" class="w-full p-2 border rounded" accept="image/*">
</div> </div>
</div> </div>
</form> <div>
</div> <label class="block text-sm font-medium">Harga</label>
<!-- Footer --> <input type="text" name="harga" class="w-full p-2 border rounded" required
<div class="p-4 border-t flex justify-end space-x-2 sticky bottom-0 bg-white z-10"> min="0" value="{{ old('harga') }}">
<button type="button" class="bg-gray-300 text-black px-3 py-1 rounded closeEditBtn" </div>
data-id="{{ $template->id }}">Batal</button> <div>
<button class="bg-blue-600 text-white px-3 py-1 rounded">Simpan Perubahan</button> <label class="block text-sm font-medium">Foto (opsional)</label>
</div> <input type="file" name="foto" class="w-full p-2 border rounded" accept="image/*">
<small class="text-gray-500">Format: JPG, PNG, GIF. Maks 5MB.</small>
</div>
</div>
<!-- Footer -->
<div class="p-4 border-t flex justify-end space-x-2 sticky bottom-0 bg-white z-10">
<button type="button" id="closeTambahBtn"
class="bg-gray-300 text-black px-3 py-1 rounded">Batal</button>
<button class="bg-blue-600 text-white px-3 py-1 rounded">Simpan</button>
</div>
</form>
</div> </div>
</div> </div>
@endforeach </div>
@endif
<!-- Modal Edit Template -->
@foreach ($templates as $template)
<div id="modalEdit{{ $template->id }}" class="fixed inset-0 hidden items-center justify-center z-50">
<div class="absolute inset-0 bg-black opacity-50 closeEditOverlay" data-id="{{ $template->id }}"></div>
<div class="bg-white rounded-lg shadow-lg w-full max-w-md z-50 flex flex-col max-h-[90vh]">
<!-- Header -->
<div class="p-4 border-b sticky top-0 bg-white z-10">
<h5 class="text-lg font-medium">Edit Template</h5>
</div>
<!-- Scrollable content -->
<div class="p-4 space-y-4 overflow-y-auto flex-1">
<form action="{{ route('templates.update', $template->id) }}" method="POST"
enctype="multipart/form-data" class="h-full flex flex-col">
@csrf @method('PUT')
<div class="flex-1 space-y-4">
<div>
<label class="block text-sm font-medium">Nama Template</label>
<input type="text" name="nama_template"
value="{{ old('nama_template', $template->nama_template) }}"
class="w-full p-2 border rounded" required>
</div>
<div>
<label class="block text-sm font-medium">Kategori</label>
<select name="kategori_id" id="kategoriSelectEdit{{ $template->id }}"
class="w-full p-2 border rounded">
<option value="">-- Pilih Kategori --</option>
@foreach ($kategoris as $kategoriItem)
<option value="{{ $kategoriItem->id }}" @selected($kategoriItem->id == old('kategori_id', $template->kategori_id))>
{{ $kategoriItem->nama }}
</option>
@endforeach
</select>
</div>
<!-- FITUR -->
<div>
<label class="block text-sm font-medium">Fitur</label>
<div id="fiturContainerEdit{{ $template->id }}"
class="space-y-3 max-h-64 overflow-auto p-2 border rounded">
@foreach ($kategoriFiturs as $kategoriFitur)
<div>
<p class="font-semibold text-gray-700 mb-1">
{{ $kategoriFitur->deskripsi }}
</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
@foreach ($fiturs->where('kategori_fitur_id', $kategoriFitur->id) as $fiturItem)
<label class="flex items-center space-x-2">
<input type="radio" name="fitur_id[{{ $kategoriFitur->id }}]"
value="{{ $fiturItem->id }}"
data-harga="{{ $fiturItem->harga }}"
{{ old("fitur_id.$kategoriFitur->id") == $fiturItem->id || $template->fiturs->contains($fiturItem->id) ? 'checked' : '' }}>
<span class="text-sm">
{{ \Illuminate\Support\Str::limit($fiturItem->deskripsi, 80) }}
(Rp {{ number_format($fiturItem->harga, 0, ',', '.') }})
</span>
</label>
@endforeach
</div>
</div>
@endforeach
@if ($fitursTanpaKategori->count())
<div>
<p class="font-semibold text-gray-700 mb-1">Fitur Lainnya</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
@foreach ($fitursTanpaKategori as $fitur)
<label class="flex items-center space-x-2">
<input type="checkbox" name="fitur_id[]"
value="{{ $fitur->id }}" data-harga="{{ $fitur->harga }}"
{{ (is_array(old('fitur_id')) && in_array($fitur->id, old('fitur_id'))) || $template->fiturs->contains($fitur->id) ? 'checked' : '' }}>
<span class="text-sm">
{{ \Illuminate\Support\Str::limit($fitur->deskripsi, 80) }}
(Rp {{ number_format($fitur->harga, 0, ',', '.') }})
</span>
</label>
@endforeach
</div>
</div>
@endif
</div>
</div>
<div>
<label class="block text-sm font-medium">Harga</label>
<input type="text" name="harga" value="{{ old('harga', $template->harga) }}"
class="w-full p-2 border rounded" required min="0">
</div>
<div>
<label class="block text-sm font-medium">Foto (opsional)</label>
@if ($template->foto)
<div class="mb-2">
<small class="text-gray-500">Foto saat ini:</small>
<div
class="w-20 h-20 mt-1 overflow-hidden rounded bg-gray-100 flex items-center justify-center border">
<img src="{{ asset('storage/' . $template->foto) }}" alt="foto"
class="max-w-full max-h-full object-contain">
</div>
</div>
@endif
<input type="file" name="foto" class="w-full p-2 border rounded" accept="image/*">
</div>
</div>
</form>
</div>
<!-- Footer -->
<div class="p-4 border-t flex justify-end space-x-2 sticky bottom-0 bg-white z-10">
<button type="button" class="bg-gray-300 text-black px-3 py-1 rounded closeEditBtn"
data-id="{{ $template->id }}">Batal</button>
<button class="bg-blue-600 text-white px-3 py-1 rounded">Simpan Perubahan</button>
</div>
</div>
</div>
@endforeach
<script> <script>
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// ========================= // =========================
// Modal Tambah // Modal Tambah
// ========================= // =========================
const openTambahModal = document.getElementById('openTambahModal'); const openTambahModal = document.getElementById('openTambahModal');
const modalTambah = document.getElementById('modalTambah'); const modalTambah = document.getElementById('modalTambah');
const closeTambahBtn = document.getElementById('closeTambahBtn'); const closeTambahBtn = document.getElementById('closeTambahBtn');
const closeTambahOverlay = document.getElementById('closeTambahModal'); const closeTambahOverlay = document.getElementById('closeTambahModal');
if (openTambahModal) { if (openTambahModal) {
openTambahModal.addEventListener('click', () => { openTambahModal.addEventListener('click', () => {
modalTambah.classList.remove('hidden'); modalTambah.classList.remove('hidden');
modalTambah.classList.add('flex'); modalTambah.classList.add('flex');
});
}
if (closeTambahBtn) {
closeTambahBtn.addEventListener('click', () => {
modalTambah.classList.add('hidden');
modalTambah.classList.remove('flex');
});
}
if (closeTambahOverlay) {
closeTambahOverlay.addEventListener('click', () => {
modalTambah.classList.add('hidden');
modalTambah.classList.remove('flex');
});
}
// =========================
// Modal Edit
// =========================
const openEditBtns = document.querySelectorAll('.openEditModalBtn');
const closeEditBtns = document.querySelectorAll('.closeEditBtn');
const closeEditOverlays = document.querySelectorAll('.closeEditOverlay');
openEditBtns.forEach(btn => {
btn.addEventListener('click', () => {
const id = btn.dataset.id;
const modal = document.getElementById('modalEdit' + id);
if (modal) {
modal.classList.remove('hidden');
modal.classList.add('flex');
}
});
}); });
}
closeEditBtns.forEach(btn => { if (closeTambahBtn) {
btn.addEventListener('click', () => { closeTambahBtn.addEventListener('click', () => {
const id = btn.dataset.id; modalTambah.classList.add('hidden');
const modal = document.getElementById('modalEdit' + id); modalTambah.classList.remove('flex');
if (modal) {
modal.classList.add('hidden');
modal.classList.remove('flex');
}
});
}); });
}
closeEditOverlays.forEach(overlay => { if (closeTambahOverlay) {
overlay.addEventListener('click', () => { closeTambahOverlay.addEventListener('click', () => {
const id = overlay.dataset.id; modalTambah.classList.add('hidden');
const modal = document.getElementById('modalEdit' + id); modalTambah.classList.remove('flex');
if (modal) {
modal.classList.add('hidden');
modal.classList.remove('flex');
}
});
}); });
}
// ========================= // =========================
// Modal Delete Template // Modal Edit
// ========================= // =========================
const deleteTemplateModal = document.getElementById('modalDeleteTemplate'); const openEditBtns = document.querySelectorAll('.openEditModalBtn');
const deleteTemplateOverlay = document.getElementById('modalDeleteTemplateOverlay'); const closeEditBtns = document.querySelectorAll('.closeEditBtn');
const closeDeleteTemplateModal = document.getElementById('closeDeleteTemplateModal'); const closeEditOverlays = document.querySelectorAll('.closeEditOverlay');
const deleteTemplateForm = document.getElementById('deleteTemplateForm');
const deleteTemplateName = document.getElementById('deleteTemplateName');
document.querySelectorAll('.btn-delete-template').forEach(btn => { openEditBtns.forEach(btn => {
btn.addEventListener('click', (e) => { btn.addEventListener('click', () => {
e.preventDefault(); // cegah form langsung submit const id = btn.dataset.id;
deleteTemplateForm.action = btn.dataset.action; const modal = document.getElementById('modalEdit' + id);
deleteTemplateName.textContent = btn.dataset.name || 'template ini'; if (modal) {
deleteTemplateModal.classList.remove('hidden'); modal.classList.remove('hidden');
deleteTemplateModal.classList.add('flex'); modal.classList.add('flex');
});
});
const closeDeleteModalTemplate = () => {
deleteTemplateModal.classList.add('hidden');
deleteTemplateModal.classList.remove('flex');
};
if (closeDeleteTemplateModal) {
closeDeleteTemplateModal.addEventListener('click', closeDeleteModalTemplate);
}
if (deleteTemplateOverlay) {
deleteTemplateOverlay.addEventListener('click', closeDeleteModalTemplate);
}
// =========================
// Fitur: Hitung Harga Otomatis + Format ribuan
// =========================
function formatRibuan(x) {
if (!x) return '';
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}
function hitungHarga(container) {
let total = 0;
// Hitung checkbox (fitur tanpa kategori)
container.querySelectorAll('input[type="checkbox"][name="fitur_id[]"]:checked')
.forEach(cb => {
total += parseInt(cb.dataset.harga) || 0;
});
// Hitung radio (fitur per kategori)
container.querySelectorAll('input[type="radio"]:checked')
.forEach(radio => {
total += parseInt(radio.dataset.harga) || 0;
});
const inputHarga = container.querySelector('input[name="harga"]');
if (inputHarga && !inputHarga.dataset.manual) {
inputHarga.value = formatRibuan(total);
} }
}
// Format harga manual + tetap auto ribuan
document.querySelectorAll('input[name="harga"]').forEach(input => {
input.classList.add("harga-input"); // pastikan ada class
input.addEventListener('input', (e) => {
let value = e.target.value.replace(/\D/g, ''); // hanya angka
e.target.value = formatRibuan(value);
e.target.dataset.manual = "true"; // flag manual
});
});
// Modal Tambah
if (modalTambah) {
const inputs = modalTambah.querySelectorAll('input[name="fitur_id[]"], input[type="radio"]');
const inputHarga = modalTambah.querySelector('input[name="harga"]');
inputs.forEach(input => {
input.addEventListener('change', () => hitungHarga(modalTambah));
});
if (inputHarga) {
inputHarga.addEventListener('input', () => {
inputHarga.dataset.manual = "true";
});
}
// Hitung awal kalau ada yang sudah tercentang
hitungHarga(modalTambah);
}
// Modal Edit (banyak)
document.querySelectorAll('[id^="modalEdit"]').forEach(modal => {
const inputs = modal.querySelectorAll('input[name="fitur_id[]"], input[type="radio"]');
const inputHarga = modal.querySelector('input[name="harga"]');
inputs.forEach(input => {
input.addEventListener('change', () => hitungHarga(modal));
});
if (inputHarga) {
inputHarga.addEventListener('input', () => {
inputHarga.dataset.manual = "true";
});
}
// Hitung awal kalau ada yang sudah tercentang
hitungHarga(modal);
}); });
}); });
</script>
closeEditBtns.forEach(btn => {
btn.addEventListener('click', () => {
const id = btn.dataset.id;
const modal = document.getElementById('modalEdit' + id);
if (modal) {
modal.classList.add('hidden');
modal.classList.remove('flex');
}
});
});
closeEditOverlays.forEach(overlay => {
overlay.addEventListener('click', () => {
const id = overlay.dataset.id;
const modal = document.getElementById('modalEdit' + id);
if (modal) {
modal.classList.add('hidden');
modal.classList.remove('flex');
}
});
});
// =========================
// Modal Delete Template
// =========================
const deleteTemplateModal = document.getElementById('modalDeleteTemplate');
const deleteTemplateOverlay = document.getElementById('modalDeleteTemplateOverlay');
const closeDeleteTemplateModal = document.getElementById('closeDeleteTemplateModal');
const deleteTemplateForm = document.getElementById('deleteTemplateForm');
const deleteTemplateName = document.getElementById('deleteTemplateName');
document.querySelectorAll('.btn-delete-template').forEach(btn => {
btn.addEventListener('click', (e) => {
e.preventDefault(); // cegah form langsung submit
deleteTemplateForm.action = btn.dataset.action;
deleteTemplateName.textContent = btn.dataset.name || 'template ini';
deleteTemplateModal.classList.remove('hidden');
deleteTemplateModal.classList.add('flex');
});
});
const closeDeleteModalTemplate = () => {
deleteTemplateModal.classList.add('hidden');
deleteTemplateModal.classList.remove('flex');
};
if (closeDeleteTemplateModal) {
closeDeleteTemplateModal.addEventListener('click', closeDeleteModalTemplate);
}
if (deleteTemplateOverlay) {
deleteTemplateOverlay.addEventListener('click', closeDeleteModalTemplate);
}
// =========================
// Fitur: Hitung Harga Otomatis + Format ribuan
// =========================
function formatRibuan(x) {
if (!x) return '';
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}
function hitungHarga(container) {
let total = 0;
// Hitung checkbox (fitur tanpa kategori)
container.querySelectorAll('input[type="checkbox"][name="fitur_id[]"]:checked')
.forEach(cb => {
total += parseInt(cb.dataset.harga) || 0;
});
// Hitung radio (fitur per kategori)
container.querySelectorAll('input[type="radio"]:checked')
.forEach(radio => {
total += parseInt(radio.dataset.harga) || 0;
});
const inputHarga = container.querySelector('input[name="harga"]');
if (inputHarga && !inputHarga.dataset.manual) {
inputHarga.value = formatRibuan(total);
}
}
// Format harga manual + tetap auto ribuan
document.querySelectorAll('input[name="harga"]').forEach(input => {
input.classList.add("harga-input"); // pastikan ada class
input.addEventListener('input', (e) => {
let value = e.target.value.replace(/\D/g, ''); // hanya angka
e.target.value = formatRibuan(value);
e.target.dataset.manual = "true"; // flag manual
});
});
// Modal Tambah
if (modalTambah) {
const inputs = modalTambah.querySelectorAll('input[name="fitur_id[]"], input[type="radio"]');
const inputHarga = modalTambah.querySelector('input[name="harga"]');
inputs.forEach(input => {
input.addEventListener('change', () => hitungHarga(modalTambah));
});
if (inputHarga) {
inputHarga.addEventListener('input', () => {
inputHarga.dataset.manual = "true";
});
}
// Hitung awal kalau ada yang sudah tercentang
hitungHarga(modalTambah);
}
// Modal Edit (banyak)
document.querySelectorAll('[id^="modalEdit"]').forEach(modal => {
const inputs = modal.querySelectorAll('input[name="fitur_id[]"], input[type="radio"]');
const inputHarga = modal.querySelector('input[name="harga"]');
inputs.forEach(input => {
input.addEventListener('change', () => hitungHarga(modal));
});
if (inputHarga) {
inputHarga.addEventListener('input', () => {
inputHarga.dataset.manual = "true";
});
}
// Hitung awal kalau ada yang sudah tercentang
hitungHarga(modal);
});
});
</script>
</div> </div>