Files
Kol-Manager/resources/views/clients/index.blade.php
I-Fun d3c35ad730 feat: Add notification services for Email, Telegram, and WhatsApp
- Implement EmailNotifier for sending batch and test notifications via email.
- Implement TelegramNotifier for sending batch and test notifications via Telegram.
- Implement WahaNotifier for sending batch and test notifications via WhatsApp using WAHA API.
- Create migration for client_categories table and update clients table to include category_id.
- Create migration for notification_settings table to manage notification configurations.
- Add ClientCategorySeeder to populate default client categories.
- Create manifest.json for PWA support.
- Implement service worker (sw.js) for caching static assets and offline support.
- Add edit event view for modifying scheduled events.
- Create search results view for displaying search queries.
- Develop notification settings view for configuring notification channels and triggers.
2026-04-01 12:46:58 +07:00

172 lines
8.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@extends('layouts.app')
@section('title', 'Clients')
@section('page-title', 'Clients / CRM 👥')
@section('page-subtitle', 'Manage your brand partners and contacts')
@section('content')
{{-- ── Filters bar ─────────────────────────────────────────── --}}
<div class="flex flex-col gap-3 mb-5">
<div class="flex flex-col sm:flex-row sm:items-center gap-3">
{{-- Local text filter --}}
<div class="relative flex-1 max-w-xs">
<span class="absolute left-3 top-2.5 text-gray-400 text-sm">🔍</span>
<input type="text" placeholder="Filter by name…" class="input-soft pl-9 text-sm"
oninput="filterClients(this.value)" id="search-input">
</div>
{{-- Category filter --}}
<form method="GET" action="{{ route('clients.index') }}" class="flex flex-wrap gap-2 items-center" id="filter-form">
<select name="category" class="input-soft text-sm py-2"
onchange="document.getElementById('filter-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' : '' }}>
&nbsp;&nbsp;↳ {{ $child->icon }} {{ $child->name }}
</option>
@endforeach
@endforeach
</select>
<select name="status" class="input-soft text-sm py-2"
onchange="document.getElementById('filter-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>
@if(request('category') || request('status'))
<a href="{{ route('clients.index') }}" class="text-xs text-gray-400 hover:text-gray-600">✕ Clear</a>
@endif
</form>
<a href="{{ route('clients.create') }}" class="btn-sakura text-sm text-center shrink-0">+ Add Client</a>
</div>
{{-- Category pills (top-level only) --}}
<div class="flex gap-2 overflow-x-auto pb-1 -mx-4 px-4 lg:mx-0 lg:px-0">
<a href="{{ route('clients.index') }}"
class="shrink-0 text-xs px-3 py-1.5 rounded-full font-semibold transition-colors
{{ ! request('category') ? 'bg-pink-400 text-white' : 'bg-white border border-pink-200 text-gray-600 hover:bg-pink-50' }}">
All
</a>
@foreach($categories as $cat)
<a href="{{ route('clients.index', ['category' => $cat->id, 'status' => request('status')]) }}"
class="shrink-0 text-xs px-3 py-1.5 rounded-full font-semibold transition-colors whitespace-nowrap
{{ request('category') == $cat->id ? 'bg-pink-400 text-white' : 'bg-white border border-pink-200 text-gray-600 hover:bg-pink-50' }}"
style="{{ request('category') == $cat->id ? '' : 'border-color:' . $cat->color }}">
{{ $cat->icon }} {{ $cat->name }}
</a>
@endforeach
</div>
</div>
{{-- ── 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">
<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>
<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>
</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>
<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">
Del
</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