add logic in foto controller and paket foto section for crud paket foto

This commit is contained in:
LailaWulandarii 2025-12-27 18:15:35 +07:00
parent 42c6961eb2
commit f9eb2397af
6 changed files with 422 additions and 288 deletions

View File

@ -3,7 +3,12 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Additional;
use App\Models\PaketFoto;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\File;
class FotoController extends Controller
{
@ -12,54 +17,132 @@ class FotoController extends Controller
*/
public function index()
{
return view('admin.paket-foto');
$foto = PaketFoto::latest()->get();
$additional = Additional::latest()->get();
// Kirim keduanya ke view paket-foto.index
return view('admin.paket-foto.index', compact('foto', 'additional'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
$validator = Validator::make($request->all(), [
'nama' => 'required|string|min:3|max:100',
'harga' => 'required|numeric|min:0',
'durasi' => 'required|integer|min:1',
'deskripsi' => 'required|string|min:10',
'foto' => 'required|image|mimes:jpeg,png,jpg|max:2048',
], [
'required' => 'Kolom :attribute wajib diisi.',
'string' => 'Input :attribute harus berupa teks valid.',
'integer' => 'Input :attribute harus berupa angka valid.',
'max' => ':attribute melebihi batas, maksimal :max karakter/KB.',
'image' => ':attribute harus berupa file gambar (foto).',
'mimes' => 'Format :attribute tidak didukung. Gunakan format: jpeg, png, atau jpg.',
'max.file' => 'Ukuran :attribute maksimal 2MB.',
'min' => ':attribute minimal harus :min karakter/nilai.',
'numeric' => ':attribute harus berupa angka.',
], [
'nama' => 'nama paket',
'harga' => 'harga paket',
'durasi' => 'durasi paket',
'foto' => 'foto paket',
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput()
->with('error_modal', 'createFoto'); // Agar modal terbuka otomatis saat error
}
$path = null;
if ($request->hasFile('foto')) {
$file = $request->file('foto');
$filename = time() . '_' . $file->getClientOriginalName();
// Simpan langsung ke folder public untuk asset()
$file->move(public_path('img/foto'), $filename);
$path = 'img/foto/' . $filename;
}
PaketFoto::create([
'nama' => $request->nama,
'harga' => $request->harga,
'durasi' => $request->durasi,
'deskripsi' => $request->deskripsi,
'foto' => $path,
]);
return redirect()->back()->with('success', 'Paket foto baru berhasil ditambahkan!');
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
$paket = PaketFoto::findOrFail($id);
$validator = Validator::make($request->all(), [
'nama' => 'required|string|min:3|max:100',
'harga' => 'required|numeric|min:0',
'durasi' => 'required|integer|min:1',
'deskripsi' => 'required|string|min:10',
'foto' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
], [
'required' => 'Kolom :attribute wajib diisi.',
'string' => 'Input :attribute harus berupa teks valid.',
'integer' => 'Input :attribute harus berupa angka valid.',
'max' => ':attribute melebihi batas, maksimal :max karakter/KB.',
'image' => ':attribute harus berupa file gambar (foto).',
'mimes' => 'Format :attribute tidak didukung. Gunakan format: jpeg, png, atau jpg.',
'max.file' => 'Ukuran :attribute maksimal 2MB.',
'min' => ':attribute minimal harus :min karakter/nilai.',
'numeric' => ':attribute harus berupa angka.',
], [
'nama' => 'nama paket',
'harga' => 'harga paket',
'durasi' => 'durasi paket',
'foto' => 'foto paket',
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput()
->with('error_id', $id); // Membuka modal edit yang error otomatis
}
$data = $request->only(['nama', 'harga', 'durasi', 'deskripsi']);
if ($request->hasFile('foto')) {
// Hapus file lama jika ada foto baru yang diunggah
if ($paket->foto && File::exists(public_path($paket->foto))) {
File::delete(public_path($paket->foto));
}
$file = $request->file('foto');
$filename = time() . '_' . $file->getClientOriginalName();
$file->move(public_path('img/foto'), $filename);
$data['foto'] = 'img/foto/' . $filename;
}
$paket->update($data);
return redirect()->back()->with('success', 'Paket foto berhasil diperbarui!');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
// Cari data berdasarkan primary key id_paket
$paket = PaketFoto::where('id_paket', $id)->firstOrFail();
// 1. Cek dan hapus file foto dari folder public
if ($paket->foto && File::exists(public_path($paket->foto))) {
File::delete(public_path($paket->foto));
}
// 2. Hapus data dari database
$paket->delete();
return redirect()->back()->with('success', 'Paket foto dan filenya berhasil dihapus!');
}
}

View File

@ -3,6 +3,21 @@
@section('title', 'Paket Foto')
@section('content')
{{-- ALERT SUKSES --}}
@if (session('success'))
<div class="alert alert-success alert-dismissible fade show" role="alert">
{{ session('success') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
{{-- ALERT ERROR UMUM (Jika ada error selain validasi modal) --}}
@if (session('error'))
<div class="alert alert-danger alert-dismissible fade show" role="alert">
{{ session('error') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<section class="section">
<div class="d-flex gap-2 pb-3">
@ -39,36 +54,54 @@
<table class="table table-striped" id="table1">
<thead>
<tr>
<th>No.</th>
<th>Nama Paket</th>
<th>Deskripsi</th>
<th>Harga</th>
<th>Foto</th>
<th class="text-center">Aksi</th>
<th style="width: 5%" class="text-center">No.</th>
<th style="width: 20%">Nama Paket</th>
<th style="width: 35%">Deskripsi</th>
<th style="width: 15%" class="text-nowrap">Harga</th>
<th style="width: 10%" class="text-center">Foto</th>
<th style="width: 15%" class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
<tr>
<td>Graiden</td>
<td>vehicula.aliquet@semconsequat.co.uk</td>
<td>076 4820 8838</td>
<td>Offenburg</td>
<td>Offenburg</td>
<td class="col-auto text-center">
<a href="#" class="btn icon btn-primary btn-action" data-bs-toggle="modal"
data-bs-target="#foto">
<i class="bi bi-eye"></i>
</a>
<a href="#" class="btn icon btn-warning btn-action" data-bs-toggle="modal"
data-bs-target="#editFoto">
<i class="bi bi-pencil"></i>
</a>
<a href="#" class="btn icon btn-danger btn-action" data-bs-toggle="modal"
data-bs-target="#deleteFoto">
<i class="bi bi-trash"></i>
</a>
</td>
</tr>
@forelse ($foto as $f)
<tr>
<td style="width: 5%" class="text-center">{{ $loop->iteration }}</td>
<td style="width: 20%">{{ $f->nama }}</td>
<td style="width: 35%">{{ Str::limit($f->deskripsi, 50) }}</td>
<td style="width: 15%">Rp {{ number_format($f->harga, 0, ',', '.') }}</td>
<td style="width:10%" class="text-center">
<img src="{{ asset($f->foto) }}" alt="Foto Produk" class="rounded"
style="width: 50px; height: 50px; object-fit: cover;">
</td>
<td class="col-auto text-center" style="width: 15%">
<a href="#" class="btn icon btn-primary btn-action" data-bs-toggle="modal"
data-bs-target="#foto{{ $f->id_paket }}">
<i class="bi bi-eye"></i>
</a>
<a href="#" class="btn icon btn-warning btn-action" data-bs-toggle="modal"
data-bs-target="#editFoto{{ $f->id_paket }}">
<i class="bi bi-pencil"></i>
</a>
<a href="#" class="btn icon btn-danger btn-action" data-bs-toggle="modal"
data-bs-target="#deleteFoto{{ $f->id_paket }}">
<i class="bi bi-trash"></i>
</a>
</td>
</tr>
@include('admin.paket-foto.partials.modal-show-foto')
@include('admin.paket-foto.partials.modal-edit-foto')
@include('admin.paket-foto.partials.modal-delete-foto')
@empty
<tr>
<td colspan="6" class="text-center p-4">
<div class="alert alert-light-secondary color-secondary">
<i class="bi bi-exclamation-circle"></i> Belum ada data paket foto.
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@ -77,28 +110,44 @@
<table class="table table-striped" id="riwayat-foto">
<thead>
<tr>
<th>No.</th>
<th>Nama Additional</th>
<th>Harga</th>
<th class="text-center">Aksi</th>
<th style="width: 5%">No.</th>
<th style="width: 65%">Nama Additional</th>
<th style="width: 15%" class="text-nowrap">Harga</th>
<th style="width: 15%" class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
<tr>
<td>Graiden</td>
<td>vehicula.aliquet@semconsequat.co.uk</td>
<td>076 4820 8838</td>
<td class="col-auto text-center">
<a href="#" class="btn icon btn-warning btn-action" data-bs-toggle="modal"
data-bs-target="#editAdd">
<i class="bi bi-pencil"></i>
</a>
<a href="#" class="btn icon btn-danger btn-action" data-bs-toggle="modal"
data-bs-target="#deleteAdd">
<i class="bi bi-trash"></i>
</a>
</td>
</tr>
@forelse ($additional as $ad)
<tr>
<td style="width: 5%">{{ $loop->iteration }}</td>
<td style="width: 65%">{{ $ad->nama }}</td>
<td style="width: 15%">Rp {{ number_format($ad->harga, 0, ',', '.') }}</td>
<td class="col-auto text-center" style="width: 15%">
<a href="#" class="btn icon btn-warning btn-action"
data-bs-toggle="modal"
data-bs-target="#editFoto{{ $ad->id_additional }}">
<i class="bi bi-pencil"></i>
</a>
<a href="#" class="btn icon btn-danger btn-action"
data-bs-toggle="modal"
data-bs-target="#deleteFoto{{ $ad->id_additional }}">
<i class="bi bi-trash"></i>
</a>
</td>
</tr>
{{-- @include('admin.produk-buket.partials.modal-show')
@include('admin.produk-buket.partials.modal-edit')
@include('admin.produk-buket.partials.modal-delete') --}}
@empty
<tr>
<td colspan="6" class="text-center p-4">
<div class="alert alert-light-secondary color-secondary">
<i class="bi bi-exclamation-circle"></i> Belum ada data additional.
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@ -115,5 +164,60 @@
@include('admin.paket-foto.partials.modal-create-additional')
@include('admin.paket-foto.partials.modal-edit-additional')
@include('admin.paket-foto.partials.modal-delete-additional')
@push('scripts')
<script>
// FUNGSI PREVIEW UNIVERSAL (Bisa untuk Create & Edit)
function previewImage(input, previewId, placeholderId) {
const preview = document.getElementById(previewId);
const placeholder = document.getElementById(placeholderId);
const file = input.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
preview.src = e.target.result;
preview.classList.remove('d-none');
if (placeholder) placeholder.classList.add('d-none');
}
reader.readAsDataURL(file);
}
}
document.addEventListener('DOMContentLoaded', function() {
function clearBackdrop() {
const backdrops = document.querySelectorAll('.modal-backdrop');
backdrops.forEach(b => b.remove());
document.body.classList.remove('modal-open');
document.body.style.paddingRight = '';
}
// Logic Modal Error tetap sama seperti milikmu
@if (session('error_modal'))
clearBackdrop();
var modalId = "{{ session('error_modal') }}";
var targetElement = document.getElementById(modalId);
if (targetElement) {
new bootstrap.Modal(targetElement).show();
}
@endif
@if (session('error_id'))
clearBackdrop();
var errorId = "{{ session('error_id') }}";
var editModalId = document.getElementById("editFoto" + errorId) ? "editFoto" + errorId : "editAdd" +
errorId;
var targetEdit = document.getElementById(editModalId);
if (targetEdit) {
new bootstrap.Modal(targetEdit).show();
}
@endif
});
function showImage(src) {
var modalImg = document.getElementById('img-preview-target');
modalImg.src = src;
new bootstrap.Modal(document.getElementById('modalImagePreview')).show();
}
</script>
@endpush
@endsection

View File

@ -1,32 +1,40 @@
<div class="modal fade" id="createFoto" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-md">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Tambah Paket Foto</h5> <button type="button" class="btn-close"
data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="#" method="POST" enctype="multipart/form-data">
<div class="modal-body">
<div class="modal-body">
<form action="{{ route('admin.paket-foto.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="row gx-3">
<div class="col-12 col-md-7">
<div class="mb-2">
<label class="form-label">Nama Paket</label>
<input type="text" class="form-control" style="font-size: 13px;"
placeholder="Masukkan Nama Paket">
<input type="text" class="form-control @error('nama') is-invalid @enderror"
style="font-size: 14px;" placeholder="Masukkan Nama Paket"
value="{{ old('nama') }}">
@error('nama')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="row gx-1">
<div class="col-12 col-md-6">
<div class="mb-2">
<label class="form-label">Harga Paket</label>
<input type="number" class="form-control" style="font-size: 13px;"
placeholder="Harga Paket">
<input type="number" class="form-control @error('nama') is-invalid @enderror"
style="font-size: 14px;"
placeholder="Harga Paket"value="{{ old('nama') }}">
<p class="mb-0"><small class="text-muted mb-0">Dalam Rupiah</small>
</p>
@error('nama')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
@ -34,95 +42,82 @@
<div class="col-12 col-md-6">
<div class="mb-2">
<label class="form-label">Durasi</label>
<input type="number" class="form-control" style="font-size: 13px;"
placeholder="Durasi Paket">
<input type="number" class="form-control @error('nama') is-invalid @enderror"
style="font-size: 14px;"
placeholder="Durasi Paket"value="{{ old('nama') }}">
<p class="mb-0"><small class="text-muted mb-0">Dalam Menit</small>
</p>
@error('nama')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
</div>
<div class="mb-2">
<label class="form-label">Deskripsi Paket</label>
<textarea class="form-control" rows="4" style="font-size: 13px;" placeholder="Masukkan Deskripsi Paket"></textarea>
<textarea class="form-control @error('nama') is-invalid @enderror" rows="5" style="font-size: 14px;"
placeholder="Masukkan Deskripsi Paket">{{ old('deskripsi') }}</textarea>
@error('deskripsi')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</textarea>
</div>
</div>
<div class="col-12 col-md-5">
<div class="mb-3">
<label class="form-label">Upload Foto Buket</label>
<div class="mb-2">
<label class="form-label">Upload Foto Paket</label>
<div class="upload-area p-2 text-center d-flex flex-column align-items-center justify-content-center"
onclick="document.getElementById('fileInput').click()">
{{-- Area Upload Custom --}}
<div class="upload-area p-4 text-centerd d-flex flex-column align-items-center justify-content-center"
onclick="document.getElementById('createFotoInput').click()"
style="cursor: pointer;">
<i class="bi bi-file-earmark-arrow-up fs-5 text-secondary mb-3"></i>
<span class="fw-semibold text-dark">Upload Foto Paket</span>
<small class="text-muted">Max. 2 MB</small>
<span class="fw-semibold text-dark">Klik untuk Upload</span>
<small class="text-muted">Max 2MB (JPG/PNG)</small>
<input type="file" id="fileInput" class="d-none" name="foto">
{{-- Input File Tersembunyi (ID UNIK: createFotoInput) --}}
<input type="file" id="createFotoInput" class="d-none" name="foto"
accept="image/*"
onchange="previewImage(this, 'createImgPreview', 'createPlaceholder')">
</div>
@error('foto')
<div class="text-danger mt-1" style="font-size: 12px;">{{ $message }}</div>
@enderror
</div>
<div class="mb-2">
<label class="form-label">Preview Foto</label>
{{-- 7. Preview Foto (Fixed Container) --}}
<div class="mb-3">
<label class="form-label">Preview</label>
<div class="border rounded d-flex justify-content-center align-items-center position-relative overflow-hidden"
style="height: 120px; background-color: #f8f9fa;">
<div class="border rounded d-flex justify-content-center align-items-center position-relative"
style="height: 120px; background-color: #f8f9fa; overflow: hidden;">
<div id="placeholder-text" class="text-center text-muted">
<i class="bi bi-image fs-5 mb-2"></i>
<p class="mb-0 fw-medium" style="font-size: 0.65rem;">Gambarmu akan muncul
di
sini</p>
{{-- Placeholder Teks (ID UNIK: createPlaceholder) --}}
<div id="createPlaceholder" class="text-center text-muted">
<i class="bi bi-image fs-4"></i>
<p class="mb-0" style="font-size: 12px;">Belum ada foto dipilih</p>
</div>
<img id="img-preview" src="#" class="img-fluid w-100 h-100 d-none"
style="object-fit: cover; position: absolute; top: 0; left: 0;">
{{-- Gambar Preview (ID UNIK: createImgPreview) --}}
<img id="createImgPreview" src="#" class="d-none w-100 h-100"
style="object-fit: contain;">
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer justify-content-end border-top-0 pt-0">
<button type="submit" class="btn btn-primary rounded-pill terima px-3 py-2">
Simpan
</button>
</div>
</form>
<div class="modal-footer justify-content-end border-top-0 pt-0">
<button type="submit" class="btn btn-primary rounded-pill terima px-3 py-2">
Simpan
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
// Target elemen berdasarkan ID
const fileInput = document.getElementById('fileInput');
const imgPreview = document.getElementById('img-preview');
const placeholder = document.getElementById('placeholder-text');
fileInput.addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
// Jika ada file, baca gambarnya
const reader = new FileReader();
reader.onload = function(e) {
imgPreview.src = e.target.result; // Masukkan data gambar
// TUKAR TAMPILAN:
imgPreview.classList.remove('d-none'); // Munculkan gambar
placeholder.classList.add('d-none'); // Sembunyikan teks
}
reader.readAsDataURL(file);
} else {
// Jika user membatalkan upload (cancel), reset ke awal
imgPreview.src = "#";
imgPreview.classList.add('d-none');
placeholder.classList.remove('d-none');
}
});
</script>

View File

@ -1,15 +1,17 @@
<div class="modal fade" id="deleteFoto" tabindex="-1" aria-hidden="true">
<div class="modal fade" id="deleteFoto{{ $f->id_paket }}" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered ">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Hapus Paket Foto</h5> <button type="button" class="btn-close"
<h5 class="modal-title">Hapus {{ $f->nama }}</h5> <button type="button" class="btn-close"
data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="#" method="POST" enctype="multipart/form-data">
<form action="{{ route('admin.paket-foto.destroy', $f->id_paket) }}" method="POST">
@csrf
@method('DELETE')
<div class="modal-body">
<p>Apakah anda yakin ingin menghapus nama paket?</p>
<p>Apakah anda yakin ingin menghapus {{ $f->nama }}?</p>
</div>
<div class="modal-footer justify-content-end border-top-0 pt-0">
<button type="submit" class="btn btn-danger rounded-pill tolak px-3 py-2">
@ -21,33 +23,3 @@
</div>
</div>
</div>
<script>
// Target elemen berdasarkan ID
const fileInput = document.getElementById('fileInput');
const imgPreview = document.getElementById('img-preview');
const placeholder = document.getElementById('placeholder-text');
fileInput.addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
// Jika ada file, baca gambarnya
const reader = new FileReader();
reader.onload = function(e) {
imgPreview.src = e.target.result; // Masukkan data gambar
// TUKAR TAMPILAN:
imgPreview.classList.remove('d-none'); // Munculkan gambar
placeholder.classList.add('d-none'); // Sembunyikan teks
}
reader.readAsDataURL(file);
} else {
// Jika user membatalkan upload (cancel), reset ke awal
imgPreview.src = "#";
imgPreview.classList.add('d-none');
placeholder.classList.remove('d-none');
}
});
</script>

View File

@ -1,14 +1,17 @@
<div class="modal fade" id="editFoto" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal fade" id="editFoto{{ $f->id_paket }}" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Paket Foto</h5> <button type="button" class="btn-close"
<h5 class="modal-title">Edit {{ $f->nama }}</h5> <button type="button" class="btn-close"
data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="#" method="POST" enctype="multipart/form-data">
<form action="{{ route('admin.paket-foto.update', $f->id_paket) }}" method="POST"
enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="modal-body">
<div class="row gx-3">
@ -16,53 +19,72 @@
<div class="mb-2">
<label class="form-label">Nama Paket</label>
<input type="text" class="form-control" style="font-size: 13px;"
placeholder="Masukkan Nama Paket">
<input type="text" name="nama"
class="form-control @error('nama') is-invalid @enderror" style="font-size: 14px;"
placeholder="Masukkan Nama Paket"value="{{ old('nama', $f->nama) }}">
@error('nama')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="row gx-1">
<div class="col-12 col-md-6">
<div class="mb-2">
<label class="form-label">Harga Paket</label>
<input type="number" class="form-control" style="font-size: 13px;"
placeholder="Harga Paket">
<input type="number" name="harga"
class="form-control @error('harga') is-invalid @enderror"
style="font-size: 14px;"
placeholder="Harga Paket"value="{{ old('harga', $f->harga) }}">
<p class="mb-0"><small class="text-muted mb-0">Dalam Rupiah</small>
</p>
@error('harga')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="mb-2">
<label class="form-label">Durasi</label>
<input type="number" class="form-control" style="font-size: 13px;"
placeholder="Durasi Paket">
<input type="number" name="durasi"
class="form-control @error('durasi') is-invalid @enderror"
style="font-size: 14px;"
placeholder="Durasi Paket"value="{{ old('durasi', $f->durasi) }}">
<p class="mb-0"><small class="text-muted mb-0">Dalam Menit</small>
</p>
@error('durasi')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
</div>
<div class="mb-2">
<label class="form-label">Deskripsi Paket</label>
<textarea class="form-control" rows="4" style="font-size: 13px;" placeholder="Masukkan Deskripsi Paket"></textarea>
<textarea class="form-control @error('deskripsi') is-invalid @enderror" rows="5" name="deskripsi"
style="font-size: 14px;" placeholder="Masukkan Deskripsi Paket"> {{ old('deskripsi', $f->deskripsi) }}</textarea>
@error('deskripsi')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
</div>
<div class="col-12 col-md-5">
<div class="mb-2">
<label class="form-label">Upload Foto Paket</label>
<div class="upload-area p-2 text-center d-flex flex-column align-items-center justify-content-center"
onclick="document.getElementById('fileInput').click()">
onclick="document.getElementById('editFotoInput{{ $f->id_paket }}').click()">
<i class="bi bi-file-earmark-arrow-up fs-5 text-secondary mb-3"></i>
<span class="fw-semibold text-dark">Upload Foto Paket</span>
<small class="text-muted">Max. 2 MB</small>
<input type="file" id="fileInput" class="d-none" name="foto">
<input type="file" id="editFotoInput{{ $f->id_paket }}" class="d-none"
name="foto" accept="image/*"
onchange="previewImage(this, 'editImgPreview{{ $f->id_paket }}', 'placeholder-edit-{{ $f->id_paket }}')">
</div>
@error('foto')
<div class="text-danger mt-1" style="font-size: 12px;">{{ $message }}</div>
@enderror
</div>
<div class="mb-2">
@ -71,15 +93,16 @@
<div class="border rounded d-flex justify-content-center align-items-center position-relative"
style="height: 120px; background-color: #f8f9fa; overflow: hidden;">
<div id="placeholder-text" class="text-center text-muted">
<div id="placeholder-edit-{{ $f->id_paket }}"
class="text-center text-muted d-none">
<i class="bi bi-image fs-5 mb-2"></i>
<p class="mb-0 fw-medium" style="font-size: 0.65rem;">Gambarmu akan muncul di
sini</p>
</div>
<img id="img-preview" src="#" class="img-fluid w-100 h-100 d-none"
<img id="editImgPreview{{ $f->id_paket }}" src="{{ asset($f->foto) }}"
class="img-fluid w-100 h-100"
style="object-fit: cover; position: absolute; top: 0; left: 0;">
</div>
</div>
@ -95,33 +118,3 @@
</div>
</div>
</div>
<script>
// Target elemen berdasarkan ID
const fileInput = document.getElementById('fileInput');
const imgPreview = document.getElementById('img-preview');
const placeholder = document.getElementById('placeholder-text');
fileInput.addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
// Jika ada file, baca gambarnya
const reader = new FileReader();
reader.onload = function(e) {
imgPreview.src = e.target.result; // Masukkan data gambar
// TUKAR TAMPILAN:
imgPreview.classList.remove('d-none'); // Munculkan gambar
placeholder.classList.add('d-none'); // Sembunyikan teks
}
reader.readAsDataURL(file);
} else {
// Jika user membatalkan upload (cancel), reset ke awal
imgPreview.src = "#";
imgPreview.classList.add('d-none');
placeholder.classList.remove('d-none');
}
});
</script>

View File

@ -1,29 +1,35 @@
<div class="modal fade" id="foto" tabindex="-1" aria-hidden="true">
<div class="modal fade" id="foto{{ $f->id_paket }}" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Detail Nama Paket Foto</h5> <button type="button" class="btn-close"
<h5 class="modal-title">Detail {{ $f->nama }}</h5> <button type="button" class="btn-close"
data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row gx-3">
<div class="col-12 col-md-4">
<div class="buket-img-wrapper text-align-center h-100"
onclick="showImage('{{ asset('img/invoice.jpg') }}')">
<img src="{{ asset('img/invoice.jpg') }}" class="proof-img">
</div>
<div class="col-12 col-sm-4">
@if ($f->foto)
{{-- Langsung img tanpa wrapper --}}
<img src="{{ asset($f->foto) }}" class="custom-img-box-foto"
onclick="showImage('{{ asset($f->foto) }}')">
@else
{{-- Div pengganti kalau tidak ada foto --}}
<div
class="custom-img-box-foto d-flex align-items-center justify-content-center text-muted">
<small>Tidak ada foto</small>
</div>
@endif
</div>
<div class="col-12 col-md-8">
<div class="col-12 col-sm-8">
<div class="detail-buket ps-md-3 h-100">
<div class="row mb-2">
<div class="col-4 col-sm-3">
<span class="detail-buket-label">Nama Paket</span>
</div>
<div class="col-8 col-sm-9">
<span class="detail-buket-value">Single</span>
<span class="detail-buket-value">{{ $f->nama }}</span>
</div>
</div>
@ -32,7 +38,16 @@
<span class="detail-buket-label">Harga Paket</span>
</div>
<div class="col-8 col-sm-9">
<span class="detail-buket-value">Rp 130.000</span>
<span class="detail-buket-value">Rp
{{ number_format($f->harga, 0, ',', '.') }}</span>
</div>
</div>
<div class="row mb-2">
<div class="col-4 col-sm-3">
<span class="detail-buket-label">Durasi Paket</span>
</div>
<div class="col-8 col-sm-9">
<span class="detail-buket-value">{{ $f->durasi }} Menit</span>
</div>
</div>
@ -42,21 +57,10 @@
</div>
<div class="col-8 col-sm-9">
<p class="detail-buket-value text-justify mb-0" style="line-height: 1.6;">
Untuk 1 menit
10 menit sesi foto sepuasnya
5 menit sesi pilih foto (jika ada yang diprint)
{{ $f->deskripsi }}
</p>
</div>
</div>
<div class="row mb-2">
<div class="col-4 col-sm-3">
<span class="detail-buket-label text-nowrap">Request Khusus</span>
</div>
<div class="col-8 col-sm-9">
<span class="detail-buket-value">Wrapping, Tone Warna</span>
</div>
</div>
</div>
</div>
</div>
@ -65,33 +69,16 @@
</div>
</div>
</div>
<script>
// Target elemen berdasarkan ID
const fileInput = document.getElementById('fileInput');
const imgPreview = document.getElementById('img-preview');
const placeholder = document.getElementById('placeholder-text');
fileInput.addEventListener('change', function(event) {
const file = event.target.files[0];
<div class="modal fade" id="modalImagePreview" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content bg-transparent border-0 shadow-none">
if (file) {
// Jika ada file, baca gambarnya
const reader = new FileReader();
<div class="modal-body p-0 text-center">
<img id="img-preview-target" src="" class="img-fluid rounded shadow-lg"
style="max-height: 85vh;">
</div>
reader.onload = function(e) {
imgPreview.src = e.target.result; // Masukkan data gambar
// TUKAR TAMPILAN:
imgPreview.classList.remove('d-none'); // Munculkan gambar
placeholder.classList.add('d-none'); // Sembunyikan teks
}
reader.readAsDataURL(file);
} else {
// Jika user membatalkan upload (cancel), reset ke awal
imgPreview.src = "#";
imgPreview.classList.add('d-none');
placeholder.classList.remove('d-none');
}
});
</script>
</div>
</div>
</div>