260 lines
9.4 KiB
PHP
260 lines
9.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Category;
|
|
use App\Models\Favorite;
|
|
use App\Services\CarRecommendationService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class CategoryController extends Controller
|
|
{
|
|
public function index()
|
|
{
|
|
Category::releaseExpiredReservations();
|
|
|
|
$categories = Category::orderBy('created_at', 'desc')->get();
|
|
|
|
return view('admin.kategori', compact('categories'));
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255',
|
|
'description' => 'required|string|max:1000',
|
|
'merk' => 'nullable|string|max:255',
|
|
'model' => 'nullable|string|max:255',
|
|
'kategori' => 'nullable|string|max:255',
|
|
'price' => 'required|numeric|min:0',
|
|
'year' => 'required|integer|min:1900|max:' . date('Y'),
|
|
'mesin_cc' => 'nullable|integer|min:0',
|
|
'transmisi' => 'nullable|string|max:255',
|
|
'bahan_bakar' => 'nullable|string|max:255',
|
|
'status' => 'required|in:available,reserved,sold',
|
|
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
|
|
], [
|
|
'name.required' => 'Nama kategori wajib diisi.',
|
|
'description.required' => 'Deskripsi kategori wajib diisi.',
|
|
'price.required' => 'Harga mobil wajib diisi.',
|
|
'price.numeric' => 'Harga mobil harus berupa angka.',
|
|
'price.min' => 'Harga mobil tidak boleh negatif.',
|
|
'year.required' => 'Tahun mobil wajib diisi.',
|
|
'year.integer' => 'Tahun mobil harus berupa angka.',
|
|
'year.min' => 'Tahun mobil tidak valid.',
|
|
'year.max' => 'Tahun mobil tidak valid.',
|
|
'status.required' => 'Status mobil wajib dipilih.',
|
|
'status.in' => 'Status mobil tidak valid.',
|
|
'image.image' => 'File harus berupa gambar.',
|
|
'image.mimes' => 'Format gambar harus jpeg, png, jpg, atau gif.',
|
|
'image.max' => 'Ukuran gambar maksimal 2MB.',
|
|
]);
|
|
|
|
if ($request->hasFile('image')) {
|
|
$validated['image'] = $request->file('image')->store('categories', 'public');
|
|
}
|
|
|
|
Category::create($validated);
|
|
|
|
return redirect()->route('kategori')->with('success', 'Kategori berhasil ditambahkan.');
|
|
}
|
|
|
|
public function edit(Category $category)
|
|
{
|
|
return view('admin.kategori-edit', compact('category'));
|
|
}
|
|
|
|
public function update(Request $request, Category $category)
|
|
{
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255',
|
|
'description' => 'required|string|max:1000',
|
|
'merk' => 'nullable|string|max:255',
|
|
'model' => 'nullable|string|max:255',
|
|
'kategori' => 'nullable|string|max:255',
|
|
'price' => 'required|numeric|min:0',
|
|
'year' => 'required|integer|min:1900|max:' . date('Y'),
|
|
'mesin_cc' => 'nullable|integer|min:0',
|
|
'transmisi' => 'nullable|string|max:255',
|
|
'bahan_bakar' => 'nullable|string|max:255',
|
|
'status' => 'required|in:available,reserved,sold',
|
|
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
|
|
], [
|
|
'name.required' => 'Nama kategori wajib diisi.',
|
|
'description.required' => 'Deskripsi kategori wajib diisi.',
|
|
'price.required' => 'Harga mobil wajib diisi.',
|
|
'price.numeric' => 'Harga mobil harus berupa angka.',
|
|
'price.min' => 'Harga mobil tidak boleh negatif.',
|
|
'year.required' => 'Tahun mobil wajib diisi.',
|
|
'year.integer' => 'Tahun mobil harus berupa angka.',
|
|
'year.min' => 'Tahun mobil tidak valid.',
|
|
'year.max' => 'Tahun mobil tidak valid.',
|
|
'status.required' => 'Status mobil wajib dipilih.',
|
|
'status.in' => 'Status mobil tidak valid.',
|
|
'image.image' => 'File harus berupa gambar.',
|
|
'image.mimes' => 'Format gambar harus jpeg, png, jpg, atau gif.',
|
|
'image.max' => 'Ukuran gambar maksimal 2MB.',
|
|
]);
|
|
|
|
if ($request->hasFile('image')) {
|
|
if ($category->image) {
|
|
Storage::disk('public')->delete($category->image);
|
|
}
|
|
$validated['image'] = $request->file('image')->store('categories', 'public');
|
|
}
|
|
|
|
$category->update($validated);
|
|
|
|
return redirect()->route('kategori')->with('success', 'Kategori berhasil diperbarui.');
|
|
}
|
|
|
|
public function destroy(Category $category)
|
|
{
|
|
if ($category->image) {
|
|
Storage::disk('public')->delete($category->image);
|
|
}
|
|
|
|
$category->delete();
|
|
|
|
return redirect()->route('kategori')->with('success', 'Kategori berhasil dihapus.');
|
|
}
|
|
|
|
public function userIndex(Request $request, CarRecommendationService $recommendationService)
|
|
{
|
|
Category::releaseExpiredReservations();
|
|
|
|
$budget = $request->query('budget');
|
|
$budgetValue = is_numeric($budget) ? (float) $budget : null;
|
|
$year = $request->query('year');
|
|
$yearValue = is_numeric($year) ? (int) $year : null;
|
|
$mesinCc = $request->query('mesin_cc');
|
|
$mesinCcValue = is_numeric($mesinCc) ? (int) $mesinCc : null;
|
|
|
|
$categories = Category::where('status', 'available')->orderBy('created_at', 'desc')->get();
|
|
$hasExactBudgetMatch = false;
|
|
$recommendationSource = null;
|
|
$recommendationMeta = null;
|
|
|
|
if ($budgetValue) {
|
|
$recommendation = $recommendationService->recommendForBudget($budgetValue, 50, [
|
|
'year' => $yearValue,
|
|
'mesin_cc' => $mesinCcValue,
|
|
]);
|
|
$recommended = $recommendation['cars'];
|
|
$hasExactBudgetMatch = $recommendation['has_exact_budget_match'];
|
|
$recommendationSource = $recommendation['source'];
|
|
$recommendationMeta = $recommendation['meta'];
|
|
} else {
|
|
$recommended = Category::where('status', 'available')
|
|
->orderBy('created_at', 'desc')
|
|
->get();
|
|
}
|
|
|
|
return view('user.cars', compact(
|
|
'categories',
|
|
'recommended',
|
|
'budget',
|
|
'year',
|
|
'mesinCc',
|
|
'hasExactBudgetMatch',
|
|
'recommendationSource',
|
|
'recommendationMeta'
|
|
));
|
|
}
|
|
|
|
public function allCars()
|
|
{
|
|
Category::releaseExpiredReservations();
|
|
|
|
$categories = Category::where('status', 'available')
|
|
->orderBy('created_at', 'desc')
|
|
->paginate(12);
|
|
|
|
return view('user.all-cars', compact('categories'));
|
|
}
|
|
|
|
public function budgetCars(Request $request, CarRecommendationService $recommendationService)
|
|
{
|
|
Category::releaseExpiredReservations();
|
|
|
|
$budget = $request->query('budget');
|
|
$budgetValue = is_numeric($budget) ? (float) $budget : null;
|
|
$year = $request->query('year');
|
|
$yearValue = is_numeric($year) ? (int) $year : null;
|
|
$mesinCc = $request->query('mesin_cc');
|
|
$mesinCcValue = is_numeric($mesinCc) ? (int) $mesinCc : null;
|
|
$availableCount = Category::where('status', 'available')->count();
|
|
$hasExactBudgetMatch = false;
|
|
$recommendationSource = null;
|
|
$recommendationMeta = null;
|
|
$recommended = collect();
|
|
|
|
if ($budgetValue) {
|
|
$recommendation = $recommendationService->recommendForBudget($budgetValue, 50, [
|
|
'year' => $yearValue,
|
|
'mesin_cc' => $mesinCcValue,
|
|
]);
|
|
$recommended = $recommendation['cars'];
|
|
$hasExactBudgetMatch = $recommendation['has_exact_budget_match'];
|
|
$recommendationSource = $recommendation['source'];
|
|
$recommendationMeta = $recommendation['meta'];
|
|
}
|
|
|
|
return view('user.budget-cars', compact(
|
|
'budget',
|
|
'year',
|
|
'mesinCc',
|
|
'availableCount',
|
|
'recommended',
|
|
'hasExactBudgetMatch',
|
|
'recommendationSource',
|
|
'recommendationMeta'
|
|
));
|
|
}
|
|
|
|
public function show(Category $category)
|
|
{
|
|
Category::releaseExpiredReservations();
|
|
$category->refresh();
|
|
|
|
return view('user.car-detail', compact('category'));
|
|
}
|
|
|
|
public function addToFavorites(Category $category)
|
|
{
|
|
Category::releaseExpiredReservations();
|
|
$category->refresh();
|
|
|
|
$username = auth()->user()->username;
|
|
|
|
if ($category->status !== 'available') {
|
|
return response()->json(['message' => 'Mobil ini sedang tidak tersedia.'], 422);
|
|
}
|
|
|
|
// Check if already favorited
|
|
if (Favorite::where('username', $username)->where('category_id', $category->id)->exists()) {
|
|
return response()->json(['message' => 'Already in favorites'], 409);
|
|
}
|
|
|
|
Favorite::create([
|
|
'username' => $username,
|
|
'category_id' => $category->id,
|
|
]);
|
|
|
|
return response()->json(['message' => 'Added to favorites']);
|
|
}
|
|
|
|
public function removeFromFavorites(Category $category)
|
|
{
|
|
$username = auth()->user()->username;
|
|
|
|
Favorite::where('username', $username)
|
|
->where('category_id', $category->id)
|
|
->delete();
|
|
|
|
return response()->json(['message' => 'Removed from favorites']);
|
|
}
|
|
|
|
}
|