398 lines
17 KiB
PHP
398 lines
17 KiB
PHP
<?php
|
||
|
||
use function Livewire\Volt\{state, mount, computed};
|
||
|
||
state([
|
||
'search' => '',
|
||
'statusFilter' => 'all',
|
||
'categoryFilter' => 'all',
|
||
'sortBy' => 'created_at',
|
||
'sortDirection' => 'desc',
|
||
]);
|
||
|
||
// Dummy-Produkte für die Anzeige
|
||
$products = computed(function () {
|
||
return [
|
||
[
|
||
'id' => 1,
|
||
'b2in_number' => 'B2IN-000471',
|
||
'supplier_number' => 'SOFA-ALBA-3S-ANTHR',
|
||
'name' => 'Sofa ALBA 3-Sitzer',
|
||
'brand' => 'Möbelwerk Nord',
|
||
'category' => 'Wohnzimmer > Sofas',
|
||
'status' => 'active',
|
||
'price' => 1250.00,
|
||
'stock_status' => 'in_stock',
|
||
'created_at' => '2025-11-04',
|
||
'image' => null,
|
||
],
|
||
[
|
||
'id' => 2,
|
||
'b2in_number' => 'B2IN-000472',
|
||
'supplier_number' => 'CHAIR-NORDIC-OAK',
|
||
'name' => 'Stuhl Nordic Eiche',
|
||
'brand' => 'Design Studio',
|
||
'category' => 'Esszimmer > Stühle',
|
||
'status' => 'active',
|
||
'price' => 189.00,
|
||
'stock_status' => 'in_stock',
|
||
'created_at' => '2025-11-05',
|
||
'image' => null,
|
||
],
|
||
[
|
||
'id' => 3,
|
||
'b2in_number' => 'B2IN-000473',
|
||
'supplier_number' => 'BED-LUNA-180',
|
||
'name' => 'Bett Luna 180x200',
|
||
'brand' => 'Schlafwelt',
|
||
'category' => 'Schlafzimmer > Betten',
|
||
'status' => 'draft',
|
||
'price' => 899.00,
|
||
'stock_status' => 'on_order',
|
||
'created_at' => '2025-11-03',
|
||
'image' => null,
|
||
],
|
||
[
|
||
'id' => 4,
|
||
'b2in_number' => 'B2IN-000474',
|
||
'supplier_number' => 'TABLE-OAK-EXTEND',
|
||
'name' => 'Esstisch Eiche ausziehbar',
|
||
'brand' => 'Tischmanufaktur',
|
||
'category' => 'Esszimmer > Tische',
|
||
'status' => 'active',
|
||
'price' => 1450.00,
|
||
'stock_status' => 'in_stock',
|
||
'created_at' => '2025-10-28',
|
||
'image' => null,
|
||
],
|
||
[
|
||
'id' => 5,
|
||
'b2in_number' => 'B2IN-000475',
|
||
'supplier_number' => 'WARDROBE-CLASSIC',
|
||
'name' => 'Kleiderschrank Classic',
|
||
'brand' => 'Möbelwerk Nord',
|
||
'category' => 'Schlafzimmer > Schränke',
|
||
'status' => 'inactive',
|
||
'price' => 2100.00,
|
||
'stock_status' => 'out_of_stock',
|
||
'created_at' => '2025-10-15',
|
||
'image' => null,
|
||
],
|
||
[
|
||
'id' => 6,
|
||
'b2in_number' => 'B2IN-000476',
|
||
'supplier_number' => 'SIDEBOARD-MOD-120',
|
||
'name' => 'Sideboard Modern 120cm',
|
||
'brand' => 'Design Studio',
|
||
'category' => 'Wohnzimmer > Sideboards',
|
||
'status' => 'active',
|
||
'price' => 675.00,
|
||
'stock_status' => 'in_stock',
|
||
'created_at' => '2025-11-01',
|
||
'image' => null,
|
||
],
|
||
];
|
||
});
|
||
|
||
?>
|
||
|
||
<div class="space-y-6">
|
||
{{-- Header --}}
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<flux:heading size="xl">{{ __('Produkte') }} (in Entwicklung)</flux:heading>
|
||
<flux:subheading>{{ __('Verwalten Sie Ihre Produktliste') }}</flux:subheading>
|
||
</div>
|
||
<flux:button variant="primary" icon="plus" :href="route('products.create')" wire:navigate>
|
||
{{ __('Neues Produkt') }}
|
||
</flux:button>
|
||
</div>
|
||
|
||
{{-- Filter & Suche --}}
|
||
<flux:card class="p-6">
|
||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||
{{-- Suchfeld --}}
|
||
<div class="md:col-span-2">
|
||
<flux:input
|
||
wire:model.live.debounce.300ms="search"
|
||
placeholder="{{ __('Suche nach Name, Artikelnummer...') }}"
|
||
icon="magnifying-glass"
|
||
/>
|
||
</div>
|
||
|
||
{{-- Status Filter --}}
|
||
<flux:select wire:model.live="statusFilter">
|
||
<option value="all">{{ __('Alle Status') }}</option>
|
||
<option value="active">{{ __('Aktiv') }}</option>
|
||
<option value="draft">{{ __('Entwurf') }}</option>
|
||
<option value="inactive">{{ __('Inaktiv') }}</option>
|
||
</flux:select>
|
||
|
||
{{-- Kategorie Filter --}}
|
||
<flux:select wire:model.live="categoryFilter">
|
||
<option value="all">{{ __('Alle Kategorien') }}</option>
|
||
<option value="sofas">{{ __('Sofas') }}</option>
|
||
<option value="chairs">{{ __('Stühle') }}</option>
|
||
<option value="tables">{{ __('Tische') }}</option>
|
||
<option value="beds">{{ __('Betten') }}</option>
|
||
<option value="wardrobes">{{ __('Schränke') }}</option>
|
||
</flux:select>
|
||
</div>
|
||
|
||
{{-- Aktive Filter Anzeige --}}
|
||
@if($search || $statusFilter !== 'all' || $categoryFilter !== 'all')
|
||
<div class="flex items-center gap-2 mt-4 pt-4 border-t border-zinc-200 dark:border-zinc-700">
|
||
<span class="text-sm text-zinc-600 dark:text-zinc-400">{{ __('Aktive Filter:') }}</span>
|
||
@if($search)
|
||
<flux:badge color="blue">
|
||
{{ __('Suche: ') }}{{ $search }}
|
||
<button wire:click="$set('search', '')" class="ml-1">×</button>
|
||
</flux:badge>
|
||
@endif
|
||
@if($statusFilter !== 'all')
|
||
<flux:badge color="green">
|
||
{{ __('Status: ') }}{{ __($statusFilter) }}
|
||
<button wire:click="$set('statusFilter', 'all')" class="ml-1">×</button>
|
||
</flux:badge>
|
||
@endif
|
||
@if($categoryFilter !== 'all')
|
||
<flux:badge color="purple">
|
||
{{ __('Kategorie: ') }}{{ __($categoryFilter) }}
|
||
<button wire:click="$set('categoryFilter', 'all')" class="ml-1">×</button>
|
||
</flux:badge>
|
||
@endif
|
||
<button
|
||
wire:click="$set('search', ''); $set('statusFilter', 'all'); $set('categoryFilter', 'all')"
|
||
class="text-sm text-accent-600 hover:text-accent-700 dark:text-accent-400 ml-2"
|
||
>
|
||
{{ __('Alle Filter zurücksetzen') }}
|
||
</button>
|
||
</div>
|
||
@endif
|
||
</flux:card>
|
||
|
||
{{-- Produkttabelle --}}
|
||
<flux:card>
|
||
<flux:table>
|
||
<flux:table.columns>
|
||
<flux:table.column class="w-20">{{ __('Bild') }}</flux:table.column>
|
||
<flux:table.column>{{ __('Produkt') }}</flux:table.column>
|
||
<flux:table.column>{{ __('Marke') }}</flux:table.column>
|
||
<flux:table.column>{{ __('Kategorie') }}</flux:table.column>
|
||
<flux:table.column class="text-right">{{ __('Preis') }}</flux:table.column>
|
||
<flux:table.column class="text-center">{{ __('Status') }}</flux:table.column>
|
||
<flux:table.column class="text-center">{{ __('Lager') }}</flux:table.column>
|
||
<flux:table.column>{{ __('Erstellt') }}</flux:table.column>
|
||
<flux:table.column class="text-right w-32">{{ __('Aktionen') }}</flux:table.column>
|
||
</flux:table.columns>
|
||
|
||
<flux:table.rows>
|
||
@forelse($this->products as $product)
|
||
<flux:table.row :key="$product['id']" class="odd:bg-zinc-50 dark:odd:bg-zinc-800/30">
|
||
{{-- Bild --}}
|
||
<flux:table.cell>
|
||
<div class="w-12 h-12 bg-zinc-200 dark:bg-zinc-700 rounded flex items-center justify-center">
|
||
<flux:icon.photo class="w-6 h-6 text-zinc-400" />
|
||
</div>
|
||
</flux:table.cell>
|
||
|
||
{{-- Produkt --}}
|
||
<flux:table.cell>
|
||
<div>
|
||
<div class="font-semibold text-zinc-900 dark:text-zinc-100">
|
||
{{ $product['name'] }}
|
||
</div>
|
||
<div class="text-xs text-zinc-500 dark:text-zinc-400 space-y-0.5 mt-1">
|
||
<div>B2in: {{ $product['b2in_number'] }}</div>
|
||
<div>Art.-Nr.: {{ $product['supplier_number'] }}</div>
|
||
</div>
|
||
</div>
|
||
</flux:table.cell>
|
||
|
||
{{-- Marke --}}
|
||
<flux:table.cell>
|
||
<span class="text-sm text-zinc-700 dark:text-zinc-300">
|
||
{{ $product['brand'] }}
|
||
</span>
|
||
</flux:table.cell>
|
||
|
||
{{-- Kategorie --}}
|
||
<flux:table.cell>
|
||
<span class="text-sm text-zinc-600 dark:text-zinc-400">
|
||
{{ $product['category'] }}
|
||
</span>
|
||
</flux:table.cell>
|
||
|
||
{{-- Preis --}}
|
||
<flux:table.cell class="text-right">
|
||
<span class="font-semibold text-zinc-900 dark:text-zinc-100">
|
||
{{ number_format($product['price'], 2, ',', '.') }} €
|
||
</span>
|
||
</flux:table.cell>
|
||
|
||
{{-- Status --}}
|
||
<flux:table.cell class="text-center">
|
||
@php
|
||
$statusColors = [
|
||
'active' => 'green',
|
||
'draft' => 'yellow',
|
||
'inactive' => 'zinc',
|
||
];
|
||
$statusLabels = [
|
||
'active' => __('Aktiv'),
|
||
'draft' => __('Entwurf'),
|
||
'inactive' => __('Inaktiv'),
|
||
];
|
||
@endphp
|
||
<flux:badge :color="$statusColors[$product['status']]" size="sm">
|
||
{{ $statusLabels[$product['status']] }}
|
||
</flux:badge>
|
||
</flux:table.cell>
|
||
|
||
{{-- Lagerstatus --}}
|
||
<flux:table.cell class="text-center">
|
||
@php
|
||
$stockColors = [
|
||
'in_stock' => 'green',
|
||
'on_order' => 'yellow',
|
||
'out_of_stock' => 'red',
|
||
];
|
||
$stockLabels = [
|
||
'in_stock' => __('Auf Lager'),
|
||
'on_order' => __('Bestellung'),
|
||
'out_of_stock' => __('Nicht verfügbar'),
|
||
];
|
||
@endphp
|
||
<flux:badge :color="$stockColors[$product['stock_status']]" size="sm" variant="outline">
|
||
{{ $stockLabels[$product['stock_status']] }}
|
||
</flux:badge>
|
||
</flux:table.cell>
|
||
|
||
{{-- Erstellt am --}}
|
||
<flux:table.cell>
|
||
<span class="text-sm text-zinc-600 dark:text-zinc-400">
|
||
{{ \Carbon\Carbon::parse($product['created_at'])->format('d.m.Y') }}
|
||
</span>
|
||
</flux:table.cell>
|
||
|
||
{{-- Aktionen --}}
|
||
<flux:table.cell class="text-right">
|
||
<div class="flex items-center justify-end gap-2">
|
||
<flux:button variant="ghost" size="sm" icon="eye">
|
||
{{ __('Ansehen') }}
|
||
</flux:button>
|
||
|
||
<flux:dropdown position="bottom" align="end">
|
||
<flux:button variant="ghost" size="sm" icon="ellipsis-horizontal" icon-trailing />
|
||
|
||
<flux:menu class="w-48">
|
||
<flux:menu.item icon="pencil">
|
||
{{ __('Bearbeiten') }}
|
||
</flux:menu.item>
|
||
<flux:menu.item icon="document-duplicate">
|
||
{{ __('Duplizieren') }}
|
||
</flux:menu.item>
|
||
<flux:menu.separator />
|
||
<flux:menu.item icon="archive-box">
|
||
{{ __('Archivieren') }}
|
||
</flux:menu.item>
|
||
<flux:menu.item icon="trash" variant="danger">
|
||
{{ __('Löschen') }}
|
||
</flux:menu.item>
|
||
</flux:menu>
|
||
</flux:dropdown>
|
||
</div>
|
||
</flux:table.cell>
|
||
</flux:table.row>
|
||
@empty
|
||
<flux:table.row>
|
||
<flux:table.cell colspan="9" class="text-center py-12">
|
||
<div class="flex flex-col items-center justify-center">
|
||
<flux:icon.cube class="w-16 h-16 text-zinc-400 mb-4" />
|
||
<flux:heading size="lg" class="mb-2">{{ __('Keine Produkte gefunden') }}</flux:heading>
|
||
<flux:subheading class="mb-4">
|
||
{{ __('Erstellen Sie Ihr erstes Produkt oder passen Sie Ihre Filter an.') }}
|
||
</flux:subheading>
|
||
<flux:button variant="primary" icon="plus" :href="route('products.create')" wire:navigate>
|
||
{{ __('Neues Produkt erstellen') }}
|
||
</flux:button>
|
||
</div>
|
||
</flux:table.cell>
|
||
</flux:table.row>
|
||
@endforelse
|
||
</flux:table.rows>
|
||
</flux:table>
|
||
|
||
{{-- Pagination / Stats --}}
|
||
<div class="px-6 py-4 border-t border-zinc-200 dark:border-zinc-700">
|
||
<div class="flex items-center justify-between">
|
||
<div class="text-sm text-zinc-600 dark:text-zinc-400">
|
||
{{ __('Zeige') }} <span class="font-semibold">{{ count($this->products) }}</span> {{ __('von') }} <span class="font-semibold">{{ count($this->products) }}</span> {{ __('Produkten') }}
|
||
</div>
|
||
|
||
{{-- Hier würde normalerweise die Pagination kommen --}}
|
||
<div class="flex items-center gap-2">
|
||
<flux:button variant="ghost" size="sm" icon="chevron-left" disabled>
|
||
{{ __('Zurück') }}
|
||
</flux:button>
|
||
<span class="text-sm text-zinc-600 dark:text-zinc-400">{{ __('Seite 1 von 1') }}</span>
|
||
<flux:button variant="ghost" size="sm" icon="chevron-right" icon-trailing disabled>
|
||
{{ __('Weiter') }}
|
||
</flux:button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
|
||
{{-- Statistiken (Optional) --}}
|
||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||
<flux:card class="p-4">
|
||
<div class="flex items-center gap-3">
|
||
<div class="p-3 bg-green-100 dark:bg-green-900/20 rounded-lg">
|
||
<flux:icon.check-circle class="w-6 h-6 text-green-600 dark:text-green-400" />
|
||
</div>
|
||
<div>
|
||
<div class="text-2xl font-bold text-zinc-900 dark:text-zinc-100">4</div>
|
||
<div class="text-sm text-zinc-600 dark:text-zinc-400">{{ __('Aktive Produkte') }}</div>
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
|
||
<flux:card class="p-4">
|
||
<div class="flex items-center gap-3">
|
||
<div class="p-3 bg-yellow-100 dark:bg-yellow-900/20 rounded-lg">
|
||
<flux:icon.document class="w-6 h-6 text-yellow-600 dark:text-yellow-400" />
|
||
</div>
|
||
<div>
|
||
<div class="text-2xl font-bold text-zinc-900 dark:text-zinc-100">1</div>
|
||
<div class="text-sm text-zinc-600 dark:text-zinc-400">{{ __('Entwürfe') }}</div>
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
|
||
<flux:card class="p-4">
|
||
<div class="flex items-center gap-3">
|
||
<div class="p-3 bg-blue-100 dark:bg-blue-900/20 rounded-lg">
|
||
<flux:icon.cube class="w-6 h-6 text-blue-600 dark:text-blue-400" />
|
||
</div>
|
||
<div>
|
||
<div class="text-2xl font-bold text-zinc-900 dark:text-zinc-100">5</div>
|
||
<div class="text-sm text-zinc-600 dark:text-zinc-400">{{ __('Auf Lager') }}</div>
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
|
||
<flux:card class="p-4">
|
||
<div class="flex items-center gap-3">
|
||
<div class="p-3 bg-zinc-100 dark:bg-zinc-700 rounded-lg">
|
||
<flux:icon.currency-euro class="w-6 h-6 text-zinc-600 dark:text-zinc-400" />
|
||
</div>
|
||
<div>
|
||
<div class="text-2xl font-bold text-zinc-900 dark:text-zinc-100">6.563 €</div>
|
||
<div class="text-sm text-zinc-600 dark:text-zinc-400">{{ __('Ø Preis') }}</div>
|
||
</div>
|
||
</div>
|
||
</flux:card>
|
||
</div>
|
||
</div>
|
||
|