b2in/resources/views/livewire/products/index.blade.php
2026-01-23 17:33:10 +01:00

398 lines
17 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.

<?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>