20-02-2026

This commit is contained in:
Kevin Adametz 2026-02-20 17:57:50 +01:00
parent 854ce02bf6
commit 4d6b4930b2
128 changed files with 18247 additions and 2093 deletions

View file

@ -0,0 +1,220 @@
<?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>