Files
Kol-Manager/app/Http/Controllers/RateCardController.php
I-Fun 22f03ccca7 Add contract management and invoice settings pages
- Created a new Blade view for managing brand contracts with forms for adding and editing contracts, including client and category selection.
- Implemented success message notifications for contract actions.
- Added a new Blade view for invoice settings, allowing customization of invoice number format, header branding, and default values for new invoices.
- Introduced a new PDF view for generating rate cards with customizable styles based on user profile settings.
- Developed a profile management page for rate cards, enabling users to update their identity, appearance, and visibility settings.
2026-04-01 21:47:34 +07:00

175 lines
6.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use App\Models\RateCard;
use App\Models\RateCardProfile;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;
class RateCardController extends Controller
{
public function index(): View
{
$rateCards = RateCard::orderBy('sort_order')->orderBy('platform')->get();
$profile = RateCardProfile::getSingleton();
return view('rate-cards.index', compact('rateCards', 'profile'));
}
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
{
$profile = RateCardProfile::getSingleton();
$rateCards = RateCard::where('is_active', true)
->orderBy('sort_order')
->orderBy('platform')
->get()
->groupBy('platform');
return view('rate-cards.public', compact('rateCards', 'profile'));
}
// ── Profile Settings ─────────────────────────────────────────
public function profilePage(): View
{
$profile = RateCardProfile::getSingleton();
return view('rate-cards.profile', compact('profile'));
}
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:500',
'show_prices' => 'boolean',
'logo' => 'nullable|image|max:2048',
]);
$profile = RateCardProfile::getSingleton();
if ($request->hasFile('logo')) {
$path = $request->file('logo')->store('profile', 'private');
$validated['logo_path'] = $path;
}
$validated['show_prices'] = $request->boolean('show_prices');
unset($validated['logo']);
$profile->update($validated);
return back()->with('success', '🎨 Profile updated!');
}
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 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', 'portrait');
$filename = 'rate-card-' . now()->format('Y-m-d') . '.pdf';
return $pdf->download($filename);
}
}