275 lines
13 KiB
PHP
275 lines
13 KiB
PHP
<?php
|
|
|
|
use App\Enums\PotentialClientType;
|
|
use App\Models\PotentialClient;
|
|
use Livewire\Volt\Component;
|
|
use Livewire\WithPagination;
|
|
|
|
new class extends Component {
|
|
use WithPagination;
|
|
|
|
public string $search = '';
|
|
public string $typeFilter = '';
|
|
public int $perPage = 10;
|
|
|
|
public ?int $deletingClientId = null;
|
|
public bool $showDeleteModal = false;
|
|
|
|
public function updatedSearch(): void
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatedTypeFilter(): void
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatedPerPage(): void
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function clearFilters(): void
|
|
{
|
|
$this->search = '';
|
|
$this->typeFilter = '';
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function confirmDelete(int $id): void
|
|
{
|
|
$this->deletingClientId = $id;
|
|
$this->showDeleteModal = true;
|
|
}
|
|
|
|
public function cancelDelete(): void
|
|
{
|
|
$this->deletingClientId = null;
|
|
$this->showDeleteModal = false;
|
|
}
|
|
|
|
public function delete(): void
|
|
{
|
|
if ($this->deletingClientId) {
|
|
PotentialClient::find($this->deletingClientId)?->delete();
|
|
session()->flash('success', __('potential-clients.deleted_success'));
|
|
}
|
|
|
|
$this->deletingClientId = null;
|
|
$this->showDeleteModal = false;
|
|
}
|
|
|
|
public function getDeletingClientProperty(): ?PotentialClient
|
|
{
|
|
return $this->deletingClientId ? PotentialClient::find($this->deletingClientId) : null;
|
|
}
|
|
|
|
public function with(): array
|
|
{
|
|
return [
|
|
'potentialClients' => PotentialClient::query()
|
|
->when($this->search, fn ($q) => $q->where(function ($q) {
|
|
$q->where('name', 'like', "%{$this->search}%")
|
|
->orWhere('email', 'like', "%{$this->search}%")
|
|
->orWhere('phone', 'like', "%{$this->search}%");
|
|
}))
|
|
->when($this->typeFilter, fn ($q) => $q->where('type', $this->typeFilter))
|
|
->latest()
|
|
->paginate($this->perPage),
|
|
'types' => PotentialClientType::cases(),
|
|
];
|
|
}
|
|
}; ?>
|
|
|
|
<div>
|
|
<div class="page-header mb-6">
|
|
<div>
|
|
<flux:heading size="xl" class="text-xl sm:text-2xl">{{ __('potential-clients.title') }}</flux:heading>
|
|
<flux:text class="mt-1 text-zinc-500">{{ __('potential-clients.subtitle') }}</flux:text>
|
|
</div>
|
|
<div class="header-actions">
|
|
<flux:button variant="primary" :href="route('admin.potential-clients.create')" wire:navigate icon="plus" class="w-full sm:w-auto justify-center">
|
|
{{ __('potential-clients.add_potential_client') }}
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-6 rounded-lg border border-zinc-200 bg-white p-4">
|
|
<div class="flex flex-col gap-4 sm:flex-row sm:items-end">
|
|
<div class="flex-1">
|
|
<flux:input
|
|
wire:model.live.debounce.300ms="search"
|
|
:placeholder="__('potential-clients.search_placeholder')"
|
|
icon="magnifying-glass"
|
|
/>
|
|
</div>
|
|
<div class="w-full sm:w-48">
|
|
<flux:select wire:model.live="typeFilter">
|
|
<flux:select.option value="">{{ __('potential-clients.all_types') }}</flux:select.option>
|
|
@foreach ($types as $type)
|
|
<flux:select.option value="{{ $type->value }}">
|
|
{{ $type->label() }}
|
|
</flux:select.option>
|
|
@endforeach
|
|
</flux:select>
|
|
</div>
|
|
<div class="w-full sm:w-32">
|
|
<flux:select wire:model.live="perPage">
|
|
<flux:select.option value="10">10 {{ __('potential-clients.per_page') }}</flux:select.option>
|
|
<flux:select.option value="25">25 {{ __('potential-clients.per_page') }}</flux:select.option>
|
|
<flux:select.option value="50">50 {{ __('potential-clients.per_page') }}</flux:select.option>
|
|
</flux:select>
|
|
</div>
|
|
@if ($search || $typeFilter)
|
|
<flux:button wire:click="clearFilters" variant="ghost" icon="x-mark">
|
|
{{ __('potential-clients.clear_filters') }}
|
|
</flux:button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div class="overflow-hidden rounded-lg border border-zinc-200 bg-white">
|
|
<div class="table-scroll-wrapper">
|
|
<table class="min-w-full divide-y divide-zinc-200">
|
|
<thead class="bg-zinc-50">
|
|
<tr>
|
|
<th class="px-6 py-3 text-start text-xs font-medium uppercase tracking-wider text-zinc-500">
|
|
{{ __('potential-clients.fields.name') }}
|
|
</th>
|
|
<th class="px-6 py-3 text-start text-xs font-medium uppercase tracking-wider text-zinc-500">
|
|
{{ __('potential-clients.fields.type') }}
|
|
</th>
|
|
<th class="px-6 py-3 text-start text-xs font-medium uppercase tracking-wider text-zinc-500">
|
|
{{ __('potential-clients.fields.email') }}
|
|
</th>
|
|
<th class="px-6 py-3 text-start text-xs font-medium uppercase tracking-wider text-zinc-500">
|
|
{{ __('potential-clients.fields.phone') }}
|
|
</th>
|
|
<th class="px-6 py-3 text-start text-xs font-medium uppercase tracking-wider text-zinc-500">
|
|
{{ __('potential-clients.created_at') }}
|
|
</th>
|
|
<th class="px-6 py-3 text-end text-xs font-medium uppercase tracking-wider text-zinc-500">
|
|
{{ __('potential-clients.actions') }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-zinc-200 bg-white">
|
|
@forelse ($potentialClients as $potentialClient)
|
|
<tr wire:key="potential-client-{{ $potentialClient->id }}">
|
|
<td class="whitespace-nowrap px-6 py-4">
|
|
<div class="flex items-center gap-3">
|
|
<flux:avatar size="sm" :name="$potentialClient->name ?? '?'" />
|
|
<span class="font-medium text-zinc-900">{{ $potentialClient->name ?? '-' }}</span>
|
|
</div>
|
|
</td>
|
|
<td class="whitespace-nowrap px-6 py-4">
|
|
@switch($potentialClient->type)
|
|
@case(PotentialClientType::Individual)
|
|
<flux:badge color="blue" size="sm">{{ $potentialClient->type->label() }}</flux:badge>
|
|
@break
|
|
@case(PotentialClientType::Company)
|
|
<flux:badge color="purple" size="sm">{{ $potentialClient->type->label() }}</flux:badge>
|
|
@break
|
|
@case(PotentialClientType::Agency)
|
|
<flux:badge color="amber" size="sm">{{ $potentialClient->type->label() }}</flux:badge>
|
|
@break
|
|
@endswitch
|
|
</td>
|
|
<td class="whitespace-nowrap px-6 py-4 text-zinc-600">
|
|
{{ $potentialClient->email ?? '-' }}
|
|
</td>
|
|
<td class="whitespace-nowrap px-6 py-4 text-zinc-600">
|
|
{{ $potentialClient->phone ?? '-' }}
|
|
</td>
|
|
<td class="whitespace-nowrap px-6 py-4 text-zinc-600">
|
|
{{ $potentialClient->created_at->format('Y-m-d') }}
|
|
</td>
|
|
<td class="whitespace-nowrap px-6 py-4 text-end">
|
|
<div class="flex items-center justify-end gap-2">
|
|
<flux:button
|
|
variant="ghost"
|
|
size="sm"
|
|
icon="eye"
|
|
:href="route('admin.potential-clients.show', $potentialClient)"
|
|
wire:navigate
|
|
:title="__('potential-clients.view')"
|
|
/>
|
|
<flux:button
|
|
variant="ghost"
|
|
size="sm"
|
|
icon="pencil"
|
|
:href="route('admin.potential-clients.edit', $potentialClient)"
|
|
wire:navigate
|
|
:title="__('potential-clients.edit')"
|
|
/>
|
|
<flux:button
|
|
variant="ghost"
|
|
size="sm"
|
|
icon="trash"
|
|
wire:click="confirmDelete({{ $potentialClient->id }})"
|
|
:title="__('potential-clients.delete')"
|
|
class="text-red-600 hover:text-red-700"
|
|
/>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="6" class="px-6 py-12 text-center">
|
|
<div class="flex flex-col items-center">
|
|
<flux:icon name="user-group" class="mb-4 h-12 w-12 text-zinc-400" />
|
|
<flux:text class="text-zinc-500">
|
|
@if ($search || $typeFilter)
|
|
{{ __('potential-clients.no_potential_clients_match') }}
|
|
@else
|
|
{{ __('potential-clients.no_potential_clients_found') }}
|
|
@endif
|
|
</flux:text>
|
|
@if ($search || $typeFilter)
|
|
<flux:button wire:click="clearFilters" variant="ghost" class="mt-4">
|
|
{{ __('potential-clients.clear_filters') }}
|
|
</flux:button>
|
|
@else
|
|
<flux:button variant="primary" :href="route('admin.potential-clients.create')" wire:navigate class="mt-4">
|
|
{{ __('potential-clients.add_potential_client') }}
|
|
</flux:button>
|
|
@endif
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
@if ($potentialClients->hasPages())
|
|
<div class="border-t border-zinc-200 bg-zinc-50 px-6 py-4">
|
|
{{ $potentialClients->links() }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Delete Confirmation Modal --}}
|
|
<flux:modal wire:model="showDeleteModal" class="min-w-[22rem]">
|
|
<div class="space-y-6">
|
|
<div>
|
|
<flux:heading size="lg">{{ __('potential-clients.delete_confirm_title') }}</flux:heading>
|
|
<flux:text class="mt-2">{{ __('potential-clients.delete_confirm_message') }}</flux:text>
|
|
@if ($this->deletingClient)
|
|
<flux:text class="mt-2 font-medium">{{ $this->deletingClient->name ?? __('potential-clients.not_provided') }}</flux:text>
|
|
@endif
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<flux:spacer />
|
|
<flux:button variant="ghost" wire:click="cancelDelete">
|
|
{{ __('potential-clients.cancel') }}
|
|
</flux:button>
|
|
<flux:button variant="danger" wire:click="delete">
|
|
{{ __('potential-clients.delete') }}
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
</flux:modal>
|
|
</div>
|