Merge branch 'baru' of https://git.abbauf.com/Magang-2025/Undangan into baru
This commit is contained in:
commit
1ef83feac9
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Review;
|
||||
|
||||
class ReviewApiController extends Controller
|
||||
{
|
||||
// Ambil semua ulasan (JSON)
|
||||
public function index()
|
||||
{
|
||||
$reviews = Review::latest()->get();
|
||||
|
||||
return response()->json($reviews, 200);
|
||||
}
|
||||
|
||||
// Simpan ulasan baru
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'rating' => 'required|integer|min:1|max:5',
|
||||
'message' => 'required|string',
|
||||
'name' => 'required|string|max:100',
|
||||
'city' => 'required|string|max:100',
|
||||
]);
|
||||
|
||||
$review = Review::create($validated);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Ulasan berhasil disimpan',
|
||||
'data' => $review,
|
||||
], 201);
|
||||
}
|
||||
|
||||
// Tampilkan ulasan tertentu
|
||||
public function show($id)
|
||||
{
|
||||
$review = Review::findOrFail($id);
|
||||
return response()->json($review, 200);
|
||||
}
|
||||
|
||||
// Hapus ulasan
|
||||
public function destroy($id)
|
||||
{
|
||||
$review = Review::findOrFail($id);
|
||||
$review->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Ulasan berhasil dihapus',
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
@ -3,35 +3,58 @@
|
||||
@section('title', 'Tambah Kategori')
|
||||
|
||||
@section('content')
|
||||
<div class="container mt-4">
|
||||
<h2 class="mb-3">Tambah Kategori</h2>
|
||||
<div class="container mx-auto py-8">
|
||||
<div class="max-w-2xl mx-auto bg-white shadow-md rounded-xl p-8 border border-blue-100">
|
||||
<h2 class="text-2xl font-semibold text-black mb-6">Tambah Kategori</h2>
|
||||
|
||||
<form action="{{ route('admin.kategori.store') }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<form action="{{ route('admin.kategori.store') }}" method="POST" enctype="multipart/form-data" class="space-y-5">
|
||||
@csrf
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="nama" class="form-label">Nama Kategori</label>
|
||||
<input type="text" class="form-control @error('nama') is-invalid @enderror"
|
||||
id="nama" name="nama" value="{{ old('nama') }}" required>
|
||||
@error('nama') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
<!-- Nama Kategori -->
|
||||
<div>
|
||||
<label for="nama" class="block text-sm font-medium text-gray-700 mb-2">Nama Kategori</label>
|
||||
<input type="text" id="nama" name="nama"
|
||||
value="{{ old('nama') }}"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none @error('nama') border-red-500 @enderror"
|
||||
placeholder="Masukkan nama kategori" required>
|
||||
@error('nama')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="deskripsi" class="form-label">Deskripsi</label>
|
||||
<textarea class="form-control @error('deskripsi') is-invalid @enderror"
|
||||
id="deskripsi" name="deskripsi">{{ old('deskripsi') }}</textarea>
|
||||
@error('deskripsi') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
<!-- Deskripsi -->
|
||||
<div>
|
||||
<label for="deskripsi" class="block text-sm font-medium text-gray-700 mb-2">Deskripsi</label>
|
||||
<textarea id="deskripsi" name="deskripsi" rows="4"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none @error('deskripsi') border-red-500 @enderror"
|
||||
placeholder="Tuliskan deskripsi kategori">{{ old('deskripsi') }}</textarea>
|
||||
@error('deskripsi')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="foto" class="form-label">Foto</label>
|
||||
<input type="file" class="form-control @error('foto') is-invalid @enderror"
|
||||
id="foto" name="foto">
|
||||
@error('foto') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
<!-- Foto -->
|
||||
<div>
|
||||
<label for="foto" class="block text-sm font-medium text-gray-700 mb-2">Foto</label>
|
||||
<input type="file" id="foto" name="foto"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-50 cursor-pointer focus:ring-2 focus:ring-blue-400 @error('foto') border-red-500 @enderror">
|
||||
@error('foto')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success">Simpan</button>
|
||||
<a href="{{ route('admin.kategori.index') }}" class="btn btn-secondary">Kembali</a>
|
||||
</form>
|
||||
<!-- Tombol -->
|
||||
<div class="flex justify-end gap-3 pt-4">
|
||||
<a href="{{ route('admin.kategori.index') }}"
|
||||
class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium px-5 py-2 rounded-lg transition duration-200">
|
||||
Kembali
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white font-medium px-6 py-2 rounded-lg shadow transition duration-200">
|
||||
Simpan
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@ -3,41 +3,64 @@
|
||||
@section('title', 'Edit Kategori')
|
||||
|
||||
@section('content')
|
||||
<div class="container mt-4">
|
||||
<h2 class="mb-3">Edit Kategori</h2>
|
||||
<div class="container mx-auto py-8">
|
||||
<div class="max-w-2xl mx-auto bg-white shadow-md rounded-xl p-8 border border-blue-100">
|
||||
<h2 class="text-2xl font-semibold text-black mb-6">Edit Kategori</h2>
|
||||
|
||||
<form action="{{ route('admin.kategori.update', $kategori->id) }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<form action="{{ route('admin.kategori.update', $kategori->id) }}" method="POST" enctype="multipart/form-data" class="space-y-5">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="nama" class="form-label">Nama Kategori</label>
|
||||
<input type="text" class="form-control @error('nama') is-invalid @enderror"
|
||||
id="nama" name="nama" value="{{ old('nama', $kategori->nama) }}" required>
|
||||
@error('nama') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
<!-- Nama Kategori -->
|
||||
<div>
|
||||
<label for="nama" class="block text-sm font-medium text-gray-700 mb-2">Nama Kategori</label>
|
||||
<input type="text" id="nama" name="nama"
|
||||
value="{{ old('nama', $kategori->nama) }}"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none @error('nama') border-red-500 @enderror"
|
||||
placeholder="Masukkan nama kategori" required>
|
||||
@error('nama')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="deskripsi" class="form-label">Deskripsi</label>
|
||||
<textarea class="form-control @error('deskripsi') is-invalid @enderror"
|
||||
id="deskripsi" name="deskripsi">{{ old('deskripsi', $kategori->deskripsi) }}</textarea>
|
||||
@error('deskripsi') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
<!-- Deskripsi -->
|
||||
<div>
|
||||
<label for="deskripsi" class="block text-sm font-medium text-gray-700 mb-2">Deskripsi</label>
|
||||
<textarea id="deskripsi" name="deskripsi" rows="4"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none @error('deskripsi') border-red-500 @enderror"
|
||||
placeholder="Tuliskan deskripsi kategori">{{ old('deskripsi', $kategori->deskripsi) }}</textarea>
|
||||
@error('deskripsi')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="foto" class="form-label">Foto</label>
|
||||
@if($kategori->foto)
|
||||
<div class="mb-2">
|
||||
<img src="{{ asset('storage/'.$kategori->foto) }}" width="100" class="img-thumbnail">
|
||||
</div>
|
||||
@endif
|
||||
<input type="file" class="form-control @error('foto') is-invalid @enderror"
|
||||
id="foto" name="foto">
|
||||
@error('foto') <div class="invalid-feedback">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
<!-- Foto -->
|
||||
<div>
|
||||
<label for="foto" class="block text-sm font-medium text-gray-700 mb-2">Foto</label>
|
||||
@if($kategori->foto)
|
||||
<div class="mb-3">
|
||||
<img src="{{ asset('storage/'.$kategori->foto) }}" alt="Foto Kategori" class="w-32 h-32 object-cover rounded-lg border border-gray-200">
|
||||
</div>
|
||||
@endif
|
||||
<input type="file" id="foto" name="foto"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-50 cursor-pointer focus:ring-2 focus:ring-blue-400 @error('foto') border-red-500 @enderror">
|
||||
@error('foto')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
<a href="{{ route('admin.kategori.index') }}" class="btn btn-secondary">Kembali</a>
|
||||
</form>
|
||||
<!-- Tombol -->
|
||||
<div class="flex justify-end gap-3 pt-4">
|
||||
<a href="{{ route('admin.kategori.index') }}"
|
||||
class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium px-5 py-2 rounded-lg transition duration-200">
|
||||
Kembali
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white font-medium px-6 py-2 rounded-lg shadow transition duration-200">
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@ -3,44 +3,67 @@
|
||||
@section('title', 'Buat Pesanan')
|
||||
|
||||
@section('content')
|
||||
<div class="container mt-4">
|
||||
<h2 class="mb-3">Buat Pesanan</h2>
|
||||
<div class="container mx-auto py-8">
|
||||
<div class="max-w-2xl mx-auto bg-white shadow-md rounded-xl p-8 border border-blue-100">
|
||||
<h2 class="text-2xl font-semibold text-black mb-6">Buat Pesanan</h2>
|
||||
|
||||
<form action="{{ route('pelanggans.store') }}" method="POST">
|
||||
@csrf
|
||||
<form action="{{ route('pelanggans.store') }}" method="POST" class="space-y-5">
|
||||
@csrf
|
||||
|
||||
<div class="mb-3">
|
||||
<label>Nama Pemesan</label>
|
||||
<input type="text" name="nama_pemesan" class="form-control" value="{{ old('nama_pemesan') }}" required>
|
||||
</div>
|
||||
<!-- Nama Pemesan -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Nama Pemesan</label>
|
||||
<input type="text" name="nama_pemesan"
|
||||
value="{{ old('nama_pemesan') }}"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label>Email</label>
|
||||
<input type="email" name="email" class="form-control" value="{{ old('email') }}" required>
|
||||
</div>
|
||||
<!-- Email -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Email</label>
|
||||
<input type="email" name="email"
|
||||
value="{{ old('email') }}"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label>No. Telepon</label>
|
||||
<input type="text" name="no_tlpn" class="form-control" value="{{ old('no_tlpn') }}" required>
|
||||
</div>
|
||||
<!-- No. Telepon -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">No. Telepon</label>
|
||||
<input type="text" name="no_tlpn"
|
||||
value="{{ old('no_tlpn') }}"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label>Template</label>
|
||||
<select name="template_id" id="template_id" class="form-select" required>
|
||||
<option value="">-- Pilih Template --</option>
|
||||
@foreach($templates as $template)
|
||||
<option value="{{ $template->id }}" data-form='@json($template->form)'>
|
||||
{{ $template->nama_template }} (Rp {{ number_format($template->harga,0,',','.') }})
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<!-- Template -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Template</label>
|
||||
<select name="template_id" id="template_id"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-50 focus:ring-2 focus:ring-blue-400 focus:outline-none"
|
||||
required>
|
||||
<option value="">-- Pilih Template --</option>
|
||||
@foreach($templates as $template)
|
||||
<option value="{{ $template->id }}" data-form='@json($template->form)'>
|
||||
{{ $template->nama_template }} (Rp {{ number_format($template->harga,0,',','.') }})
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- tempat field dinamis -->
|
||||
<div id="dynamic-form"></div>
|
||||
<!-- Tempat field dinamis -->
|
||||
<div id="dynamic-form"></div>
|
||||
|
||||
<button type="submit" class="btn btn-success">Kirim Pesanan</button>
|
||||
</form>
|
||||
<!-- Tombol -->
|
||||
<div class="flex justify-end pt-4">
|
||||
<button type="submit"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white font-medium px-6 py-2 rounded-lg shadow transition duration-200">
|
||||
Kirim Pesanan
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@ -58,11 +81,11 @@ document.getElementById('template_id').addEventListener('change', function () {
|
||||
let input = '';
|
||||
|
||||
if (field.type === 'text') {
|
||||
input = `<input type="text" name="form[${key}]" class="form-control" ${field.required ? 'required' : ''}>`;
|
||||
input = `<input type="text" name="form[${key}]" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none" ${field.required ? 'required' : ''}>`;
|
||||
} else if (field.type === 'textarea') {
|
||||
input = `<textarea name="form[${key}]" class="form-control" ${field.required ? 'required' : ''}></textarea>`;
|
||||
input = `<textarea name="form[${key}]" class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none" ${field.required ? 'required' : ''}></textarea>`;
|
||||
} else if (field.type === 'select') {
|
||||
input = `<select name="form[${key}]" class="form-select">`;
|
||||
input = `<select name="form[${key}]" class="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-50 focus:ring-2 focus:ring-blue-400 focus:outline-none">`;
|
||||
field.options.forEach(opt => {
|
||||
input += `<option value="${opt}">${opt}</option>`;
|
||||
});
|
||||
@ -70,7 +93,7 @@ document.getElementById('template_id').addEventListener('change', function () {
|
||||
}
|
||||
container.innerHTML += `
|
||||
<div class="mb-3">
|
||||
<label>${label}</label>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">${label}</label>
|
||||
${input}
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -3,86 +3,101 @@
|
||||
@section('title', 'Edit Template')
|
||||
|
||||
@section('content')
|
||||
<div class="container mt-4">
|
||||
<h2>Edit Template</h2>
|
||||
<div class="container mx-auto py-8">
|
||||
<div class="max-w-2xl mx-auto bg-white shadow-md rounded-xl p-8 border border-blue-100">
|
||||
<h2 class="text-2xl font-semibold text-black mb-6">Edit Template</h2>
|
||||
|
||||
{{-- Alert sukses / error --}}
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success">{{ session('success') }}</div>
|
||||
@endif
|
||||
@if($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul class="mb-0">
|
||||
@foreach($errors->all() as $err)
|
||||
<li>{{ $err }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('admin.template.update', $template->id) }}"
|
||||
method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
{{-- Nama Template --}}
|
||||
<div class="mb-3">
|
||||
<label for="nama_template" class="form-label">Nama Template</label>
|
||||
<input type="text" name="nama_template" id="nama_template"
|
||||
class="form-control @error('nama_template') is-invalid @enderror"
|
||||
value="{{ old('nama_template', $template->nama_template) }}" required>
|
||||
@error('nama_template')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Harga --}}
|
||||
<div class="mb-3">
|
||||
<label for="harga" class="form-label">Harga</label>
|
||||
<input type="number" name="harga" id="harga"
|
||||
class="form-control @error('harga') is-invalid @enderror"
|
||||
value="{{ old('harga', $template->harga) }}" required>
|
||||
@error('harga')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Paket --}}
|
||||
<div class="mb-3">
|
||||
<label for="paket" class="form-label">Paket</label>
|
||||
<select name="paket" id="paket" class="form-select @error('paket') is-invalid @enderror" required>
|
||||
<option value="starter" {{ old('paket', $template->paket) == 'starter' ? 'selected' : '' }}>Starter</option>
|
||||
<option value="basic" {{ old('paket', $template->paket) == 'basic' ? 'selected' : '' }}>Basic</option>
|
||||
<option value="premium" {{ old('paket', $template->paket) == 'premium' ? 'selected' : '' }}>Premium</option>
|
||||
</select>
|
||||
@error('paket')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Foto / Gambar --}}
|
||||
<div class="mb-3">
|
||||
<label for="foto" class="form-label">Gambar Template</label>
|
||||
<div class="mb-2">
|
||||
@if($template->foto)
|
||||
<img src="{{ asset('storage/' . $template->foto) }}"
|
||||
alt="{{ $template->nama_template }}"
|
||||
class="rounded border" style="max-height: 120px">
|
||||
@else
|
||||
<p class="text-muted">Belum ada gambar</p>
|
||||
@endif
|
||||
{{-- Alert sukses / error --}}
|
||||
@if(session('success'))
|
||||
<div class="bg-green-100 text-green-700 px-4 py-2 rounded-lg mb-4 border border-green-200">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
<input type="file" name="foto" id="foto"
|
||||
class="form-control @error('foto') is-invalid @enderror">
|
||||
<small class="text-muted">Kosongkan jika tidak ingin mengganti gambar.</small>
|
||||
@error('foto')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
@endif
|
||||
@if($errors->any())
|
||||
<div class="bg-red-100 text-red-700 px-4 py-2 rounded-lg mb-4 border border-red-200">
|
||||
<ul class="list-disc pl-5 mb-0">
|
||||
@foreach($errors->all() as $err)
|
||||
<li>{{ $err }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Tombol --}}
|
||||
<button type="submit" class="btn btn-primary">Simpan Perubahan</button>
|
||||
<a href="{{ route('admin.template.index') }}" class="btn btn-secondary">Batal</a>
|
||||
</form>
|
||||
<form action="{{ route('admin.template.update', $template->id) }}" method="POST" enctype="multipart/form-data" class="space-y-5">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
{{-- Nama Template --}}
|
||||
<div>
|
||||
<label for="nama_template" class="block text-sm font-medium text-gray-700 mb-2">Nama Template</label>
|
||||
<input type="text" id="nama_template" name="nama_template"
|
||||
value="{{ old('nama_template', $template->nama_template) }}"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none @error('nama_template') border-red-500 @enderror"
|
||||
required>
|
||||
@error('nama_template')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Harga --}}
|
||||
<div>
|
||||
<label for="harga" class="block text-sm font-medium text-gray-700 mb-2">Harga</label>
|
||||
<input type="number" id="harga" name="harga"
|
||||
value="{{ old('harga', $template->harga) }}"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-400 focus:outline-none @error('harga') border-red-500 @enderror"
|
||||
required>
|
||||
@error('harga')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Paket --}}
|
||||
<div>
|
||||
<label for="paket" class="block text-sm font-medium text-gray-700 mb-2">Paket</label>
|
||||
<select id="paket" name="paket"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-50 focus:ring-2 focus:ring-blue-400 focus:outline-none @error('paket') border-red-500 @enderror"
|
||||
required>
|
||||
<option value="starter" {{ old('paket', $template->paket) == 'starter' ? 'selected' : '' }}>Starter</option>
|
||||
<option value="basic" {{ old('paket', $template->paket) == 'basic' ? 'selected' : '' }}>Basic</option>
|
||||
<option value="premium" {{ old('paket', $template->paket) == 'premium' ? 'selected' : '' }}>Premium</option>
|
||||
</select>
|
||||
@error('paket')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Foto / Gambar --}}
|
||||
<div>
|
||||
<label for="foto" class="block text-sm font-medium text-gray-700 mb-2">Gambar Template</label>
|
||||
<div class="mb-3">
|
||||
@if($template->foto)
|
||||
<img src="{{ asset('storage/' . $template->foto) }}"
|
||||
alt="{{ $template->nama_template }}"
|
||||
class="w-32 h-32 object-cover rounded-lg border border-gray-200">
|
||||
@else
|
||||
<p class="text-gray-500 text-sm">Belum ada gambar</p>
|
||||
@endif
|
||||
</div>
|
||||
<input type="file" id="foto" name="foto"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-50 cursor-pointer focus:ring-2 focus:ring-blue-400 @error('foto') border-red-500 @enderror">
|
||||
<p class="text-gray-500 text-sm mt-1">Kosongkan jika tidak ingin mengganti gambar.</p>
|
||||
@error('foto')
|
||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Tombol --}}
|
||||
<div class="flex justify-end gap-3 pt-4">
|
||||
<a href="{{ route('admin.template.index') }}"
|
||||
class="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium px-5 py-2 rounded-lg transition duration-200">
|
||||
Batal
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white font-medium px-6 py-2 rounded-lg shadow transition duration-200">
|
||||
Simpan Perubahan
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\Api\TemplateApiController;
|
||||
use App\Http\Controllers\Api\KategoriApiController;
|
||||
use App\Http\Controllers\Api\PelangganApiController;
|
||||
use App\Http\Controllers\Api\ReviewApiController;
|
||||
|
||||
Route::get('kategoris', [KategoriApiController::class, 'index']);
|
||||
Route::get('kategoris/{kategori}', [KategoriApiController::class, 'show']);
|
||||
@ -12,7 +13,11 @@ Route::get('kategoris/{kategori}', [KategoriApiController::class, 'show']);
|
||||
Route::get('/templates', [TemplateApiController::class, 'index']);
|
||||
Route::get('/templates/{template}', [TemplateApiController::class, 'show']);
|
||||
|
||||
|
||||
Route::get('/templates/category/{id}', [TemplateApiController::class, 'getByCategory']);
|
||||
|
||||
Route::post('/pelanggans', [PelangganApiController::class, 'store']);
|
||||
|
||||
Route::get('/reviews', [ReviewApiController::class, 'index']);
|
||||
Route::post('/reviews', [ReviewApiController::class, 'store']);
|
||||
Route::get('/reviews/{id}', [ReviewApiController::class, 'show']);
|
||||
Route::delete('/reviews/{id}', [ReviewApiController::class, 'destroy']);
|
||||
|
||||
@ -2,60 +2,16 @@
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
// id template yang mau ditampilkan
|
||||
const selectedIds = [1, 2, 3, 4, 5, 6]
|
||||
const selectedIds = [1, 2, 3, 5, 6]
|
||||
|
||||
// state dropdown
|
||||
// state dropdown (buat fitur paket aja sekarang)
|
||||
const openDropdownId = ref(null)
|
||||
const toggleDropdown = (templateId) => {
|
||||
openDropdownId.value = openDropdownId.value === templateId ? null : templateId
|
||||
}
|
||||
|
||||
// Paket & fitur hardcode (tidak tergantung kategori backend)
|
||||
const paketData = [
|
||||
{
|
||||
paket: 'Starter',
|
||||
fiturs: [
|
||||
'1x Acara',
|
||||
'Masa Aktif 3 Bulan',
|
||||
'Nama Tamu Personal',
|
||||
'Maks. 100 Tamu',
|
||||
'Request Musik'
|
||||
]
|
||||
},
|
||||
{
|
||||
paket: 'Basic',
|
||||
fiturs: [
|
||||
'1x Acara',
|
||||
'6 Galeri Foto',
|
||||
'Hitung Mundur Waktu Acara',
|
||||
'Buku Tamu + Data Kehadiran',
|
||||
'Masa Aktif 6 Bulan',
|
||||
'Nama Tamu Personal',
|
||||
'Maks. 200 Tamu',
|
||||
'Request Musik'
|
||||
]
|
||||
},
|
||||
{
|
||||
paket: 'Premium',
|
||||
fiturs: [
|
||||
'Maksimal 3x Acara (Akad, Resepsi, Syukuran)',
|
||||
'Unlimited Galeri Foto',
|
||||
'Timeline Story',
|
||||
'Google Maps',
|
||||
'Reminder Google Calendar',
|
||||
'Link Instagram Live Streaming',
|
||||
'Amplop Digital',
|
||||
'Placement Video Cinematic',
|
||||
'Bonus Undangan Image Post Story',
|
||||
'Masa Aktif 12 Bulan',
|
||||
'Nama Tamu Personal Unlimited Tamu',
|
||||
'Request Musik'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// fetch API dari backend (hanya untuk nama template & harga)
|
||||
const { data: templatesData } = await useFetch('http://localhost:8000/api/templates')
|
||||
// fetch API dari Laravel
|
||||
const { data: templatesData, error } = await useFetch('http://localhost:8000/api/templates')
|
||||
|
||||
// mapping template: nama_template & harga dari backend, paket & fiturs hardcode
|
||||
const templates = computed(() =>
|
||||
@ -84,10 +40,17 @@ const templates = computed(() =>
|
||||
|
||||
<!-- Grid Template -->
|
||||
<div v-if="templates.length" class="grid gap-8 max-w-[1100px] mx-auto grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<div v-for="t in templates" :key="t.id"
|
||||
class="bg-white border rounded-lg overflow-hidden shadow-md hover:shadow-xl transition-shadow duration-300">
|
||||
<div
|
||||
v-for="t in templates"
|
||||
:key="t.id"
|
||||
class="bg-white border rounded-lg overflow-hidden shadow-md hover:shadow-xl transition-shadow duration-300"
|
||||
>
|
||||
<!-- Image -->
|
||||
<img :src="t.foto" :alt="t.nama_template" class="w-full h-48 object-cover" />
|
||||
<img
|
||||
:src="`http://localhost:8000${t.foto}`"
|
||||
:alt="t.nama_template"
|
||||
class="w-full h-48 object-cover"
|
||||
/>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="p-5 text-center">
|
||||
@ -95,45 +58,41 @@ const templates = computed(() =>
|
||||
<p class="text-green-600 font-semibold text-xl mb-1">
|
||||
Rp {{ Number(t.harga).toLocaleString('id-ID') }}
|
||||
</p>
|
||||
<p class="text-gray-500 mb-4 font-medium">Paket: {{ t.paket }}</p>
|
||||
|
||||
<!-- Dropdown fitur -->
|
||||
<div v-if="t.fiturs && t.fiturs.length > 0" class="relative mb-4">
|
||||
<button @click="toggleDropdown(t.id)"
|
||||
class="w-full bg-white border border-gray-300 rounded-md shadow-sm px-4 py-2 inline-flex justify-between items-start">
|
||||
<button
|
||||
@click="toggleDropdown(t.id)"
|
||||
class="w-full bg-white border border-gray-300 rounded-md shadow-sm px-4 py-2 inline-flex justify-between items-center"
|
||||
>
|
||||
<span class="mx-auto text-gray-700 font-semibold">FITUR YANG TERSEDIA</span>
|
||||
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
|
||||
fill="currentColor">
|
||||
<path fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd" />
|
||||
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<transition name="fade">
|
||||
<div v-if="openDropdownId === t.id" class="mt-4">
|
||||
<ul
|
||||
class="space-y-2 text-gray-600 text-left max-h-60 overflow-y-auto px-3 py-2 border border-gray-200 rounded-md shadow-inner bg-gray-50">
|
||||
<li v-for="f in t.fiturs" :key="f.id" class="flex items-center">
|
||||
<svg class="h-4 w-4 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
{{ f.deskripsi }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</transition>
|
||||
<div v-if="openDropdownId === t.id">
|
||||
<ul class="mt-4 space-y-2 text-gray-600 text-left">
|
||||
<li v-for="f in t.fiturs" :key="f.id" class="flex items-center">
|
||||
<svg class="h-4 w-4 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
||||
</svg>
|
||||
{{ f.deskripsi }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons -->
|
||||
<!-- Tombol -->
|
||||
<div class="flex items-center gap-3 mt-6">
|
||||
<button
|
||||
class="w-full bg-white border border-gray-300 text-gray-800 font-semibold py-2 px-4 rounded-lg hover:bg-gray-100 transition-colors">
|
||||
Preview
|
||||
</button>
|
||||
<NuxtLink
|
||||
:to="`/form/${t.kategori ? t.kategori.toLowerCase().replace(/ /g, '-') : ''}` + `?template_id=${t.id}`"
|
||||
class="w-full bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors text-center">
|
||||
:to="`/form/${t.kategori.nama.toLowerCase().replace(/ /g, '-')}` + `?template_id=${t.id}`"
|
||||
class="w-full bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors text-center"
|
||||
>
|
||||
Order
|
||||
</NuxtLink>
|
||||
</div>
|
||||
@ -141,7 +100,7 @@ const templates = computed(() =>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Jika tidak ada template -->
|
||||
<!-- Jika error -->
|
||||
<div v-else class="text-gray-500">Tidak ada template yang bisa ditampilkan</div>
|
||||
|
||||
<!-- See more -->
|
||||
|
||||
Loading…
Reference in New Issue
Block a user