This commit is contained in:
timotiabbauftech 2025-10-09 11:48:13 +07:00
commit eb2ba50ac9
9 changed files with 272 additions and 54 deletions

View File

@ -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,
]);
}
}

View File

@ -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.');
}
}

View File

@ -19,6 +19,7 @@ class Pelanggan extends Model
'form',
'harga',
'status',
'invitation_code',
];
protected $casts = [

View File

@ -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);

View File

@ -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();
});
}

View File

@ -12,6 +12,7 @@ class DatabaseSeeder extends Seeder
$this->call([
TemplateSeeder::class,
AdminSeeder::class,
PelangganSeeder::class,
]);
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\Pelanggan;
use Illuminate\Support\Str;
class PelangganSeeder extends Seeder
{
public function run(): void
{
// contoh beberapa pelanggan
$pelanggans = [
[
'nama_pemesan' => '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);
}
}
}

View File

@ -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']);

View File

@ -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']);
});
});