diff --git a/backend-baru/app/Http/Controllers/Api/PelangganApiController.php b/backend-baru/app/Http/Controllers/Api/PelangganApiController.php index 711e4e5..4534f13 100644 --- a/backend-baru/app/Http/Controllers/Api/PelangganApiController.php +++ b/backend-baru/app/Http/Controllers/Api/PelangganApiController.php @@ -6,27 +6,118 @@ use App\Http\Controllers\Controller; use App\Models\Pelanggan; use App\Models\Template; use Illuminate\Http\Request; +use Illuminate\Support\Str; class PelangganApiController extends Controller { - public function store(Request $request) -{ - $template = Template::findOrFail($request->input('template_id')); + // 🔹 Simpan pesanan pelanggan via API + public function store(Request $request) + { + $request->validate([ + 'nama_pemesan' => 'required|string|max:255', + 'email' => 'required|email', + 'no_tlpn' => 'required|string|max:20', + 'template_id' => 'required|exists:templates,id', + 'form' => 'required|array', + ]); - $pelanggan = Pelanggan::create([ - 'nama_pemesan' => $request->nama_pemesan, - 'email' => $request->email, - 'no_tlpn' => $request->no_tlpn, - 'template_id' => $template->id, - 'form' => $request->input('form'), - 'harga' => $template->harga, - 'status' => 'menunggu', - ]); + $template = Template::findOrFail($request->input('template_id')); - return response()->json([ - 'success' => true, - 'message' => 'Pesanan berhasil dibuat', - 'data' => $pelanggan - ], 201); -} + // 🔸 Generate kode undangan unik + $invitationCode = 'INV-' . strtoupper(Str::random(6)); + while (Pelanggan::where('invitation_code', $invitationCode)->exists()) { + $invitationCode = 'INV-' . strtoupper(Str::random(6)); + } + + // 🔸 Simpan data pelanggan baru + $pelanggan = Pelanggan::create([ + 'nama_pemesan' => $request->nama_pemesan, + 'email' => $request->email, + 'no_tlpn' => $request->no_tlpn, + 'template_id' => $template->id, + 'form' => $request->input('form'), + 'harga' => $template->harga, + 'status' => 'menunggu', + 'invitation_code' => $invitationCode, + ]); + + return response()->json([ + 'success' => true, + 'message' => 'Pesanan berhasil dibuat', + 'data' => $pelanggan, + ], 201); + } + + // 🔹 Ambil semua data pelanggan + public function index() + { + $pelanggan = Pelanggan::with('template')->latest()->get(); + + return response()->json([ + 'success' => true, + 'data' => $pelanggan, + ]); + } + + // 🔹 Ambil pesanan berdasarkan ID + public function show($id) + { + $pelanggan = Pelanggan::with('template')->find($id); + + if (!$pelanggan) { + return response()->json([ + 'success' => false, + 'message' => 'Data pelanggan tidak ditemukan.', + ], 404); + } + + return response()->json([ + 'success' => true, + 'data' => $pelanggan, + ]); + } + + // 🔹 Ambil pesanan berdasarkan invitation code + public function getByInvitationCode($code) + { + $pelanggan = Pelanggan::with('template') + ->where('invitation_code', $code) + ->first(); + + if (!$pelanggan) { + return response()->json([ + 'success' => false, + 'message' => 'Data pelanggan dengan kode undangan tidak ditemukan.', + ], 404); + } + + return response()->json([ + 'success' => true, + 'data' => $pelanggan, + ]); + } + + // 🔹 Update status pesanan (opsional untuk admin mobile) + public function updateStatus(Request $request, $id) + { + $request->validate([ + 'status' => 'required|in:menunggu,diterima,ditolak', + ]); + + $pelanggan = Pelanggan::find($id); + if (!$pelanggan) { + return response()->json([ + 'success' => false, + 'message' => 'Pesanan tidak ditemukan.', + ], 404); + } + + $pelanggan->update(['status' => $request->status]); + + return response()->json([ + 'success' => true, + 'message' => 'Status pesanan berhasil diperbarui.', + 'data' => $pelanggan, + ]); + } } diff --git a/backend-baru/app/Http/Controllers/PelangganController.php b/backend-baru/app/Http/Controllers/PelangganController.php index 3cbb2ec..159d950 100644 --- a/backend-baru/app/Http/Controllers/PelangganController.php +++ b/backend-baru/app/Http/Controllers/PelangganController.php @@ -5,36 +5,47 @@ namespace App\Http\Controllers; use App\Models\Pelanggan; use App\Models\Template; use Illuminate\Http\Request; +use Illuminate\Support\Str; class PelangganController extends Controller { - // List pesanan + // 🔹 Tampilkan daftar pesanan (admin) public function index() { $pelanggans = Pelanggan::with('template')->latest()->paginate(10); return view('admin.pelanggans.index', compact('pelanggans')); } - // Detail pesanan + // 🔹 Tampilkan detail pesanan (admin) public function show($id) { $pelanggan = Pelanggan::with('template')->findOrFail($id); return view('admin.pelanggans.show', compact('pelanggan')); } - // Pelanggan membuat pesanan (user side) + // 🔹 Tampilkan detail pesanan berdasarkan invitation code + public function showByCode($code) + { + $pelanggan = Pelanggan::with('template') + ->where('invitation_code', $code) + ->firstOrFail(); + + return view('admin.pelanggans.show', compact('pelanggan')); + } + + // 🔹 Pelanggan membuat pesanan (frontend user) public function store(Request $request) { $template = Template::findOrFail($request->input('template_id')); $rules = [ 'nama_pemesan' => 'required|string|max:255', - 'email' => 'required|email', - 'no_tlpn' => 'required|string|max:30', - 'template_id' => 'required|exists:templates,id', + 'email' => 'required|email', + 'no_tlpn' => 'required|string|max:30', + 'template_id' => 'required|exists:templates,id', ]; - // validasi dinamis dari field JSON form di template + // 🔸 Validasi dinamis dari JSON form template if ($template->form) { foreach ($template->form as $field => $options) { $rule = []; @@ -46,24 +57,29 @@ class PelangganController extends Controller $validated = $request->validate($rules); - // harga otomatis dari template - $harga = $template->harga; + // 🔸 Generate kode undangan unik + $invitationCode = 'INV-' . strtoupper(Str::random(6)); + while (Pelanggan::where('invitation_code', $invitationCode)->exists()) { + $invitationCode = 'INV-' . strtoupper(Str::random(6)); + } + // 🔸 Simpan pesanan baru $pelanggan = Pelanggan::create([ - 'nama_pemesan' => $validated['nama_pemesan'], - 'email' => $validated['email'], - 'no_tlpn' => $validated['no_tlpn'], - 'template_id' => $template->id, - 'form' => $request->input('form'), - 'harga' => $harga, - 'status' => 'menunggu', // default + 'nama_pemesan' => $validated['nama_pemesan'], + 'email' => $validated['email'], + 'no_tlpn' => $validated['no_tlpn'], + 'template_id' => $template->id, + 'form' => $request->input('form'), + 'harga' => $template->harga, + 'status' => 'menunggu', + 'invitation_code' => $invitationCode, ]); return redirect()->route('pelanggans.show', $pelanggan->id) ->with('success', 'Pesanan berhasil dikirim, status menunggu konfirmasi admin.'); } - // Admin ubah status + // 🔹 Update status pesanan (admin) public function update(Request $request, $id) { $pelanggan = Pelanggan::findOrFail($id); @@ -77,13 +93,13 @@ class PelangganController extends Controller return redirect()->back()->with('success', 'Status pesanan berhasil diperbarui.'); } - // Admin hapus pesanan + // 🔹 Hapus pesanan (admin) public function destroy($id) { $pelanggan = Pelanggan::findOrFail($id); $pelanggan->delete(); - return redirect()->route('admin.pelanggan.index') + return redirect()->route('admin.pelanggans.index') ->with('success', 'Pesanan berhasil dihapus.'); } } diff --git a/backend-baru/app/Models/Pelanggan.php b/backend-baru/app/Models/Pelanggan.php index 1ada881..095f08c 100644 --- a/backend-baru/app/Models/Pelanggan.php +++ b/backend-baru/app/Models/Pelanggan.php @@ -19,6 +19,7 @@ class Pelanggan extends Model 'form', 'harga', 'status', + 'invitation_code', ]; protected $casts = [ diff --git a/backend-baru/app/Models/Template.php b/backend-baru/app/Models/Template.php index c69c519..2493b1c 100644 --- a/backend-baru/app/Models/Template.php +++ b/backend-baru/app/Models/Template.php @@ -26,19 +26,21 @@ class Template extends Model 'harga' => 'decimal:2', ]; + protected $appends = ['slug']; + // Relasi ke Kategori public function kategori() { return $this->belongsTo(Kategori::class, 'kategori_id'); } - // Relasi ke Pelanggan (jika kamu mau tahu siapa saja pesan template ini) + // Relasi ke Pelanggan public function pelanggans() { return $this->hasMany(Pelanggan::class, 'template_id'); } - // Accessor untuk slug berdasarkan nama_template + // Accessor untuk slug public function getSlugAttribute() { return Str::slug($this->nama_template); diff --git a/backend-baru/database/migrations/2025_10_02_052812_create_pelanggans_table.php b/backend-baru/database/migrations/2025_10_02_052812_create_pelanggans_table.php index 4c8edc9..d2a9068 100644 --- a/backend-baru/database/migrations/2025_10_02_052812_create_pelanggans_table.php +++ b/backend-baru/database/migrations/2025_10_02_052812_create_pelanggans_table.php @@ -21,6 +21,7 @@ return new class extends Migration { $table->decimal('harga', 15, 2)->nullable(); $table->enum('status', ['menunggu', 'diterima', 'ditolak'])->default('menunggu'); + $table->string('invitation_code')->unique(); $table->timestamps(); }); } diff --git a/backend-baru/database/seeders/DatabaseSeeder.php b/backend-baru/database/seeders/DatabaseSeeder.php index f2f8ff0..434bc09 100644 --- a/backend-baru/database/seeders/DatabaseSeeder.php +++ b/backend-baru/database/seeders/DatabaseSeeder.php @@ -12,6 +12,7 @@ class DatabaseSeeder extends Seeder $this->call([ TemplateSeeder::class, AdminSeeder::class, + PelangganSeeder::class, ]); } } diff --git a/backend-baru/database/seeders/PelangganSeeder.php b/backend-baru/database/seeders/PelangganSeeder.php new file mode 100644 index 0000000..5d0cf07 --- /dev/null +++ b/backend-baru/database/seeders/PelangganSeeder.php @@ -0,0 +1,61 @@ + 'Arief Dwi Wicaksono', + 'email' => 'arief@example.com', + 'no_tlpn' => '081234567890', + 'template_id' => 1, // pastikan ada template_id valid + 'form' => json_encode([ + 'nama_pria' => 'Arief', + 'nama_wanita' => 'Nisa', + 'alamat' => 'Malang', + ]), + 'harga' => 150000, + 'status' => 'menunggu', + ], + [ + 'nama_pemesan' => 'Rizky Ramadhan', + 'email' => 'rizky@example.com', + 'no_tlpn' => '081298765432', + 'template_id' => 2, + 'form' => json_encode([ + 'nama_pria' => 'Rizky', + 'nama_wanita' => 'Dinda', + 'alamat' => 'Surabaya', + ]), + 'harga' => 250000, + 'status' => 'diterima', + ], + [ + 'nama_pemesan' => 'Siti Rahmawati', + 'email' => 'siti@example.com', + 'no_tlpn' => '081212341234', + 'template_id' => 3, + 'form' => json_encode([ + 'nama_pria' => 'Andi', + 'nama_wanita' => 'Siti', + 'alamat' => 'Jakarta', + ]), + 'harga' => 300000, + 'status' => 'menunggu', + ], + ]; + + foreach ($pelanggans as $data) { + $data['invitation_code'] = 'INV-' . strtoupper(Str::random(6)); // 🟢 generate code unik + Pelanggan::create($data); + } + } +} diff --git a/backend-baru/routes/api.php b/backend-baru/routes/api.php index 9da3cdf..ca5891f 100644 --- a/backend-baru/routes/api.php +++ b/backend-baru/routes/api.php @@ -7,16 +7,40 @@ use App\Http\Controllers\Api\KategoriApiController; use App\Http\Controllers\Api\PelangganApiController; use App\Http\Controllers\Api\ReviewApiController; +// ============================ +// KATEGORI TEMPLATE +// ============================ Route::get('kategoris', [KategoriApiController::class, 'index']); Route::get('kategoris/{kategori}', [KategoriApiController::class, 'show']); +// ============================ +// TEMPLATE +// ============================ Route::get('/templates', [TemplateApiController::class, 'index']); Route::get('/templates/{template}', [TemplateApiController::class, 'show']); - Route::get('/templates/category/{id}', [TemplateApiController::class, 'getByCategory']); +// ============================ +// PELANGGAN +// ============================ +// Ambil semua pelanggan +Route::get('/pelanggans', [PelangganApiController::class, 'index']); + +// Ambil pelanggan berdasarkan ID +Route::get('/pelanggans/id/{id}', [PelangganApiController::class, 'show']); + +// Ambil pelanggan berdasarkan KODE UNDANGAN +Route::get('/pelanggans/code/{code}', [PelangganApiController::class, 'getByInvitationCode']); + +// Simpan pesanan baru Route::post('/pelanggans', [PelangganApiController::class, 'store']); +// Update status pesanan +Route::put('/pelanggans/{id}/status', [PelangganApiController::class, 'updateStatus']); + +// ============================ +// REVIEW +// ============================ Route::get('/reviews', [ReviewApiController::class, 'index']); Route::post('/reviews', [ReviewApiController::class, 'store']); Route::get('/reviews/{id}', [ReviewApiController::class, 'show']); diff --git a/backend-baru/routes/web.php b/backend-baru/routes/web.php index 3e0ab9b..0e0936c 100644 --- a/backend-baru/routes/web.php +++ b/backend-baru/routes/web.php @@ -6,10 +6,12 @@ use App\Http\Controllers\DashboardController; use App\Http\Controllers\KategoriController; use App\Http\Controllers\TemplateController; use App\Http\Controllers\PelangganController; +use App\Http\Controllers\ReviewController; // Pastikan ini controller web, bukan API use Illuminate\Support\Facades\Auth; -use App\Http\Controllers\Api\ReviewController; -// logout umum +// ============================ +// LOGOUT UMUM +// ============================ Route::post('/logout', function () { Auth::logout(); request()->session()->invalidate(); @@ -17,38 +19,57 @@ Route::post('/logout', function () { return redirect()->route('admin.login'); })->name('logout'); -// redirect root ke login admin +// ============================ +// REDIRECT ROOT KE LOGIN ADMIN +// ============================ Route::get('/', function () { return redirect()->route('admin.login'); }); -// Admin routes +// ============================ +// ADMIN ROUTES +// ============================ Route::prefix('admin')->name('admin.')->group(function () { - // Auth + + // ---------------------------- + // AUTH (LOGIN ADMIN) + // ---------------------------- Route::middleware('guest:admin')->group(function () { Route::get('/login', [AdminAuthController::class, 'showLogin'])->name('login'); Route::post('/login', [AdminAuthController::class, 'login'])->name('login.post'); }); + // ---------------------------- + // ADMIN AREA (AUTH PROTECTED) + // ---------------------------- Route::middleware('auth:admin')->group(function () { - Route::get('/dashboard', function () { - return view('admin.dashboard'); - })->name('dashboard'); + // Dashboard + Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard'); + + // Logout Route::post('/logout', [AdminAuthController::class, 'logout'])->name('logout'); - // Resource routes + // ---------------------------- + // KATEGORI + // ---------------------------- Route::resource('kategori', KategoriController::class); - // Template routes (index, edit, update) + // ---------------------------- + // TEMPLATE + // ---------------------------- Route::get('/template', [TemplateController::class, 'index'])->name('template.index'); Route::get('/template/{template}/edit', [TemplateController::class, 'edit'])->name('template.edit'); Route::put('/template/{template}', [TemplateController::class, 'update'])->name('template.update'); - // Pelanggan routes - Route::resource('pelanggan', PelangganController::class)->except(['create', 'edit']); + // ---------------------------- + // PELANGGAN + // ---------------------------- + Route::resource('pelanggan', PelangganController::class)->except(['create', 'edit']); - // Ulasan routes - Route::resource('reviews', ReviewController::class)->except(['create', 'edit', 'update', 'show', 'store']); + // ---------------------------- + // REVIEW / ULASAN + // ---------------------------- + Route::resource('reviews', ReviewController::class)->except(['create', 'edit', 'update', 'show', 'store']); }); });