with(['user', 'category']) ->approved() ->where('created_at', '>=', now()->subDays(7)) ->withCount('upvotes') ->orderBy('upvotes_count', 'desc') ->limit(6) ->get(); // Get recently added products $recentProducts = Product::query() ->with(['user', 'category']) ->approved() ->latest() ->limit(12) ->get(); // Get popular categories with product counts $categories = Category::query() ->withCount(['products' => function($query) { $query->approved(); }]) ->having('products_count', '>', 0) ->orderBy('products_count', 'desc') ->limit(8) ->get(); return view('welcome', compact('trendingProducts', 'recentProducts', 'categories')); } /** * Display a listing of the products. */ public function index(Request $request) { $validated = $request->validate([ 'search' => 'nullable|string|max:255', 'category' => 'nullable|integer|exists:categories,id', 'status' => 'nullable|string|in:pending,approved,rejected', 'date_range' => 'nullable|string|in:today,week,month,year', 'sort' => 'nullable|string|in:newest,oldest,popular', ]); // Build the query with all filters and search $query = Product::query() ->with(['user', 'category']) ->approved() // Only show approved products on the public index ->search($request->search) ->byCategory($request->category) ->dateRange($request->date_range) ->sortBy($request->sort); // Paginate results with query parameters preserved $products = $query->paginate(12)->appends($request->query()); // Get all categories for the filter dropdown $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.'); } }