orderBy('platform')->get(); return view('rate-cards.index', compact('rateCards')); } public function create(): View { return view('rate-cards.create'); } public function store(Request $request): RedirectResponse { $validated = $request->validate([ 'service_name' => 'required|string|max:255', 'description' => 'nullable|string', 'platform' => 'required|in:instagram,tiktok,youtube,general', 'content_type' => 'nullable|string|max:50', 'price' => 'required|numeric|min:0', 'currency' => 'required|string|max:10', 'price_unit' => 'required|in:per_content,per_month,per_campaign', 'is_negotiable' => 'boolean', 'sort_order' => 'nullable|integer', ]); $validated['is_negotiable'] = $request->boolean('is_negotiable'); $validated['is_active'] = true; RateCard::create($validated); return redirect()->route('rate-cards.index') ->with('success', '💰 Rate card entry added!'); } public function edit(RateCard $rateCard): View { return view('rate-cards.edit', compact('rateCard')); } public function update(Request $request, RateCard $rateCard): RedirectResponse { $validated = $request->validate([ 'service_name' => 'required|string|max:255', 'description' => 'nullable|string', 'platform' => 'required|in:instagram,tiktok,youtube,general', 'content_type' => 'nullable|string|max:50', 'price' => 'required|numeric|min:0', 'currency' => 'required|string|max:10', 'price_unit' => 'required|in:per_content,per_month,per_campaign', 'is_negotiable' => 'boolean', 'is_active' => 'boolean', 'sort_order' => 'nullable|integer', ]); $validated['is_negotiable'] = $request->boolean('is_negotiable'); $validated['is_active'] = $request->boolean('is_active'); $rateCard->update($validated); return redirect()->route('rate-cards.index') ->with('success', '💰 Rate card updated!'); } public function destroy(RateCard $rateCard): RedirectResponse { $rateCard->delete(); return redirect()->route('rate-cards.index')->with('success', 'Entry removed.'); } // ── Public Page ────────────────────────────────────────────── public function public(): View { $rateCards = RateCard::where('is_active', true) ->orderBy('sort_order') ->orderBy('platform') ->get() ->groupBy('platform'); return view('rate-cards.public', compact('rateCards')); } // ── Profile Settings ───────────────────────────────────────── public function profilePage(): View { $mediaFiles = \App\Models\MediaFile::latest()->get(); return view('rate-cards.profile', compact('mediaFiles')); } public function profileUpdate(Request $request): RedirectResponse { $validated = $request->validate([ 'owner_name' => 'required|string|max:100', 'tagline' => 'nullable|string|max:200', 'whatsapp' => 'nullable|string|max:30', 'ig_handle' => 'nullable|string|max:60', 'tiktok_handle' => 'nullable|string|max:60', 'youtube_handle'=> 'nullable|string|max:60', 'email' => 'nullable|email|max:150', 'bg_color' => 'nullable|string|max:20', 'accent_color' => 'nullable|string|max:20', 'text_color' => 'nullable|string|max:20', 'custom_footer' => 'nullable|string|max:255', 'show_prices' => 'nullable|boolean', 'terms_and_conditions' => 'nullable|string', 'brand_logo_size' => 'nullable|in:small,medium,large', 'contact_person_html' => 'nullable|string', 'logo' => 'nullable|image|max:2048', 'content_showcase' => 'nullable|array', 'content_showcase.*.file_id' => 'required_with:content_showcase|string', 'content_showcase.*.name' => 'required_with:content_showcase|string|max:255', 'content_showcase.*.url' => 'nullable|url', 'content_showcase.*.thumbnail_path' => 'nullable|string', 'content_showcase.*.show_on_public' => 'nullable', 'content_showcase.*.show_on_pdf' => 'nullable', ]); $profile = RateCardProfile::getSingleton(); if ($request->hasFile('logo')) { $path = $request->file('logo')->store('profile', 'private'); $validated['logo_path'] = $path; } $validated['show_prices'] = $request->has('show_prices'); $contentShowcase = $validated['content_showcase'] ?? []; foreach ($contentShowcase as &$item) { $item['show_on_public'] = filter_var($item['show_on_public'] ?? true, FILTER_VALIDATE_BOOLEAN); $item['show_on_pdf'] = filter_var($item['show_on_pdf'] ?? true, FILTER_VALIDATE_BOOLEAN); } $validated['content_showcase'] = $contentShowcase; unset($validated['logo']); $profile->update($validated); return back()->with('success', '🎨 Profile updated!'); } public function uploadLogo(Request $request) { $request->validate([ 'logo' => 'required|image|max:2048', ]); $profile = RateCardProfile::getSingleton(); if ($profile->logo_path) { \Storage::disk('private')->delete($profile->logo_path); } $path = $request->file('logo')->store('profile', 'private'); $profile->update(['logo_path' => $path]); return response()->json([ 'url' => route('files.serve-profile-logo'), ]); } public function deleteLogo() { $profile = RateCardProfile::getSingleton(); if ($profile->logo_path) { \Storage::disk('private')->delete($profile->logo_path); $profile->update(['logo_path' => null]); } return response()->json(['success' => true]); } public function uploadBrandLogo(Request $request) { $request->validate(['logo' => 'required|image|max:2048']); $profile = RateCardProfile::getSingleton(); $path = $request->file('logo')->store('brands', 'public'); $brands = $profile->past_brands ?? []; $brands[] = $path; $profile->update(['past_brands' => $brands]); return response()->json([ 'path' => $path, 'url' => asset('storage/' . $path) ]); } public function deleteBrandLogo(Request $request) { $request->validate(['path' => 'required|string']); $path = $request->input('path'); $profile = RateCardProfile::getSingleton(); $brands = $profile->past_brands ?? []; if (($key = array_search($path, $brands)) !== false) { unset($brands[$key]); $profile->update(['past_brands' => array_values($brands)]); Storage::disk('public')->delete($path); } return response()->json(['success' => true]); } public function serveProfileLogo(): Response { $profile = RateCardProfile::getSingleton(); if (! $profile->logo_path || ! \Storage::disk('private')->exists($profile->logo_path)) { abort(404); } $contents = \Storage::disk('private')->get($profile->logo_path); $mime = \Storage::disk('private')->mimeType($profile->logo_path); return response($contents, 200)->header('Content-Type', $mime); } // ── PDF Download ───────────────────────────────────────────── public function uploadShowcaseThumbnail(Request $request) { $request->validate(['thumbnail' => 'required|image|max:2048']); $path = $request->file('thumbnail')->store('showcase', 'public'); return response()->json([ 'path' => $path, 'url' => asset('storage/' . $path) ]); } public function pdf(): \Illuminate\Http\Response { $profile = RateCardProfile::getSingleton(); $rateCards = RateCard::where('is_active', true) ->orderBy('sort_order') ->orderBy('platform') ->get() ->groupBy('platform'); $pdf = Pdf::loadView('rate-cards.pdf', compact('rateCards', 'profile')) ->setPaper('a4', 'landscape'); $filename = 'rate-card-' . now()->format('Y-m-d') . '.pdf'; return $pdf->download($filename); } }