feat: extend rate card profiles with brands, terms, and custom HTML, and remove search bar from search index view
This commit is contained in:
@@ -38,7 +38,7 @@ class ClientController extends Controller
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$query = Client::with('category')
|
||||
->withCount(['invoices', 'events', 'contentBriefs'])
|
||||
->withCount(['invoices', 'events', 'contentBriefs', 'mediaFiles'])
|
||||
->latest();
|
||||
|
||||
if ($request->filled('category')) {
|
||||
|
||||
@@ -52,7 +52,7 @@ class MediaFileController extends Controller
|
||||
$this->fileService->uploadAsset(
|
||||
$request->file('file'),
|
||||
$request->input('folder'),
|
||||
$request->input('client_id')
|
||||
$request->filled('client_id') ? (int) $request->input('client_id') : null
|
||||
);
|
||||
|
||||
if ($request->expectsJson() || $request->ajax()) {
|
||||
|
||||
@@ -119,8 +119,11 @@ class RateCardController extends Controller
|
||||
'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',
|
||||
'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',
|
||||
]);
|
||||
|
||||
@@ -131,7 +134,7 @@ class RateCardController extends Controller
|
||||
$validated['logo_path'] = $path;
|
||||
}
|
||||
|
||||
$validated['show_prices'] = $request->boolean('show_prices');
|
||||
$validated['show_prices'] = $request->has('show_prices');
|
||||
unset($validated['logo']);
|
||||
|
||||
$profile->update($validated);
|
||||
@@ -139,6 +142,69 @@ class RateCardController extends Controller
|
||||
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)
|
||||
{
|
||||
$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();
|
||||
@@ -165,7 +231,7 @@ class RateCardController extends Controller
|
||||
->groupBy('platform');
|
||||
|
||||
$pdf = Pdf::loadView('rate-cards.pdf', compact('rateCards', 'profile'))
|
||||
->setPaper('a4', 'portrait');
|
||||
->setPaper('a4', 'landscape');
|
||||
|
||||
$filename = 'rate-card-' . now()->format('Y-m-d') . '.pdf';
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class SearchController extends Controller
|
||||
{
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$q = trim($request->get('q', ''));
|
||||
$q = trim((string) $request->get('q', ''));
|
||||
$results = $q ? $this->search($q) : [];
|
||||
|
||||
return view('search.index', compact('q', 'results'));
|
||||
@@ -26,7 +26,7 @@ class SearchController extends Controller
|
||||
/** Quick AJAX endpoint — returns grouped results for the dropdown */
|
||||
public function quick(Request $request): JsonResponse
|
||||
{
|
||||
$q = trim($request->get('q', ''));
|
||||
$q = trim((string) $request->get('q', ''));
|
||||
|
||||
if (strlen($q) < 2) {
|
||||
return response()->json([]);
|
||||
@@ -138,6 +138,24 @@ class SearchController extends Controller
|
||||
];
|
||||
}
|
||||
|
||||
// ── Notes ───────────────────────────────────────────
|
||||
$notes = \App\Models\Note::where('title', 'LIKE', $like)
|
||||
->orWhere('content', 'LIKE', $like)
|
||||
->limit($limit)->get();
|
||||
|
||||
if ($notes->isNotEmpty()) {
|
||||
$groups[] = [
|
||||
'type' => 'notes',
|
||||
'label' => '📝 Notes',
|
||||
'items' => $notes->map(fn ($n) => [
|
||||
'icon' => '📝',
|
||||
'title' => $n->title ?: 'Untitled',
|
||||
'subtitle' => 'Notes Management',
|
||||
'url' => route('notes.index'),
|
||||
])->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user