193 lines
11 KiB
PHP
193 lines
11 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('title', 'Clients')
|
||
@section('page-title', 'Clients👥')
|
||
@section('page-subtitle', 'Manage your brand partners and contacts')
|
||
|
||
@section('content')
|
||
|
||
{{-- ── Toolbar + collapsible filter ───────────────────────── --}}
|
||
<div x-data="{ open: {{ request('category') || request('status') ? 'true' : 'false' }} }">
|
||
|
||
<div class="flex items-center justify-between gap-2 mb-3">
|
||
<div class="flex items-center gap-2">
|
||
<a href="{{ route('clients.create') }}" class="btn-sakura text-sm">+ Add Client</a>
|
||
@if(request('category') || request('status'))
|
||
<a href="{{ route('clients.index') }}"
|
||
class="text-xs px-3 py-2 rounded-full border border-gray-200 text-gray-500 hover:bg-gray-50 flex items-center gap-1">
|
||
✕ Clear filters
|
||
</a>
|
||
@endif
|
||
</div>
|
||
<button @click="open = !open"
|
||
class="flex items-center gap-1.5 text-xs px-3 py-2 rounded-full border transition-colors"
|
||
:class="open ? 'border-pink-300 bg-pink-50 text-pink-600' : 'border-gray-200 text-gray-500 hover:bg-gray-50'">
|
||
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24"
|
||
stroke="currentColor" stroke-width="2">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M3 4h18M7 10h10M11 16h2" />
|
||
</svg>
|
||
Filter
|
||
@if(request('category') || request('status'))
|
||
<span class="w-2 h-2 rounded-full bg-pink-400 inline-block ml-0.5"></span>
|
||
@endif
|
||
</button>
|
||
</div>
|
||
|
||
{{-- ── Filters panel (collapsible) ────────────────────────── --}}
|
||
<div x-show="open" x-transition.duration.150ms>
|
||
<form method="GET" action="{{ route('clients.index') }}" id="filter-form" class="cat-card p-3 mb-4">
|
||
{{-- Row 1: search + dropdowns --}}
|
||
<div class="grid grid-cols-1 sm:grid-cols-12 gap-3 items-center">
|
||
{{-- Search --}}
|
||
<div class="relative sm:col-span-5 lg:col-span-6 w-full">
|
||
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm pointer-events-none"></span>
|
||
<input type="text" placeholder="🔍 Filter by name…" class="input-soft pl-9 text-sm py-2 w-full"
|
||
oninput="filterClients(this.value)" id="search-input">
|
||
</div>
|
||
|
||
{{-- Category dropdown --}}
|
||
<div class="sm:col-span-4 lg:col-span-3 w-full">
|
||
<select name="category" class="input-soft text-sm py-2 w-full" onchange="this.form.submit()">
|
||
<option value="">All Categories</option>
|
||
@foreach($categories as $parent)
|
||
<option value="{{ $parent->id }}" {{ request('category') == $parent->id ? 'selected' : '' }}>
|
||
{{ $parent->icon }} {{ $parent->name }}
|
||
</option>
|
||
@foreach($parent->children as $child)
|
||
<option value="{{ $child->id }}" {{ request('category') == $child->id ? 'selected' : '' }}>
|
||
↳ {{ $child->name }}
|
||
</option>
|
||
@endforeach
|
||
@endforeach
|
||
</select>
|
||
</div>
|
||
|
||
{{-- Status dropdown --}}
|
||
<div class="sm:col-span-3 lg:col-span-3 w-full">
|
||
<select name="status" class="input-soft text-sm py-2 w-full" onchange="this.form.submit()">
|
||
<option value="">All Statuses</option>
|
||
@foreach($statuses as $s)
|
||
<option value="{{ $s->value }}" {{ request('status') === $s->value ? 'selected' : '' }}>
|
||
{{ $s->label() }}
|
||
</option>
|
||
@endforeach
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
</form>
|
||
</div>
|
||
</div>{{-- end x-data --}}
|
||
|
||
{{-- ── Client grid ─────────────────────────────────────────── --}}
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-4" id="clients-grid">
|
||
@forelse($clients as $client)
|
||
<div class="cat-card p-4 flex flex-col gap-3 hover:shadow-md transition-shadow duration-200"
|
||
data-name="{{ strtolower($client->name) }} {{ strtolower($client->company ?? '') }}">
|
||
|
||
<div class="flex items-start gap-3">
|
||
@if($client->avatar)
|
||
<div class="w-11 h-11 rounded-2xl overflow-hidden shrink-0 shadow-sm ring-2 ring-pink-100">
|
||
<img src="{{ \Illuminate\Support\Facades\Storage::url($client->avatar) }}" alt="{{ $client->name }}"
|
||
class="w-full h-full object-cover">
|
||
</div>
|
||
@else
|
||
<div class="w-11 h-11 rounded-2xl flex items-center justify-center text-white font-bold text-base shadow-sm shrink-0"
|
||
style="background: linear-gradient(135deg, {{ $client->category?->color ?? '#FFB7C5' }}, #E8D5F5);">
|
||
{{ $client->initials }}
|
||
</div>
|
||
@endif
|
||
<div class="flex-1 min-w-0">
|
||
<div class="flex items-center gap-2 flex-wrap">
|
||
<h3 class="font-bold text-gray-800 text-sm truncate">{{ $client->name }}</h3>
|
||
<span class="badge {{ $client->status->badgeClass() }} text-xs shrink-0">
|
||
{{ $client->status->label() }}
|
||
</span>
|
||
</div>
|
||
@if($client->company)
|
||
<div class="text-xs text-gray-400 truncate">{{ $client->company }}</div>
|
||
@endif
|
||
@if($client->category)
|
||
<div class="text-xs mt-0.5"
|
||
style="color: {{ $client->category->color === '#FDFD96' ? '#8B8000' : $client->category->color }}">
|
||
{{ $client->category->icon }} {{ $client->category->name }}
|
||
@if($client->category->parent)
|
||
<span class="text-gray-300 mx-0.5">·</span>
|
||
{{ $client->category->parent->name }}
|
||
@endif
|
||
</div>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex flex-wrap gap-1.5">
|
||
@if($client->ig_handle)
|
||
<span class="text-xs bg-pink-50 text-pink-600 px-2 py-0.5 rounded-full">📸 {{ $client->ig_handle }}</span>
|
||
@endif
|
||
@if($client->tiktok_handle)
|
||
<span class="text-xs bg-purple-50 text-purple-600 px-2 py-0.5 rounded-full">🎵
|
||
{{ $client->tiktok_handle }}</span>
|
||
@endif
|
||
@if($client->youtube_handle)
|
||
<span class="text-xs bg-red-50 text-red-600 px-2 py-0.5 rounded-full">▶️
|
||
{{ $client->youtube_handle }}</span>
|
||
@endif
|
||
</div>
|
||
|
||
<div class="flex gap-3 text-xs text-gray-500">
|
||
<span>📅 {{ $client->events_count }}</span>
|
||
<span>🧾 {{ $client->invoices_count }}</span>
|
||
<span>🎬 {{ $client->content_briefs_count }}</span>
|
||
<span>📁 {{ $client->media_files_count ?? 0 }}</span>
|
||
</div>
|
||
|
||
@if($client->email || $client->city)
|
||
<div class="text-xs text-gray-400 space-y-0.5">
|
||
@if($client->email)
|
||
<div class="truncate">✉️ {{ $client->email }}</div> @endif
|
||
@if($client->city)
|
||
<div>📍 {{ $client->city }}{{ $client->country ? ', ' . $client->country : '' }}</div> @endif
|
||
</div>
|
||
@endif
|
||
|
||
<div class="flex gap-2 pt-2 border-t border-pink-50">
|
||
<a href="{{ route('clients.show', $client) }}" class="btn-sakura text-xs py-1.5 flex-1 text-center">View</a>
|
||
<a href="{{ route('clients.edit', $client) }}"
|
||
class="flex-1 text-center text-xs py-1.5 px-3 rounded-full border border-pink-200 text-gray-600 hover:bg-pink-50">
|
||
Edit
|
||
</a>
|
||
{{-- Share button disabled --}}
|
||
<form action="{{ route('clients.destroy', $client) }}" method="POST"
|
||
onsubmit="return confirm('Remove this client?')">
|
||
@csrf @method('DELETE')
|
||
<button class="text-xs py-1.5 px-3 rounded-full border border-red-100 text-red-400 hover:bg-red-50">
|
||
✕
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
@empty
|
||
<div class="col-span-full text-center py-16 text-gray-400">
|
||
<span class="text-5xl block mb-3">🐱</span>
|
||
<p class="text-base font-medium">No clients found!</p>
|
||
@if(request('category') || request('status'))
|
||
<a href="{{ route('clients.index') }}" class="text-sm text-pink-500 mt-2 block">Clear filters</a>
|
||
@else
|
||
<a href="{{ route('clients.create') }}" class="btn-sakura mt-4 inline-block">Add your first client</a>
|
||
@endif
|
||
</div>
|
||
@endforelse
|
||
</div>
|
||
|
||
{{ $clients->links() }}
|
||
|
||
@push('scripts')
|
||
<script>
|
||
function filterClients(query) {
|
||
document.querySelectorAll('#clients-grid > div[data-name]').forEach(card => {
|
||
card.style.display = card.dataset.name.includes(query.toLowerCase()) ? '' : 'none';
|
||
});
|
||
}
|
||
</script>
|
||
@endpush
|
||
@endsection |