| <?php |
|
|
| namespace App\Http\Controllers; |
| use App\Models\Product; |
| use App\Models\CustomGame; |
| use Illuminate\Http\Request; |
| use Illuminate\Support\Facades\Storage; |
|
|
| class ProductController extends Controller |
| { |
| |
| public function store(Request $request) |
| { |
| $request->validate([ |
| 'name' => 'required', |
| 'price' => 'required|numeric', |
| 'description' => 'required', |
| 'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048', |
| 'Amount' => 'required|numeric', |
| 'game' => 'nullable|string' |
| ]); |
|
|
| $product = new Product($request->only(['name', 'price', 'description', 'Amount', 'game'])); |
|
|
| if ($request->hasFile('image')) { |
| $imagePath = $request->file('image')->store('products', 'public'); |
| $product->image = $imagePath; |
| } |
|
|
| $product->save(); |
|
|
| return redirect()->back()->with('success', 'Product created successfully'); |
| } |
| public function show($category, $product_name) |
| { |
| $product = Product::where('game', $category) |
| ->where('slug', $product_name) |
| ->firstOrFail(); |
| return view('show', compact('product')); |
| } |
|
|
| public function categoryProducts($category) |
| { |
| $products = Product::where('game', $category)->get(); |
| |
| |
| $customGames = CustomGame::orderBy('name')->get(); |
| |
| return view('category_products', compact('products', 'category', 'customGames')); |
| } |
| |
| public function edit($id) |
| { |
| $product = Product::findOrFail($id); |
| return response()->json($product); |
| } |
| public function listOFproduct(Request $request) |
| { |
| $query = Product::query(); |
|
|
| |
| if ($request->filled('game')) { |
| $query->where('game', $request->input('game')); |
| } |
|
|
| |
| if ($request->filled('stock')) { |
| $stock = $request->input('stock'); |
| switch ($stock) { |
| case 'in_stock': |
| $query->where('Amount', '>', 5); |
| break; |
| case 'low_stock': |
| $query->whereBetween('Amount', [1, 5]); |
| break; |
| case 'out_of_stock': |
| $query->where('Amount', 0); |
| break; |
| } |
| } |
|
|
| |
| if ($request->filled('search')) { |
| $search = $request->input('search'); |
| $query->where(function($q) use ($search) { |
| $q->where('name', 'like', '%' . $search . '%') |
| ->orWhere('description', 'like', '%' . $search . '%'); |
| }); |
| } |
|
|
| $products = $query->orderBy('created_at', 'desc')->get(); |
| |
| |
| $customGames = CustomGame::orderBy('name')->get(); |
| |
| return view('table_product', compact('products', 'customGames')); |
| } |
| public function update(Request $request, $id) |
| { |
| $request->validate([ |
| 'name' => 'required', |
| 'price' => 'required|numeric', |
| 'description' => 'required', |
| 'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048', |
| 'Amount' => 'required|numeric', |
| 'game' => 'nullable|string' |
| ]); |
|
|
| $product = Product::findOrFail($id); |
| $product->update($request->only(['name', 'price', 'description', 'Amount', 'game'])); |
|
|
| if ($request->hasFile('image')) { |
| |
| if ($product->image && Storage::disk('public')->exists($product->image)) { |
| Storage::disk('public')->delete($product->image); |
| } |
| |
| $imagePath = $request->file('image')->store('products', 'public'); |
| $product->image = $imagePath; |
| $product->save(); |
| } |
|
|
| return redirect()->back()->with('success', 'Product updated successfully'); |
| } |
|
|
| public function destroy($id) |
| { |
| try { |
| $product = Product::findOrFail($id); |
| |
| |
| if ($product->image && Storage::disk('public')->exists($product->image)) { |
| Storage::disk('public')->delete($product->image); |
| } |
| |
| $product->delete(); |
|
|
| return back()->with('success', 'Product deleted successfully'); |
| } catch (\Exception $e) { |
| return back()->with('error', 'Failed to delete product: ' . $e->getMessage()); |
| } |
| } |
|
|
| public function categories() |
| { |
| |
| $categoryCounts = [ |
| 'Genshin' => Product::where('game', 'Genshin')->count(), |
| 'Starrail' => Product::where('game', 'Starrail')->count(), |
| 'WutheringWave' => Product::where('game', 'WutheringWave')->count(), |
| ]; |
|
|
| |
| $customGames = CustomGame::orderBy('name')->get(); |
|
|
| return view('categories', compact('categoryCounts', 'customGames')); |
| } |
|
|
| public function getByCategory($game) |
| { |
| $products = Product::where('game', $game)->get(); |
| |
| |
| $productsWithSales = $products->map(function ($product) { |
| $salesCount = \App\Models\Order::where('cart_data', 'LIKE', '%"product_id":' . $product->id . '%') |
| ->where('status', 'completed') |
| ->count(); |
| $product->sales_count = $salesCount; |
| return $product; |
| }); |
| |
| return response()->json($productsWithSales); |
| } |
|
|
| public function storeCustomGame(Request $request) |
| { |
| try { |
| $request->validate([ |
| 'name' => 'required|string|max:50|unique:custom_games,name', |
| 'icon' => 'nullable|string', |
| 'color_gradient' => 'nullable|string' |
| ]); |
|
|
| $customGame = CustomGame::create([ |
| 'name' => $request->name, |
| 'icon' => $request->icon ?? 'fas fa-gamepad', |
| 'color_gradient' => $request->color_gradient ?? 'from-purple-500 to-blue-500' |
| ]); |
|
|
| return response()->json([ |
| 'success' => true, |
| 'message' => "Custom game '{$request->name}' has been created successfully!", |
| 'data' => $customGame |
| ]); |
|
|
| } catch (\Exception $e) { |
| return response()->json([ |
| 'success' => false, |
| 'message' => 'Failed to create custom game: ' . $e->getMessage() |
| ], 500); |
| } |
| } |
|
|
| public function deleteCustomGame($gameName) |
| { |
| try { |
| |
| $productsCount = Product::where('game', $gameName)->count(); |
| |
| if ($productsCount > 0) { |
| return response()->json([ |
| 'success' => false, |
| 'message' => "Cannot delete '{$gameName}' because {$productsCount} product(s) are still using this category. Please reassign or delete those products first." |
| ], 400); |
| } |
| |
| |
| $customGame = CustomGame::where('name', $gameName)->first(); |
| if ($customGame) { |
| $customGame->delete(); |
| } |
| |
| return response()->json([ |
| 'success' => true, |
| 'message' => "Custom game '{$gameName}' has been deleted successfully!" |
| ]); |
| |
| } catch (\Exception $e) { |
| return response()->json([ |
| 'success' => false, |
| 'message' => 'Failed to delete custom game: ' . $e->getMessage() |
| ], 500); |
| } |
| } |
|
|
| public function search(Request $request) |
| { |
| $query = $request->get('q', ''); |
| |
| if (strlen($query) < 2) { |
| return response()->json(['games' => [], 'products' => []]); |
| } |
|
|
| |
| $mainGames = [ |
| [ |
| 'name' => 'Genshin Impact', |
| 'slug' => 'Genshin', |
| 'icon' => 'fas fa-star', |
| 'count' => Product::where('game', 'Genshin')->count(), |
| 'description' => 'Discover premium digital content for your favorite games', |
| 'gradient' => 'from-yellow-500 to-orange-500', |
| 'logo' => asset('images/games/genshin-logo.png'), |
| 'category' => 'RPG', |
| 'popularity' => 'Popular' |
| ], |
| [ |
| 'name' => 'Honkai: Star Rail', |
| 'slug' => 'Starrail', |
| 'icon' => 'fas fa-rocket', |
| 'count' => Product::where('game', 'Starrail')->count(), |
| 'description' => 'Space fantasy RPG with strategic combat', |
| 'gradient' => 'from-purple-500 to-pink-500', |
| 'logo' => asset('images/games/starrail-logo.png'), |
| 'category' => 'RPG', |
| 'popularity' => 'Featured' |
| ], |
| [ |
| 'name' => 'Wuthering Waves', |
| 'slug' => 'WutheringWave', |
| 'icon' => 'fas fa-wave-square', |
| 'count' => Product::where('game', 'WutheringWave')->count(), |
| 'description' => 'Open-world action RPG with stunning visuals', |
| 'gradient' => 'from-cyan-500 to-blue-500', |
| 'logo' => asset('images/games/wuthering-logo.png'), |
| 'category' => 'Action RPG', |
| 'popularity' => 'New' |
| ], |
| [ |
| 'name' => 'Zenless Zone Zero', |
| 'slug' => 'ZenlessZoneZero', |
| 'icon' => 'fas fa-city', |
| 'count' => Product::where('game', 'ZenlessZoneZero')->count(), |
| 'description' => 'Urban fantasy action game', |
| 'gradient' => 'from-red-500 to-pink-500', |
| 'logo' => asset('images/games/zenless-logo.png'), |
| 'category' => 'Action', |
| 'popularity' => 'Trending' |
| ], |
| [ |
| 'name' => 'Arknights', |
| 'slug' => 'Arknights', |
| 'icon' => 'fas fa-chess-knight', |
| 'count' => Product::where('game', 'Arknights')->count(), |
| 'description' => 'Strategic tower defense with anime characters', |
| 'gradient' => 'from-indigo-500 to-purple-500', |
| 'logo' => asset('images/games/arknights-logo.png'), |
| 'category' => 'Strategy', |
| 'popularity' => 'Classic' |
| ], |
| [ |
| 'name' => 'Azur Lane', |
| 'slug' => 'AzurLane', |
| 'icon' => 'fas fa-ship', |
| 'count' => Product::where('game', 'AzurLane')->count(), |
| 'description' => 'Naval warfare with anthropomorphic ships', |
| 'gradient' => 'from-blue-500 to-teal-500', |
| 'logo' => asset('images/games/azurlane-logo.png'), |
| 'category' => 'Strategy', |
| 'popularity' => 'Popular' |
| ], |
| ]; |
|
|
| |
| $customGames = CustomGame::all()->map(function($game) { |
| return [ |
| 'name' => $game->name, |
| 'slug' => $game->name, |
| 'icon' => $game->icon, |
| 'count' => Product::where('game', $game->name)->count(), |
| 'description' => 'Custom game category with unique items', |
| 'gradient' => $game->color_gradient, |
| 'logo' => asset('images/games/custom-logo.png'), |
| 'category' => 'Custom', |
| 'popularity' => 'Special' |
| ]; |
| }); |
|
|
| $allGames = collect($mainGames)->concat($customGames); |
| |
| |
| $matchingGames = $allGames->filter(function($game) use ($query) { |
| return stripos($game['name'], $query) !== false; |
| })->take(5)->values(); |
|
|
| |
| $products = Product::where('name', 'like', "%{$query}%") |
| ->orWhere('description', 'like', "%{$query}%") |
| ->orWhere('game', 'like', "%{$query}%") |
| ->take(8) |
| ->get() |
| ->map(function($product) { |
| |
| $salesCount = \App\Models\Order::where('status', 'completed') |
| ->where('cart_data', 'LIKE', '%"id":' . $product->id . '%') |
| ->get() |
| ->sum(function($order) use ($product) { |
| $cartData = json_decode($order->cart_data, true); |
| $quantity = 0; |
| if (is_array($cartData)) { |
| foreach ($cartData as $item) { |
| if (isset($item['id']) && $item['id'] == $product->id) { |
| $quantity += $item['quantity'] ?? 1; |
| } |
| } |
| } |
| return $quantity; |
| }); |
|
|
| |
| $rating = $salesCount > 0 ? min(5.0, 3.5 + ($salesCount / 100)) : 4.0; |
|
|
| return [ |
| 'id' => $product->id, |
| 'name' => $product->name, |
| 'slug' => $product->slug ?? strtolower(str_replace(' ', '-', $product->name)), |
| 'game' => $product->game, |
| 'game_slug' => $product->game, |
| 'price' => number_format($product->price, 2), |
| 'original_price' => $product->price, |
| 'image' => $product->image ? asset($product->image) : 'https://via.placeholder.com/150x150/374151/ffffff?text=No+Image', |
| 'description' => $product->description, |
| 'short_description' => strlen($product->description) > 100 ? substr($product->description, 0, 100) . '...' : $product->description, |
| 'amount' => $product->Amount, |
| 'stock_status' => $product->Amount > 10 ? 'In Stock (' . $product->Amount . ')' : |
| ($product->Amount > 0 ? 'Low Stock (' . $product->Amount . ')' : 'Out of Stock'), |
| 'stock_color' => $product->Amount > 10 ? 'text-green-400' : |
| ($product->Amount > 0 ? 'text-yellow-400' : 'text-red-400'), |
| 'stock_bg' => $product->Amount > 10 ? 'bg-green-500/20' : |
| ($product->Amount > 0 ? 'bg-yellow-500/20' : 'bg-red-500/20'), |
| 'created_at' => $product->created_at->format('M d, Y'), |
| 'is_new' => $product->created_at->diffInDays(now()) <= 7, |
| 'rating' => round($rating, 1), |
| 'sales_count' => $salesCount, |
| 'total_revenue' => $salesCount * $product->price, |
| 'availability' => $product->Amount > 0 ? 'Available' : 'Sold Out', |
| 'category_icon' => $this->getGameIcon($product->game), |
| 'popularity_score' => $salesCount > 50 ? 'Hot' : ($salesCount > 20 ? 'Popular' : 'New') |
| ]; |
| }); |
|
|
| return response()->json([ |
| 'games' => $matchingGames, |
| 'products' => $products |
| ]); |
| } |
|
|
| private function getGameIcon($game) |
| { |
| $icons = [ |
| 'Genshin' => 'fas fa-star', |
| 'Starrail' => 'fas fa-rocket', |
| 'WutheringWave' => 'fas fa-wave-square', |
| 'ZenlessZoneZero' => 'fas fa-city', |
| 'Arknights' => 'fas fa-chess-knight', |
| 'AzurLane' => 'fas fa-ship', |
| ]; |
|
|
| return $icons[$game] ?? 'fas fa-gamepad'; |
| } |
| } |
|
|