220 lines
8.7 KiB
PHP
220 lines
8.7 KiB
PHP
<?php
|
||
|
||
use App\Models\Partner;
|
||
use Livewire\Volt\Component;
|
||
use Livewire\WithPagination;
|
||
use function Livewire\Volt\{layout, title};
|
||
|
||
layout('components.layouts.app');
|
||
title('Partner-Verwaltung');
|
||
|
||
new class extends Component {
|
||
use WithPagination;
|
||
|
||
public string $search = '';
|
||
public string $typeFilter = '';
|
||
public bool $onlyActive = false;
|
||
|
||
public function updatedSearch(): void
|
||
{
|
||
$this->resetPage();
|
||
}
|
||
|
||
public function updatedTypeFilter(): void
|
||
{
|
||
$this->resetPage();
|
||
}
|
||
|
||
public function updatedOnlyActive(): void
|
||
{
|
||
$this->resetPage();
|
||
}
|
||
|
||
public function with(): array
|
||
{
|
||
$this->authorize('viewAny', Partner::class);
|
||
|
||
$partners = Partner::query()
|
||
->with(['hub', 'users'])
|
||
->when($this->search, fn ($q) => $q->where(function ($q) {
|
||
$q->where('company_name', 'like', "%{$this->search}%")
|
||
->orWhere('city', 'like', "%{$this->search}%")
|
||
->orWhere('email', 'like', "%{$this->search}%");
|
||
}))
|
||
->when($this->typeFilter, fn ($q) => $q->where('type', $this->typeFilter))
|
||
->when($this->onlyActive, fn ($q) => $q->where('is_active', true))
|
||
->orderBy('company_name')
|
||
->paginate(20);
|
||
|
||
return [
|
||
'partners' => $partners,
|
||
'totalCount' => Partner::count(),
|
||
'activeCount' => Partner::where('is_active', true)->count(),
|
||
];
|
||
}
|
||
}; ?>
|
||
|
||
<div class="space-y-6 p-6">
|
||
{{-- Header --}}
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<flux:heading size="xl" class="mb-2">{{ __('Partner-Verwaltung') }}</flux:heading>
|
||
<flux:subheading>{{ __('Alle registrierten Partner auf der Plattform') }}</flux:subheading>
|
||
</div>
|
||
<flux:button
|
||
href="{{ route('admin.partners.invite') }}"
|
||
variant="primary"
|
||
icon="plus"
|
||
>
|
||
{{ __('Partner einladen') }}
|
||
</flux:button>
|
||
</div>
|
||
|
||
{{-- Statistics --}}
|
||
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||
<flux:card class="shadow-elegant">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<flux:subheading>{{ __('Gesamt') }}</flux:subheading>
|
||
<flux:heading size="2xl" class="mt-2">{{ $totalCount }}</flux:heading>
|
||
</div>
|
||
<div class="flex h-12 w-12 items-center justify-center rounded-lg bg-blue-100 dark:bg-blue-900/20">
|
||
<flux:icon.building-office class="h-6 w-6 text-blue-600 dark:text-blue-400" />
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
|
||
<flux:card class="shadow-elegant">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<flux:subheading>{{ __('Aktiv') }}</flux:subheading>
|
||
<flux:heading size="2xl" class="mt-2">{{ $activeCount }}</flux:heading>
|
||
</div>
|
||
<div class="flex h-12 w-12 items-center justify-center rounded-lg bg-green-100 dark:bg-green-900/20">
|
||
<flux:icon.check-circle class="h-6 w-6 text-green-600 dark:text-green-400" />
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
|
||
<flux:card class="shadow-elegant">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<flux:subheading>{{ __('Inaktiv') }}</flux:subheading>
|
||
<flux:heading size="2xl" class="mt-2">{{ $totalCount - $activeCount }}</flux:heading>
|
||
</div>
|
||
<div class="flex h-12 w-12 items-center justify-center rounded-lg bg-zinc-100 dark:bg-zinc-800">
|
||
<flux:icon.x-circle class="h-6 w-6 text-zinc-600 dark:text-zinc-400" />
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
</div>
|
||
|
||
{{-- Filter --}}
|
||
<flux:card class="shadow-elegant">
|
||
<div class="flex flex-wrap items-end gap-4">
|
||
<flux:field class="flex-1">
|
||
<flux:label>{{ __('Suche') }}</flux:label>
|
||
<flux:input
|
||
wire:model.live.debounce.300ms="search"
|
||
placeholder="{{ __('Firmenname, Stadt oder E-Mail...') }}"
|
||
icon="magnifying-glass"
|
||
/>
|
||
</flux:field>
|
||
|
||
<flux:field>
|
||
<flux:label>{{ __('Partner-Typ') }}</flux:label>
|
||
<flux:select wire:model.live="typeFilter">
|
||
<flux:select.option value="">{{ __('Alle Typen') }}</flux:select.option>
|
||
<flux:select.option value="retailer">{{ __('Händler') }}</flux:select.option>
|
||
<flux:select.option value="manufacturer">{{ __('Hersteller') }}</flux:select.option>
|
||
<flux:select.option value="estate_agent">{{ __('Makler') }}</flux:select.option>
|
||
</flux:select>
|
||
</flux:field>
|
||
|
||
<flux:field>
|
||
<flux:label>{{ __('Status') }}</flux:label>
|
||
<flux:switch wire:model.live="onlyActive" label="{{ __('Nur aktive') }}" />
|
||
</flux:field>
|
||
</div>
|
||
</flux:card>
|
||
|
||
{{-- Partner-Tabelle --}}
|
||
<flux:card class="shadow-elegant">
|
||
<flux:table>
|
||
<flux:table.columns>
|
||
<flux:table.column>{{ __('Partner') }}</flux:table.column>
|
||
<flux:table.column>{{ __('Typ') }}</flux:table.column>
|
||
<flux:table.column>{{ __('Hub') }}</flux:table.column>
|
||
<flux:table.column>{{ __('Benutzer') }}</flux:table.column>
|
||
<flux:table.column>{{ __('Status') }}</flux:table.column>
|
||
<flux:table.column></flux:table.column>
|
||
</flux:table.columns>
|
||
|
||
<flux:table.rows>
|
||
@forelse ($partners as $partner)
|
||
<flux:table.row>
|
||
<flux:table.cell>
|
||
<div class="font-medium text-zinc-900 dark:text-white">
|
||
{{ $partner->company_name }}
|
||
</div>
|
||
@if ($partner->city)
|
||
<div class="text-sm text-zinc-500">{{ $partner->zip }} {{ $partner->city }}</div>
|
||
@endif
|
||
</flux:table.cell>
|
||
|
||
<flux:table.cell>
|
||
<flux:badge size="sm" color="{{ match($partner->type?->value ?? $partner->type) {
|
||
'retailer' => 'blue',
|
||
'manufacturer' => 'purple',
|
||
'estate_agent' => 'amber',
|
||
default => 'zinc'
|
||
} }}">
|
||
{{ $partner->type?->label() ?? ucfirst($partner->type ?? '–') }}
|
||
</flux:badge>
|
||
</flux:table.cell>
|
||
|
||
<flux:table.cell>
|
||
{{ $partner->hub?->name ?? '–' }}
|
||
</flux:table.cell>
|
||
|
||
<flux:table.cell>
|
||
{{ $partner->users->count() }}
|
||
</flux:table.cell>
|
||
|
||
<flux:table.cell>
|
||
@if ($partner->is_active)
|
||
<flux:badge size="sm" color="green">{{ __('Aktiv') }}</flux:badge>
|
||
@else
|
||
<flux:badge size="sm" color="zinc">{{ __('Inaktiv') }}</flux:badge>
|
||
@endif
|
||
</flux:table.cell>
|
||
|
||
<flux:table.cell>
|
||
<flux:button
|
||
href="{{ route('admin.partners.edit', $partner->id) }}"
|
||
size="sm"
|
||
variant="ghost"
|
||
icon="pencil"
|
||
>
|
||
{{ __('Bearbeiten') }}
|
||
</flux:button>
|
||
</flux:table.cell>
|
||
</flux:table.row>
|
||
@empty
|
||
<flux:table.row>
|
||
<flux:table.cell colspan="6" class="py-12 text-center text-zinc-500">
|
||
<flux:icon.building-office class="mx-auto mb-2 h-12 w-12 text-zinc-400" />
|
||
<div>{{ __('Keine Partner gefunden') }}</div>
|
||
</flux:table.cell>
|
||
</flux:table.row>
|
||
@endforelse
|
||
</flux:table.rows>
|
||
</flux:table>
|
||
|
||
@if ($partners->hasPages())
|
||
<div class="mt-4">
|
||
{{ $partners->links() }}
|
||
</div>
|
||
@endif
|
||
</flux:card>
|
||
</div>
|