approved() ->latest(); if ($request->has('category')) { $query->where('category_id', $request->category); } $products = $query->paginate(12); $categories = Category::all(); return view('products.index', compact('products', 'categories')); } /** * Show the form for creating a new product. */ public function create() { $categories = Category::all(); return view('products.create', compact('categories')); } /** * Store a newly created product in storage. */ public function store(Request $request) { Gate::authorize('create-product'); $validated = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'required|string', 'website_url' => 'required|url', 'thumbnail' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048', 'category_id' => 'required|exists:categories,id', ]); $validated['user_id'] = Auth::id(); $validated['status'] = 'pending'; // Handle thumbnail upload if ($request->hasFile('thumbnail')) { $path = $request->file('thumbnail')->store('thumbnails', 'public'); $validated['thumbnail'] = $path; } $product = Product::create($validated); return redirect()->route('products.show', $product) ->with('success', 'Product submitted successfully! It will be reviewed by our moderators.'); } /** * Display the specified product. */ public function show(Product $product) { // Only show approved products to non-owners if (!$product->isApproved() && $product->user_id !== Auth::id() && !Auth::user()?->hasAnyRole(['admin', 'moderator'])) { abort(404); } $product->load(['user', 'category', 'comments.user', 'upvotes', 'bookmarks']); return view('products.show', compact('product')); } /** * Show the form for editing the specified product. */ public function edit(Product $product) { Gate::authorize('edit-product', $product); $categories = Category::all(); return view('products.edit', compact('product', 'categories')); } /** * Update the specified product in storage. */ public function update(Request $request, Product $product) { Gate::authorize('edit-product', $product); $validated = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'required|string', 'website_url' => 'required|url', 'thumbnail' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048', 'category_id' => 'required|exists:categories,id', ]); // Handle thumbnail upload if ($request->hasFile('thumbnail')) { // Delete old thumbnail if exists if ($product->thumbnail) { Storage::disk('public')->delete($product->thumbnail); } $path = $request->file('thumbnail')->store('thumbnails', 'public'); $validated['thumbnail'] = $path; } $product->update($validated); return redirect()->route('products.show', $product) ->with('success', 'Product updated successfully!'); } /** * Remove the specified product from storage. */ public function destroy(Product $product) { Gate::authorize('delete-product', $product); // Delete thumbnail if exists if ($product->thumbnail) { Storage::disk('public')->delete($product->thumbnail); } $product->delete(); return redirect()->route('products.index') ->with('success', 'Product deleted successfully!'); } /** * Show the product management dashboard for admin/moderator. */ public function manage(Request $request) { Gate::authorize('approve-product'); $query = Product::with(['user', 'category']); // Filter by status if ($request->has('status') && in_array($request->status, ['pending', 'approved', 'rejected'])) { $query->byStatus($request->status); } else { $query->pending(); // Default to pending } $products = $query->latest()->paginate(20); $statusCounts = [ 'pending' => Product::pending()->count(), 'approved' => Product::approved()->count(), 'rejected' => Product::rejected()->count(), ]; return view('products.manage', compact('products', 'statusCounts')); } /** * Approve a product. */ public function approve(Product $product) { Gate::authorize('approve-product'); $product->approve(); return back()->with('success', 'Product approved successfully!'); } /** * Reject a product. */ public function reject(Product $product) { Gate::authorize('reject-product'); $product->reject(); return back()->with('success', 'Product rejected.'); } }