fix radio & checkbox
This commit is contained in:
parent
e322f2fa37
commit
8a02c512c2
@ -1,30 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// app/Http/Controllers/FiturController.php
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Fitur;
|
use App\Models\Fitur;
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\KategoriFitur;
|
use App\Models\KategoriFitur;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class FiturController extends Controller
|
class FiturController extends Controller
|
||||||
{
|
{
|
||||||
// Tampilkan semua fitur
|
public function index()
|
||||||
public function index()
|
{
|
||||||
{
|
$fitur = Fitur::with('kategoriFitur')->paginate(5);
|
||||||
$fitur = Fitur::with('kategoriFitur')->paginate(5);
|
$kategoriFiturs = KategoriFitur::all();
|
||||||
$kategoriFiturs = KategoriFitur::all();
|
|
||||||
|
|
||||||
return view('admin.fitur.index', compact('fitur', 'kategoriFiturs'));
|
return view('admin.fitur.index', compact('fitur', 'kategoriFiturs'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simpan fitur baru
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'deskripsi' => 'required|string|max:255',
|
'deskripsi' => 'required|string|max:255',
|
||||||
'harga' => 'required|numeric|min:0',
|
'harga' => 'required|numeric|min:0',
|
||||||
'kategori_fitur_id' => 'required|exists:kategori_fitur,id',
|
'kategori_fitur_id' => 'nullable|exists:kategori_fitur,id',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Fitur::create([
|
Fitur::create([
|
||||||
@ -33,32 +30,35 @@ public function index()
|
|||||||
'kategori_fitur_id' => $request->kategori_fitur_id,
|
'kategori_fitur_id' => $request->kategori_fitur_id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return redirect()->route('admin.fitur.index')->with('success', 'Fitur berhasil ditambahkan');
|
return redirect()->route('admin.fitur.index')
|
||||||
|
->with('success', 'Fitur berhasil ditambahkan');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update fitur
|
|
||||||
public function update(Request $request, $id)
|
public function update(Request $request, $id)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'deskripsi' => 'required|string|max:255',
|
'deskripsi' => 'required|string|max:255',
|
||||||
'harga' => 'required|numeric|min:0',
|
'harga' => 'required|numeric|min:0',
|
||||||
|
'kategori_fitur_id' => 'nullable|exists:kategori_fitur,id',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$fitur = Fitur::findOrFail($id);
|
$fitur = Fitur::findOrFail($id);
|
||||||
$fitur->update([
|
$fitur->update([
|
||||||
'deskripsi' => $request->deskripsi,
|
'deskripsi' => $request->deskripsi,
|
||||||
'harga' => $request->harga,
|
'harga' => $request->harga,
|
||||||
|
'kategori_fitur_id' => $request->kategori_fitur_id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return redirect()->route('admin.fitur.index')->with('success', 'Fitur berhasil diperbarui');
|
return redirect()->route('admin.fitur.index')
|
||||||
|
->with('success', 'Fitur berhasil diperbarui');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hapus fitur
|
|
||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
$fitur = Fitur::findOrFail($id);
|
$fitur = Fitur::findOrFail($id);
|
||||||
$fitur->delete();
|
$fitur->delete();
|
||||||
|
|
||||||
return redirect()->route('admin.fitur.index')->with('success', 'Fitur berhasil dihapus');
|
return redirect()->route('admin.fitur.index')
|
||||||
|
->with('success', 'Fitur berhasil dihapus');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,20 +5,35 @@ namespace App\Http\Controllers;
|
|||||||
use App\Models\Template;
|
use App\Models\Template;
|
||||||
use App\Models\Kategori;
|
use App\Models\Kategori;
|
||||||
use App\Models\Fitur;
|
use App\Models\Fitur;
|
||||||
|
use App\Models\KategoriFitur; // <-- tambah ini
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class TemplateController extends Controller
|
class TemplateController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
// eager load fiturs & kategori
|
$templates = Template::with(['kategori', 'fiturs'])->paginate(5);
|
||||||
$templates = Template::with(['kategori', 'fiturs'])->paginate(5);
|
$kategoris = Kategori::all();
|
||||||
$kategoris = Kategori::all();
|
|
||||||
$fiturs = Fitur::all();
|
// semua fitur dengan relasi kategori
|
||||||
|
$fiturs = Fitur::with('kategoriFitur')->get();
|
||||||
|
|
||||||
|
// kategori fitur beserta fiturnya
|
||||||
|
$kategoriFiturs = KategoriFitur::with('fiturs')->get();
|
||||||
|
|
||||||
|
// fitur yang tidak punya kategori
|
||||||
|
$fitursTanpaKategori = Fitur::whereNull('kategori_fitur_id')->get();
|
||||||
|
|
||||||
|
return view('admin.templates.index', compact(
|
||||||
|
'templates',
|
||||||
|
'kategoris',
|
||||||
|
'fiturs',
|
||||||
|
'kategoriFiturs',
|
||||||
|
'fitursTanpaKategori'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
return view('admin.templates.index', compact('templates', 'kategoris', 'fiturs'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
@ -108,15 +123,25 @@ class TemplateController extends Controller
|
|||||||
return redirect()->route('templates.index')->with('success', 'Template berhasil dihapus!');
|
return redirect()->route('templates.index')->with('success', 'Template berhasil dihapus!');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function byKategori($id)
|
public function byKategori($id)
|
||||||
{
|
{
|
||||||
$kategori = Kategori::findOrFail($id);
|
$kategori = Kategori::findOrFail($id);
|
||||||
$templates = Template::with(['kategori', 'fiturs'])
|
$templates = Template::with(['kategori', 'fiturs'])
|
||||||
->where('kategori_id', $id)
|
->where('kategori_id', $id)
|
||||||
->paginate(5);
|
->paginate(5);
|
||||||
$kategoris = Kategori::all();
|
$kategoris = Kategori::all();
|
||||||
$fiturs = Fitur::all();
|
$fiturs = Fitur::with('kategoriFitur')->get();
|
||||||
|
$kategoriFiturs = KategoriFitur::with('fiturs')->get();
|
||||||
|
$fitursTanpaKategori = Fitur::whereNull('kategori_fitur_id')->get(); // <-- tambahkan ini
|
||||||
|
|
||||||
|
return view('admin.templates.index', compact(
|
||||||
|
'templates',
|
||||||
|
'kategoris',
|
||||||
|
'fiturs',
|
||||||
|
'kategori',
|
||||||
|
'kategoriFiturs',
|
||||||
|
'fitursTanpaKategori' // <-- kirim ke view
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
return view('admin.templates.index', compact('templates', 'kategoris', 'fiturs', 'kategori'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,9 +18,9 @@ class Fitur extends Model
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
public function kategoriFitur()
|
public function kategoriFitur()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(KategoriFitur::class, 'kategori_fitur_id');
|
return $this->belongsTo(KategoriFitur::class, 'kategori_fitur_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,4 +14,10 @@ class KategoriFitur extends Model
|
|||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'deskripsi',
|
'deskripsi',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// relasi: satu kategori punya banyak fitur
|
||||||
|
public function fiturs()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Fitur::class, 'kategori_fitur_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -157,30 +157,43 @@
|
|||||||
<h5 class="text-lg font-medium">Tambah Fitur</h5>
|
<h5 class="text-lg font-medium">Tambah Fitur</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4 space-y-4">
|
<div class="p-4 space-y-4">
|
||||||
<!-- Kategori -->
|
|
||||||
<div>
|
{{-- Kategori --}}
|
||||||
<label class="block text-sm font-medium">Kategori Fitur</label>
|
@if($kategori_fitur ?? false)
|
||||||
<select name="kategori_fitur_id" class="w-full p-2 border rounded" required>
|
<!-- Jika controller mengirim $kategori_fitur -->
|
||||||
<option value="">-- Pilih Kategori --</option>
|
<input type="hidden" name="kategori_fitur_id" value="{{ optional($kategori_fitur ?? null)->id }}">
|
||||||
@foreach(\App\Models\KategoriFitur::all() as $kategori)
|
<p class="text-sm text-gray-600">
|
||||||
<option value="{{ $kategori->id }}">{{ $kategori->deskripsi }}</option>
|
Kategori: <strong>{{ optional($kategori_fitur ?? null)->deskripsi }}</strong>
|
||||||
@endforeach
|
</p>
|
||||||
</select>
|
@else
|
||||||
</div>
|
<!-- Kalau tidak ada kategori tertentu, tampilkan dropdown -->
|
||||||
<!-- Nama Fitur -->
|
<div>
|
||||||
|
<label class="block text-sm font-medium">Kategori Fitur</label>
|
||||||
|
<select name="kategori_fitur_id" class="w-full p-2 border rounded">
|
||||||
|
<option value="">-- Pilih Kategori --</option>
|
||||||
|
@foreach(\App\Models\KategoriFitur::all() as $kategori)
|
||||||
|
<option value="{{ $kategori->id }}">{{ $kategori->deskripsi }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{-- Nama Fitur --}}
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium">Nama Fitur</label>
|
<label class="block text-sm font-medium">Nama Fitur</label>
|
||||||
<input type="text" name="deskripsi" class="w-full p-2 border rounded" required>
|
<input type="text" name="deskripsi" class="w-full p-2 border rounded" required>
|
||||||
</div>
|
</div>
|
||||||
<!-- Harga -->
|
|
||||||
|
{{-- Harga --}}
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium">Harga</label>
|
<label class="block text-sm font-medium">Harga</label>
|
||||||
<input type="number" name="harga" step="100" min="0" class="w-full p-2 border rounded" required>
|
<input type="number" name="harga" step="100" min="0" class="w-full p-2 border rounded" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4 border-t flex justify-end space-x-2">
|
<div class="p-4 border-t flex justify-end space-x-2">
|
||||||
<button type="button" id="closeTambahBtn"
|
<button type="button" id="closeTambahBtn"
|
||||||
class="bg-gray-300 text-black px-3 py-1 rounded">Batal</button>
|
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>
|
<button class="bg-blue-600 text-white px-3 py-1 rounded">Simpan</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -199,35 +212,48 @@
|
|||||||
<h5 class="text-lg font-medium">Edit Fitur</h5>
|
<h5 class="text-lg font-medium">Edit Fitur</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4 space-y-4">
|
<div class="p-4 space-y-4">
|
||||||
<!-- Kategori -->
|
|
||||||
<div>
|
{{-- Kategori --}}
|
||||||
<label class="block text-sm font-medium">Kategori Fitur</label>
|
@if($kategori_fitur ?? false)
|
||||||
<select name="kategori_fitur_id" class="w-full p-2 border rounded" required>
|
<!-- Jika controller mengirim $kategori_fitur -->
|
||||||
<option value="">-- Pilih Kategori --</option>
|
<input type="hidden" name="kategori_fitur_id" value="{{ optional($kategori_fitur ?? null)->id }}">
|
||||||
@foreach(\App\Models\KategoriFitur::all() as $kategori)
|
<p class="text-sm text-gray-600">
|
||||||
<option value="{{ $kategori->id }}"
|
Kategori: <strong>{{ optional($kategori_fitur ?? null)->deskripsi }}</strong>
|
||||||
{{ $item->kategori_fitur_id == $kategori->id ? 'selected' : '' }}>
|
</p>
|
||||||
{{ $kategori->deskripsi }}
|
@else
|
||||||
</option>
|
<!-- Kalau tidak ada kategori tertentu, tampilkan dropdown -->
|
||||||
@endforeach
|
<div>
|
||||||
</select>
|
<label class="block text-sm font-medium">Kategori Fitur</label>
|
||||||
</div>
|
<select name="kategori_fitur_id" class="w-full p-2 border rounded">
|
||||||
<!-- Nama Fitur -->
|
<option value="">-- Pilih Kategori --</option>
|
||||||
|
@foreach(\App\Models\KategoriFitur::all() as $kategori)
|
||||||
|
<option value="{{ $kategori->id }}"
|
||||||
|
{{ $item->kategori_fitur_id == $kategori->id ? 'selected' : '' }}>
|
||||||
|
{{ $kategori->deskripsi }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{-- Nama Fitur --}}
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium">Nama Fitur</label>
|
<label class="block text-sm font-medium">Nama Fitur</label>
|
||||||
<input type="text" name="deskripsi" value="{{ $item->deskripsi }}"
|
<input type="text" name="deskripsi" value="{{ $item->deskripsi }}"
|
||||||
class="w-full p-2 border rounded" required>
|
class="w-full p-2 border rounded" required>
|
||||||
</div>
|
</div>
|
||||||
<!-- Harga -->
|
|
||||||
|
{{-- Harga --}}
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium">Harga</label>
|
<label class="block text-sm font-medium">Harga</label>
|
||||||
<input type="number" name="harga" value="{{ $item->harga }}"
|
<input type="number" name="harga" value="{{ $item->harga }}"
|
||||||
step="100" min="0" class="w-full p-2 border rounded" required>
|
step="100" min="0" class="w-full p-2 border rounded" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4 border-t flex justify-end space-x-2">
|
<div class="p-4 border-t flex justify-end space-x-2">
|
||||||
<button type="button" class="bg-gray-300 text-black px-3 py-1 rounded closeEditBtn"
|
<button type="button" class="bg-gray-300 text-black px-3 py-1 rounded closeEditBtn"
|
||||||
data-id="{{ $item->id }}">Batal</button>
|
data-id="{{ $item->id }}">Batal</button>
|
||||||
<button class="bg-blue-600 text-white px-3 py-1 rounded">Simpan Perubahan</button>
|
<button class="bg-blue-600 text-white px-3 py-1 rounded">Simpan Perubahan</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -236,6 +262,7 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Modal Hapus -->
|
<!-- Modal Hapus -->
|
||||||
@foreach ($fitur as $item)
|
@foreach ($fitur as $item)
|
||||||
<div id="modalDelete{{ $item->id }}" class="fixed inset-0 hidden items-center justify-center z-50">
|
<div id="modalDelete{{ $item->id }}" class="fixed inset-0 hidden items-center justify-center z-50">
|
||||||
|
|||||||
@ -204,150 +204,223 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
||||||
<!-- Modal Tambah Template -->
|
<!-- Modal Tambah Template -->
|
||||||
@if (!isset($kategori))
|
@if (!isset($kategori))
|
||||||
<div id="modalTambah" class="fixed inset-0 hidden items-center justify-center z-50">
|
<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="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 overflow-hidden">
|
<div class="bg-white rounded-lg shadow-lg w-full max-w-md z-50 overflow-hidden">
|
||||||
<form action="{{ route('templates.store') }}" method="POST" enctype="multipart/form-data">
|
<form action="{{ route('templates.store') }}" method="POST" enctype="multipart/form-data">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="p-4 border-b">
|
<div class="p-4 border-b">
|
||||||
<h5 class="text-lg font-medium">Tambah Template</h5>
|
<h5 class="text-lg font-medium">Tambah Template</h5>
|
||||||
</div>
|
|
||||||
<div class="p-4 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" class="w-full p-2 border rounded" required>
|
|
||||||
@foreach ($kategoris as $kategoriItem)
|
|
||||||
<option value="{{ $kategoriItem->id }}" @selected(old('kategori_id') == $kategoriItem->id)>
|
|
||||||
{{ $kategoriItem->nama }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- CHECKBOX FITUR -->
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium">Fitur</label>
|
|
||||||
<div
|
|
||||||
class="grid grid-cols-1 sm:grid-cols-2 gap-2 max-h-48 overflow-auto p-2 border rounded">
|
|
||||||
@foreach ($fiturs 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')) ? 'checked' : '' }}>
|
|
||||||
<span class="text-sm">
|
|
||||||
{{ \Illuminate\Support\Str::limit($fitur->deskripsi, 80) }}
|
|
||||||
(Rp {{ number_format($fitur->harga,0,',','.') }})
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium">Harga</label>
|
|
||||||
<input type="text" name="harga" class="w-full p-2 border rounded" required
|
|
||||||
min="0" value="{{ old('harga') }}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium">Foto (opsional)</label>
|
|
||||||
<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>
|
|
||||||
<div class="p-4 border-t flex justify-end space-x-2">
|
|
||||||
<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 class="p-4 space-y-4">
|
||||||
@endif
|
<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>
|
||||||
|
|
||||||
<!-- Modal Edit Template -->
|
<!-- FITUR -->
|
||||||
@foreach ($templates as $template)
|
<div>
|
||||||
<div id="modalEdit{{ $template->id }}" class="fixed inset-0 hidden items-center justify-center z-50">
|
<label class="block text-sm font-medium">Fitur</label>
|
||||||
<div class="absolute inset-0 bg-black opacity-50 closeEditOverlay" data-id="{{ $template->id }}"></div>
|
<div id="fiturContainerTambah"
|
||||||
<div class="bg-white rounded-lg shadow-lg w-full max-w-md z-50 overflow-hidden">
|
class="space-y-3 max-h-64 overflow-auto p-2 border rounded">
|
||||||
<form action="{{ route('templates.update', $template->id) }}" method="POST"
|
|
||||||
enctype="multipart/form-data">
|
|
||||||
@csrf @method('PUT')
|
|
||||||
<div class="p-4 border-b">
|
|
||||||
<h5 class="text-lg font-medium">Edit Template</h5>
|
|
||||||
</div>
|
|
||||||
<div class="p-4 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" class="w-full p-2 border rounded" required>
|
|
||||||
@foreach ($kategoris as $kategoriItem)
|
|
||||||
<option value="{{ $kategoriItem->id }}" @selected($kategoriItem->id == old('kategori_id', $template->kategori_id))>
|
|
||||||
{{ $kategoriItem->nama }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- EDIT: checkbox fitur dengan checked state -->
|
{{-- Fitur dengan kategori → radio --}}
|
||||||
<div>
|
@foreach ($kategoriFiturs as $kategoriFitur)
|
||||||
<label class="block text-sm font-medium">Fitur</label>
|
<div>
|
||||||
<div
|
<p class="font-semibold text-gray-700 mb-1">
|
||||||
class="grid grid-cols-1 sm:grid-cols-2 gap-2 max-h-48 overflow-auto p-2 border rounded">
|
{{ $kategoriFitur->deskripsi }}
|
||||||
@foreach ($fiturs as $fiturItem)
|
</p>
|
||||||
<label class="flex items-center space-x-2">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||||
<input type="checkbox" name="fitur_id[]" value="{{ $fiturItem->id }}"
|
@foreach ($fiturs->where('kategori_fitur_id', $kategoriFitur->id) as $fitur)
|
||||||
data-harga="{{ $fiturItem->harga }}"
|
<label class="flex items-center space-x-2">
|
||||||
{{ (is_array(old('fitur_id')) ? in_array($fiturItem->id, old('fitur_id')) : $template->fiturs->contains($fiturItem->id)) ? 'checked' : '' }}>
|
<input type="radio"
|
||||||
<span class="text-sm">
|
name="fitur_id[{{ $kategoriFitur->id }}]"
|
||||||
{{ \Illuminate\Support\Str::limit($fiturItem->deskripsi, 80) }}
|
value="{{ $fitur->id }}"
|
||||||
(Rp {{ number_format($fiturItem->harga,0,',','.') }})
|
data-harga="{{ $fitur->harga }}"
|
||||||
</span>
|
@checked(old("fitur_id.$kategoriFitur->id") == $fitur->id)>
|
||||||
</label>
|
<span class="text-sm">
|
||||||
@endforeach
|
{{ \Illuminate\Support\Str::limit($fitur->deskripsi, 80) }}
|
||||||
</div>
|
(Rp {{ number_format($fitur->harga, 0, ',', '.') }})
|
||||||
</div>
|
</span>
|
||||||
|
</label>
|
||||||
<div>
|
@endforeach
|
||||||
<label class="block text-sm font-medium">Harga</label>
|
|
||||||
<input type="number" 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>
|
||||||
@endif
|
</div>
|
||||||
<input type="file" name="foto" class="w-full p-2 border rounded" accept="image/*">
|
@endforeach
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="p-4 border-t flex justify-end space-x-2">
|
|
||||||
<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>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
|
|
||||||
<script>
|
{{-- Fitur tanpa kategori → checkbox --}}
|
||||||
|
@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')) ? '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" class="w-full p-2 border rounded" required
|
||||||
|
min="0" value="{{ old('harga') }}">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium">Foto (opsional)</label>
|
||||||
|
<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>
|
||||||
|
<div class="p-4 border-t flex justify-end space-x-2">
|
||||||
|
<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>
|
||||||
|
@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 overflow-hidden">
|
||||||
|
<form action="{{ route('templates.update', $template->id) }}" method="POST"
|
||||||
|
enctype="multipart/form-data">
|
||||||
|
@csrf @method('PUT')
|
||||||
|
<div class="p-4 border-b">
|
||||||
|
<h5 class="text-lg font-medium">Edit Template</h5>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 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">
|
||||||
|
|
||||||
|
{{-- Fitur dengan kategori → radio --}}
|
||||||
|
@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
|
||||||
|
|
||||||
|
{{-- Fitur tanpa kategori → checkbox --}}
|
||||||
|
@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="number" 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>
|
||||||
|
<div class="p-4 border-t flex justify-end space-x-2">
|
||||||
|
<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>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
// =========================
|
// =========================
|
||||||
// Modal Tambah
|
// Modal Tambah
|
||||||
@ -448,67 +521,84 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// Fitur: Hitung Harga Otomatis + Format ribuan
|
// Fitur: Hitung Harga Otomatis + Format ribuan
|
||||||
// =========================
|
// =========================
|
||||||
function formatRibuan(x) {
|
function formatRibuan(x) {
|
||||||
if (!x) return '';
|
if (!x) return '';
|
||||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
||||||
}
|
|
||||||
|
|
||||||
function hitungHarga(container) {
|
|
||||||
let total = 0;
|
|
||||||
container.querySelectorAll('input[name="fitur_id[]"]:checked').forEach(cb => {
|
|
||||||
total += parseInt(cb.dataset.harga) || 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
const inputHarga = container.querySelector('input[name="harga"]');
|
|
||||||
if (inputHarga && !inputHarga.dataset.manual) {
|
|
||||||
inputHarga.value = formatRibuan(total);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Update input text agar bisa ketik manual dengan format ribuan
|
function hitungHarga(container) {
|
||||||
document.querySelectorAll('.harga-input').forEach(input => {
|
let total = 0;
|
||||||
input.addEventListener('input', (e) => {
|
|
||||||
let value = e.target.value.replace(/\D/g, ''); // hanya angka
|
// Hitung checkbox (fitur tanpa kategori)
|
||||||
e.target.value = formatRibuan(value);
|
container.querySelectorAll('input[type="checkbox"][name="fitur_id[]"]:checked')
|
||||||
e.target.dataset.manual = "true"; // kasih flag manual
|
.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
|
// Modal Tambah
|
||||||
if (modalTambah) {
|
if (modalTambah) {
|
||||||
const checkboxes = modalTambah.querySelectorAll('input[name="fitur_id[]"]');
|
const inputs = modalTambah.querySelectorAll('input[name="fitur_id[]"], input[type="radio"]');
|
||||||
const inputHarga = modalTambah.querySelector('input[name="harga"]');
|
const inputHarga = modalTambah.querySelector('input[name="harga"]');
|
||||||
|
|
||||||
checkboxes.forEach(cb => {
|
inputs.forEach(input => {
|
||||||
cb.addEventListener('change', () => hitungHarga(modalTambah));
|
input.addEventListener('change', () => hitungHarga(modalTambah));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (inputHarga) {
|
if (inputHarga) {
|
||||||
inputHarga.addEventListener('input', () => {
|
inputHarga.addEventListener('input', () => {
|
||||||
inputHarga.dataset.manual = "true"; // kasih flag manual
|
inputHarga.dataset.manual = "true";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hitung awal kalau ada yang sudah tercentang
|
||||||
|
hitungHarga(modalTambah);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modal Edit (banyak, sesuai ID template)
|
// Modal Edit (banyak)
|
||||||
document.querySelectorAll('[id^="modalEdit"]').forEach(modal => {
|
document.querySelectorAll('[id^="modalEdit"]').forEach(modal => {
|
||||||
const checkboxes = modal.querySelectorAll('input[name="fitur_id[]"]');
|
const inputs = modal.querySelectorAll('input[name="fitur_id[]"], input[type="radio"]');
|
||||||
const inputHarga = modal.querySelector('input[name="harga"]');
|
const inputHarga = modal.querySelector('input[name="harga"]');
|
||||||
|
|
||||||
checkboxes.forEach(cb => {
|
inputs.forEach(input => {
|
||||||
cb.addEventListener('change', () => hitungHarga(modal));
|
input.addEventListener('change', () => hitungHarga(modal));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (inputHarga) {
|
if (inputHarga) {
|
||||||
inputHarga.addEventListener('input', () => {
|
inputHarga.addEventListener('input', () => {
|
||||||
inputHarga.dataset.manual = "true"; // kasih flag manual
|
inputHarga.dataset.manual = "true";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hitung awal kalau ada yang sudah tercentang
|
||||||
|
hitungHarga(modal);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user