whereNull('parent_id') ->orderBy('sort_order') ->get(); } private function flatCategories(): \Illuminate\Support\Collection { $flat = collect(); foreach ($this->categoryTree() as $parent) { $flat->push($parent); foreach ($parent->children as $child) { $flat->push($child); } } return $flat; } public function index(Request $request): View { $query = Client::with('category') ->withCount(['invoices', 'events', 'contentBriefs']) ->latest(); if ($request->filled('category')) { $query->where('category_id', $request->category); } if ($request->filled('status')) { $query->where('status', $request->status); } $clients = $query->paginate(12)->withQueryString(); $categories = $this->categoryTree(); $statuses = ClientStatus::cases(); return view('clients.index', compact('clients', 'categories', 'statuses')); } public function create(): View { $statuses = ClientStatus::cases(); $categories = $this->flatCategories(); $categoryTree = $this->categoryTree(); return view('clients.create', compact('statuses', 'categories', 'categoryTree')); } public function store(Request $request): RedirectResponse { $validated = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'nullable|email|unique:clients,email', 'phone' => 'nullable|string|max:50', 'company' => 'nullable|string|max:255', 'ig_handle' => 'nullable|string|max:100', 'tiktok_handle' => 'nullable|string|max:100', 'youtube_handle' => 'nullable|string|max:100', 'address_line1' => 'nullable|string|max:255', 'address_line2' => 'nullable|string|max:255', 'city' => 'nullable|string|max:100', 'state' => 'nullable|string|max:100', 'postal_code' => 'nullable|string|max:20', 'country' => 'nullable|string|max:100', 'status' => 'required|in:active,inactive,prospect', 'category_id' => 'nullable|exists:client_categories,id', 'notes' => 'nullable|string', ]); Client::create($validated); return redirect()->route('clients.index') ->with('success', '🐱 Client added successfully!'); } public function show(Client $client): View { $client->load([ 'category', 'events' => fn ($q) => $q->latest()->limit(5), 'invoices' => fn ($q) => $q->latest()->limit(5), 'contentBriefs'=> fn ($q) => $q->latest()->limit(5), 'mediaFiles' => fn ($q) => $q->latest()->limit(10), ]); return view('clients.show', compact('client')); } public function edit(Client $client): View { $statuses = ClientStatus::cases(); $categories = $this->flatCategories(); $categoryTree = $this->categoryTree(); return view('clients.edit', compact('client', 'statuses', 'categories', 'categoryTree')); } public function update(Request $request, Client $client): RedirectResponse { $validated = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'nullable|email|unique:clients,email,' . $client->id, 'phone' => 'nullable|string|max:50', 'company' => 'nullable|string|max:255', 'ig_handle' => 'nullable|string|max:100', 'tiktok_handle' => 'nullable|string|max:100', 'youtube_handle' => 'nullable|string|max:100', 'address_line1' => 'nullable|string|max:255', 'address_line2' => 'nullable|string|max:255', 'city' => 'nullable|string|max:100', 'state' => 'nullable|string|max:100', 'postal_code' => 'nullable|string|max:20', 'country' => 'nullable|string|max:100', 'status' => 'required|in:active,inactive,prospect', 'category_id' => 'nullable|exists:client_categories,id', 'notes' => 'nullable|string', ]); $client->update($validated); return redirect()->route('clients.show', $client) ->with('success', '🐱 Client updated successfully!'); } public function destroy(Client $client): RedirectResponse { $client->delete(); return redirect()->route('clients.index') ->with('success', '🐱 Client removed.'); } }