Initial commit: WitShop Laravel Online-Shop
- Laravel 11, Blade, Alpine.js, Tailwind CSS - Produkt- & Kategorieverwaltung mit Varianten - Checkout (Vorkasse + Rechnung), Session-Warenkorb - Admin-Backend (Dashboard, Bestellungen, Kunden, CMS) - DSGVO-konform: Cookie-Consent, Impressum, Widerruf, AGB - PDF-Rechnung via dompdf, SMTP-Mailversand - Kundenverwaltung mit manueller Freischaltung Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Meine Adressen')
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">Mein Konto</h1>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
|
||||
{{-- Sidebar --}}
|
||||
<div class="space-y-1 text-sm">
|
||||
<a href="{{ route('account.index') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Übersicht</a>
|
||||
<a href="{{ route('account.orders') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Bestellungen</a>
|
||||
<a href="{{ route('account.addresses') }}" class="block px-3 py-2 rounded bg-blue-50 text-blue-700 font-semibold">Adressen</a>
|
||||
<a href="{{ route('account.settings') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Einstellungen</a>
|
||||
<form method="POST" action="{{ route('logout') }}">@csrf
|
||||
<button class="w-full text-left px-3 py-2 rounded text-red-600 hover:bg-red-50">Abmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- Content --}}
|
||||
<div class="md:col-span-3 space-y-6">
|
||||
|
||||
{{-- Gespeicherte Adressen --}}
|
||||
@if($addresses->count())
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
@foreach($addresses as $addr)
|
||||
<div class="bg-white border rounded-lg p-4 text-sm relative">
|
||||
@if($addr->is_default)
|
||||
<span class="absolute top-3 right-3 text-xs bg-blue-100 text-blue-700 px-2 py-0.5 rounded-full">Standard</span>
|
||||
@endif
|
||||
<p class="font-semibold">{{ $addr->first_name }} {{ $addr->last_name }}</p>
|
||||
@if($addr->company)<p class="text-gray-500">{{ $addr->company }}</p>@endif
|
||||
<p class="text-gray-700 mt-1">{{ $addr->street }}</p>
|
||||
<p class="text-gray-700">{{ $addr->zip }} {{ $addr->city }}</p>
|
||||
@if($addr->phone)<p class="text-gray-400 text-xs mt-1">{{ $addr->phone }}</p>@endif
|
||||
<form method="POST" action="{{ route('account.addresses.destroy', $addr) }}" class="mt-3"
|
||||
onsubmit="return confirm('Adresse löschen?')">
|
||||
@csrf @method('DELETE')
|
||||
<button class="text-red-500 text-xs hover:underline">Löschen</button>
|
||||
</form>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<div class="bg-white border rounded-lg p-8 text-center text-gray-400 text-sm">
|
||||
Noch keine Adressen gespeichert.
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Neue Adresse --}}
|
||||
<div class="bg-white border rounded-lg p-6">
|
||||
<h2 class="font-semibold mb-4">Neue Adresse hinzufügen</h2>
|
||||
<form method="POST" action="{{ route('account.addresses.store') }}" class="grid grid-cols-2 gap-4">
|
||||
@csrf
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Vorname *</label>
|
||||
<input type="text" name="first_name" value="{{ old('first_name') }}" required
|
||||
class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Nachname *</label>
|
||||
<input type="text" name="last_name" value="{{ old('last_name') }}" required
|
||||
class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium mb-1">Firma (optional)</label>
|
||||
<input type="text" name="company" value="{{ old('company') }}"
|
||||
class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium mb-1">Straße und Hausnummer *</label>
|
||||
<input type="text" name="street" value="{{ old('street') }}" required
|
||||
class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">PLZ *</label>
|
||||
<input type="text" name="zip" value="{{ old('zip') }}" required
|
||||
class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Ort *</label>
|
||||
<input type="text" name="city" value="{{ old('city') }}" required
|
||||
class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Land *</label>
|
||||
<input type="text" name="country" value="{{ old('country', 'DE') }}" required maxlength="2"
|
||||
class="w-full border rounded px-3 py-2 text-sm uppercase">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Telefon (optional)</label>
|
||||
<input type="text" name="phone" value="{{ old('phone') }}"
|
||||
class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
@if($errors->any())
|
||||
<div class="col-span-2 bg-red-50 border border-red-200 rounded p-3 text-sm text-red-700">
|
||||
@foreach($errors->all() as $e)<p>• {{ $e }}</p>@endforeach
|
||||
</div>
|
||||
@endif
|
||||
<div class="col-span-2">
|
||||
<button type="submit" class="bg-blue-600 text-white px-5 py-2 rounded hover:bg-blue-700 text-sm">
|
||||
Adresse speichern
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,39 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Mein Konto')
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">Mein Konto</h1>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div class="space-y-1 text-sm">
|
||||
<a href="{{ route('account.index') }}" class="block px-3 py-2 rounded {{ request()->routeIs('account.index') ? 'bg-blue-50 text-blue-700 font-semibold' : 'hover:bg-gray-50' }}">Übersicht</a>
|
||||
<a href="{{ route('account.orders') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Bestellungen</a>
|
||||
<a href="{{ route('account.addresses') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Adressen</a>
|
||||
<a href="{{ route('account.settings') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Einstellungen</a>
|
||||
<form method="POST" action="{{ route('logout') }}">@csrf
|
||||
<button class="w-full text-left px-3 py-2 rounded text-red-600 hover:bg-red-50">Abmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="md:col-span-3">
|
||||
<div class="bg-white border rounded-lg p-6 mb-6">
|
||||
<p class="text-gray-600">Hallo, <strong>{{ auth()->user()->name }}</strong>!</p>
|
||||
</div>
|
||||
@if($orders->count())
|
||||
<h2 class="font-semibold mb-3">Letzte Bestellungen</h2>
|
||||
<div class="bg-white border rounded-lg overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-50"><tr><th class="px-4 py-2 text-left">Bestellnr.</th><th class="px-4 py-2 text-left">Status</th><th class="px-4 py-2 text-right">Betrag</th><th class="px-4 py-2"></th></tr></thead>
|
||||
<tbody class="divide-y">
|
||||
@foreach($orders as $o)
|
||||
<tr>
|
||||
<td class="px-4 py-2 font-mono">{{ $o->order_number }}</td>
|
||||
<td class="px-4 py-2">{{ $o->status_label }}</td>
|
||||
<td class="px-4 py-2 text-right">{{ number_format($o->total, 2, ',', '.') }} €</td>
|
||||
<td class="px-4 py-2"><a href="{{ route('account.order', $o) }}" class="text-blue-600 text-xs hover:underline">Details</a></td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,123 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Bestellung ' . $order->order_number)
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">Mein Konto</h1>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
|
||||
{{-- Sidebar --}}
|
||||
<div class="space-y-1 text-sm">
|
||||
<a href="{{ route('account.index') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Übersicht</a>
|
||||
<a href="{{ route('account.orders') }}" class="block px-3 py-2 rounded bg-blue-50 text-blue-700 font-semibold">Bestellungen</a>
|
||||
<a href="{{ route('account.addresses') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Adressen</a>
|
||||
<a href="{{ route('account.settings') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Einstellungen</a>
|
||||
<form method="POST" action="{{ route('logout') }}">@csrf
|
||||
<button class="w-full text-left px-3 py-2 rounded text-red-600 hover:bg-red-50">Abmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- Content --}}
|
||||
<div class="md:col-span-3 space-y-5">
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-sm text-gray-500">Bestellnummer</p>
|
||||
<h2 class="text-lg font-mono font-bold">{{ $order->order_number }}</h2>
|
||||
</div>
|
||||
<span class="px-3 py-1 rounded-full text-sm font-medium
|
||||
{{ match($order->status) {
|
||||
'new' => 'bg-yellow-100 text-yellow-700',
|
||||
'payment_received' => 'bg-blue-100 text-blue-700',
|
||||
'processing' => 'bg-purple-100 text-purple-700',
|
||||
'shipped' => 'bg-indigo-100 text-indigo-700',
|
||||
'completed' => 'bg-green-100 text-green-700',
|
||||
'cancelled' => 'bg-red-100 text-red-700',
|
||||
default => 'bg-gray-100 text-gray-600',
|
||||
} }}">
|
||||
{{ $order->status_label }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{-- Artikel --}}
|
||||
<div class="bg-white border rounded-lg overflow-hidden">
|
||||
<div class="px-4 py-3 bg-gray-50 border-b text-sm font-semibold">Bestellte Artikel</div>
|
||||
<table class="w-full text-sm">
|
||||
<tbody class="divide-y">
|
||||
@foreach($order->items as $item)
|
||||
<tr>
|
||||
<td class="px-4 py-3">
|
||||
<p class="font-medium">{{ $item->product_name }}</p>
|
||||
@if($item->variant_label)
|
||||
<p class="text-gray-400 text-xs">{{ $item->variant_label }}</p>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-4 py-3 text-gray-500 text-center">{{ $item->qty }}×</td>
|
||||
<td class="px-4 py-3 text-right font-medium">{{ number_format($item->price * $item->qty, 2, ',', '.') }} €</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot class="border-t bg-gray-50 text-sm">
|
||||
<tr>
|
||||
<td colspan="2" class="px-4 py-2 text-gray-500">Versand</td>
|
||||
<td class="px-4 py-2 text-right">{{ number_format($order->shipping_cost, 2, ',', '.') }} €</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="px-4 py-2 font-bold">Gesamt</td>
|
||||
<td class="px-4 py-2 text-right font-bold text-lg">{{ number_format($order->total, 2, ',', '.') }} €</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{-- Tracking --}}
|
||||
@if($order->tracking_code)
|
||||
<div class="bg-indigo-50 border border-indigo-200 rounded-lg px-4 py-3 text-sm">
|
||||
<p class="font-semibold text-indigo-800">Sendungsverfolgung</p>
|
||||
<p class="text-indigo-700 font-mono mt-1">{{ $order->tracking_code }}</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Zahlungshinweis Vorkasse --}}
|
||||
@if($order->payment_method === 'vorkasse' && in_array($order->status, ['new']))
|
||||
<div class="bg-amber-50 border border-amber-200 rounded-lg px-4 py-4 text-sm">
|
||||
<p class="font-semibold text-amber-800 mb-2">Bitte überweisen Sie den Betrag auf folgendes Konto:</p>
|
||||
<dl class="grid grid-cols-2 gap-1 text-amber-700">
|
||||
<dt class="font-medium">Empfänger:</dt><dd>{{ \App\Models\Setting::get('shop_owner') }}</dd>
|
||||
<dt class="font-medium">IBAN:</dt><dd class="font-mono">{{ \App\Models\Setting::get('bank_iban') }}</dd>
|
||||
<dt class="font-medium">BIC:</dt><dd class="font-mono">{{ \App\Models\Setting::get('bank_bic') }}</dd>
|
||||
<dt class="font-medium">Bank:</dt><dd>{{ \App\Models\Setting::get('bank_name') }}</dd>
|
||||
<dt class="font-medium">Verwendungszweck:</dt><dd class="font-mono">{{ $order->order_number }}</dd>
|
||||
<dt class="font-medium">Betrag:</dt><dd class="font-semibold">{{ number_format($order->total, 2, ',', '.') }} €</dd>
|
||||
</dl>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Adressen --}}
|
||||
<div class="grid grid-cols-2 gap-4 text-sm">
|
||||
@php
|
||||
$billing = $order->addresses->firstWhere('type', 'billing');
|
||||
$shipping = $order->addresses->firstWhere('type', 'shipping');
|
||||
@endphp
|
||||
@if($billing)
|
||||
<div class="bg-white border rounded-lg p-4">
|
||||
<p class="text-xs text-gray-400 font-semibold uppercase mb-2">Rechnungsadresse</p>
|
||||
<p class="font-medium">{{ $billing->first_name }} {{ $billing->last_name }}</p>
|
||||
@if($billing->company)<p class="text-gray-500">{{ $billing->company }}</p>@endif
|
||||
<p class="text-gray-700">{{ $billing->street }}</p>
|
||||
<p class="text-gray-700">{{ $billing->zip }} {{ $billing->city }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($shipping)
|
||||
<div class="bg-white border rounded-lg p-4">
|
||||
<p class="text-xs text-gray-400 font-semibold uppercase mb-2">Lieferadresse</p>
|
||||
<p class="font-medium">{{ $shipping->first_name }} {{ $shipping->last_name }}</p>
|
||||
@if($shipping->company)<p class="text-gray-500">{{ $shipping->company }}</p>@endif
|
||||
<p class="text-gray-700">{{ $shipping->street }}</p>
|
||||
<p class="text-gray-700">{{ $shipping->zip }} {{ $shipping->city }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<a href="{{ route('account.orders') }}" class="inline-block text-sm text-gray-500 hover:text-blue-600">← Alle Bestellungen</a>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,70 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Meine Bestellungen')
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">Mein Konto</h1>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
|
||||
{{-- Sidebar --}}
|
||||
<div class="space-y-1 text-sm">
|
||||
<a href="{{ route('account.index') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Übersicht</a>
|
||||
<a href="{{ route('account.orders') }}" class="block px-3 py-2 rounded bg-blue-50 text-blue-700 font-semibold">Bestellungen</a>
|
||||
<a href="{{ route('account.addresses') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Adressen</a>
|
||||
<a href="{{ route('account.settings') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Einstellungen</a>
|
||||
<form method="POST" action="{{ route('logout') }}">@csrf
|
||||
<button class="w-full text-left px-3 py-2 rounded text-red-600 hover:bg-red-50">Abmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- Content --}}
|
||||
<div class="md:col-span-3">
|
||||
@if($orders->count())
|
||||
<div class="bg-white border rounded-lg overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-50 border-b text-left">
|
||||
<tr>
|
||||
<th class="px-4 py-3">Bestellnr.</th>
|
||||
<th class="px-4 py-3">Status</th>
|
||||
<th class="px-4 py-3">Zahlungsart</th>
|
||||
<th class="px-4 py-3 text-right">Betrag</th>
|
||||
<th class="px-4 py-3">Datum</th>
|
||||
<th class="px-4 py-3"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y">
|
||||
@foreach($orders as $order)
|
||||
<tr class="hover:bg-gray-50">
|
||||
<td class="px-4 py-3 font-mono font-medium">{{ $order->order_number }}</td>
|
||||
<td class="px-4 py-3">
|
||||
<span class="px-2 py-0.5 rounded text-xs
|
||||
{{ match($order->status) {
|
||||
'new' => 'bg-yellow-100 text-yellow-700',
|
||||
'payment_received' => 'bg-blue-100 text-blue-700',
|
||||
'processing' => 'bg-purple-100 text-purple-700',
|
||||
'shipped' => 'bg-indigo-100 text-indigo-700',
|
||||
'completed' => 'bg-green-100 text-green-700',
|
||||
'cancelled' => 'bg-red-100 text-red-700',
|
||||
default => 'bg-gray-100 text-gray-600',
|
||||
} }}">
|
||||
{{ $order->status_label }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-gray-500">{{ $order->payment_label }}</td>
|
||||
<td class="px-4 py-3 text-right font-medium">{{ number_format($order->total, 2, ',', '.') }} €</td>
|
||||
<td class="px-4 py-3 text-gray-400">{{ $order->created_at->format('d.m.Y') }}</td>
|
||||
<td class="px-4 py-3 text-right">
|
||||
<a href="{{ route('account.order', $order) }}" class="text-blue-600 hover:underline text-xs">Details</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="px-4 py-3 border-t">{{ $orders->links() }}</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="bg-white border rounded-lg p-10 text-center text-gray-400 text-sm">
|
||||
Sie haben noch keine Bestellungen aufgegeben.
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,58 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Kontoeinstellungen')
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">Mein Konto</h1>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
|
||||
{{-- Sidebar --}}
|
||||
<div class="space-y-1 text-sm">
|
||||
<a href="{{ route('account.index') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Übersicht</a>
|
||||
<a href="{{ route('account.orders') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Bestellungen</a>
|
||||
<a href="{{ route('account.addresses') }}" class="block px-3 py-2 rounded hover:bg-gray-50">Adressen</a>
|
||||
<a href="{{ route('account.settings') }}" class="block px-3 py-2 rounded bg-blue-50 text-blue-700 font-semibold">Einstellungen</a>
|
||||
<form method="POST" action="{{ route('logout') }}">@csrf
|
||||
<button class="w-full text-left px-3 py-2 rounded text-red-600 hover:bg-red-50">Abmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- Content --}}
|
||||
<div class="md:col-span-3">
|
||||
<div class="bg-white border rounded-lg p-6">
|
||||
<h2 class="font-semibold mb-4">Persönliche Daten</h2>
|
||||
<form method="POST" action="{{ route('account.settings.update') }}" class="space-y-4">
|
||||
@csrf @method('PUT')
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Name *</label>
|
||||
<input type="text" name="name" value="{{ old('name', auth()->user()->name) }}" required
|
||||
class="w-full border rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">E-Mail-Adresse *</label>
|
||||
<input type="email" name="email" value="{{ old('email', auth()->user()->email) }}" required
|
||||
class="w-full border rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<hr>
|
||||
<p class="text-sm text-gray-500">Passwort ändern — leer lassen, wenn Sie es nicht ändern möchten.</p>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Neues Passwort</label>
|
||||
<input type="password" name="password" autocomplete="new-password"
|
||||
class="w-full border rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Passwort bestätigen</label>
|
||||
<input type="password" name="password_confirmation" autocomplete="new-password"
|
||||
class="w-full border rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
@if($errors->any())
|
||||
<div class="bg-red-50 border border-red-200 rounded p-3 text-sm text-red-700">
|
||||
@foreach($errors->all() as $e)<p>• {{ $e }}</p>@endforeach
|
||||
</div>
|
||||
@endif
|
||||
<button type="submit" class="bg-blue-600 text-white px-5 py-2 rounded hover:bg-blue-700 text-sm">
|
||||
Speichern
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,19 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Blog')
|
||||
@section('content')
|
||||
<h1 class="text-3xl font-bold mb-8">Blog / Aktuelles</h1>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
@forelse($posts as $post)
|
||||
<a href="{{ route('blog.post', $post->slug) }}" class="block bg-white border rounded-lg overflow-hidden hover:shadow-md transition">
|
||||
@if($post->image)<img src="{{ asset('storage/'.$post->image) }}" class="w-full h-48 object-cover">@endif
|
||||
<div class="p-5">
|
||||
<p class="text-xs text-gray-400 mb-1">{{ $post->published_at?->format('d.m.Y') }}</p>
|
||||
<h2 class="font-semibold text-lg mb-2">{{ $post->title }}</h2>
|
||||
</div>
|
||||
</a>
|
||||
@empty
|
||||
<p class="col-span-2 text-gray-400 text-center py-16">Noch keine Beiträge.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
<div class="mt-8">{{ $posts->links() }}</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,11 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', $post->meta_title ?: $post->title)
|
||||
@section('content')
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<p class="text-sm text-gray-400 mb-2">{{ $post->published_at?->format('d.m.Y') }}</p>
|
||||
<h1 class="text-3xl font-bold mb-6">{{ $post->title }}</h1>
|
||||
@if($post->image)<img src="{{ asset('storage/'.$post->image) }}" class="w-full rounded-lg mb-6">@endif
|
||||
<div class="prose max-w-none text-gray-700">{!! $post->content !!}</div>
|
||||
<div class="mt-8"><a href="{{ route('blog') }}" class="text-blue-600 hover:underline">← Zurück zum Blog</a></div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,83 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Warenkorb')
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">Warenkorb</h1>
|
||||
|
||||
@if(empty($items))
|
||||
<div class="text-center py-20 text-gray-400">
|
||||
<div class="text-6xl mb-4">🛒</div>
|
||||
<p class="text-lg mb-4">Ihr Warenkorb ist leer.</p>
|
||||
<a href="{{ route('shop.products.index') }}" class="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700">Weiter einkaufen</a>
|
||||
</div>
|
||||
@else
|
||||
<form method="POST" action="{{ route('cart.update') }}">
|
||||
@csrf
|
||||
<div class="bg-white border rounded-lg overflow-hidden mb-6">
|
||||
<table class="w-full">
|
||||
<thead class="bg-gray-50 text-sm">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left">Artikel</th>
|
||||
<th class="px-4 py-3 text-center">Menge</th>
|
||||
<th class="px-4 py-3 text-right">Einzelpreis</th>
|
||||
<th class="px-4 py-3 text-right">Gesamt</th>
|
||||
<th class="px-4 py-3"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y">
|
||||
@foreach($items as $key => $item)
|
||||
<tr>
|
||||
<td class="px-4 py-4">
|
||||
<div class="font-medium">{{ $item['product_name'] }}</div>
|
||||
@if($item['variant_label'])<div class="text-sm text-gray-400">{{ $item['variant_label'] }}</div>@endif
|
||||
</td>
|
||||
<td class="px-4 py-4 text-center">
|
||||
<input type="number" name="qty[{{ $key }}]" value="{{ $item['qty'] }}" min="0" class="w-16 border rounded px-2 py-1 text-sm text-center">
|
||||
</td>
|
||||
<td class="px-4 py-4 text-right text-sm">{{ number_format($item['price'], 2, ',', '.') }} €</td>
|
||||
<td class="px-4 py-4 text-right font-semibold">{{ number_format($item['price'] * $item['qty'], 2, ',', '.') }} €</td>
|
||||
<td class="px-4 py-4 text-center">
|
||||
<form method="POST" action="{{ route('cart.remove', $key) }}">
|
||||
@csrf
|
||||
<button class="text-red-400 hover:text-red-600 text-xl">✕</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<button type="submit" class="text-sm text-blue-600 hover:underline">Warenkorb aktualisieren</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<div class="w-80 bg-white border rounded-lg p-6">
|
||||
<div class="space-y-2 text-sm mb-4">
|
||||
<div class="flex justify-between"><span>Zwischensumme</span><span>{{ number_format($subtotal, 2, ',', '.') }} €</span></div>
|
||||
<div class="flex justify-between">
|
||||
<span>Versand</span>
|
||||
<span>
|
||||
@if($shippingCost == 0 && $shippingRate)
|
||||
<span class="text-green-600">Kostenlos</span>
|
||||
@elseif($shippingRate)
|
||||
{{ number_format($shippingCost, 2, ',', '.') }} €
|
||||
@else
|
||||
Wird berechnet
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
@if($shippingRate && $shippingRate->free_from && $subtotal < $shippingRate->free_from)
|
||||
<p class="text-xs text-gray-400">Noch {{ number_format($shippingRate->free_from - $subtotal, 2, ',', '.') }} € bis kostenloser Versand</p>
|
||||
@endif
|
||||
</div>
|
||||
<div class="border-t pt-3 flex justify-between font-bold text-lg mb-5">
|
||||
<span>Gesamt</span><span>{{ number_format($total, 2, ',', '.') }} €</span>
|
||||
</div>
|
||||
<a href="{{ route('checkout.index') }}" class="block w-full text-center bg-blue-600 text-white py-3 rounded-lg hover:bg-blue-700 font-semibold">
|
||||
Zur Kasse →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endsection
|
||||
@@ -0,0 +1,60 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Bestellung bestätigen')
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">Bestellung prüfen und absenden</h1>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<div class="md:col-span-2 space-y-6">
|
||||
<div class="bg-white border rounded-lg p-6">
|
||||
<h2 class="font-semibold mb-3">Lieferadresse</h2>
|
||||
@php $addr = $checkoutData['shipping'] ?? $checkoutData['billing']; @endphp
|
||||
<p class="text-sm">{{ $addr['first_name'] }} {{ $addr['last_name'] }}<br>{{ $addr['street'] }}<br>{{ $addr['zip'] }} {{ $addr['city'] }}</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-white border rounded-lg p-6">
|
||||
<h2 class="font-semibold mb-3">Bestellpositionen</h2>
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-50"><tr><th class="px-3 py-2 text-left">Artikel</th><th class="px-3 py-2 text-center">Menge</th><th class="px-3 py-2 text-right">Gesamt</th></tr></thead>
|
||||
<tbody class="divide-y">
|
||||
@foreach($items as $item)
|
||||
<tr>
|
||||
<td class="px-3 py-2">{{ $item['product_name'] }}@if($item['variant_label']) <span class="text-gray-400">({{ $item['variant_label'] }})</span>@endif</td>
|
||||
<td class="px-3 py-2 text-center">{{ $item['qty'] }}</td>
|
||||
<td class="px-3 py-2 text-right">{{ number_format($item['price'] * $item['qty'], 2, ',', '.') }} €</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="bg-white border rounded-lg p-6">
|
||||
<h2 class="font-semibold mb-2">Zahlungsart</h2>
|
||||
<p class="text-sm">{{ \App\Models\Order::$paymentLabels[$checkoutData['payment_method']] }}</p>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('checkout.confirm') }}">
|
||||
@csrf
|
||||
<button class="w-full bg-green-600 text-white py-4 rounded-lg hover:bg-green-700 font-bold text-lg">
|
||||
🛒 Jetzt kostenpflichtig bestellen
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p class="text-xs text-gray-400 text-center">
|
||||
Mit der Bestellung akzeptieren Sie unsere <a href="{{ route('page', 'agb') }}" class="underline">AGB</a> und die <a href="{{ route('page', 'widerrufsbelehrung') }}" class="underline">Widerrufsbelehrung</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="bg-white border rounded-lg p-6 sticky top-4">
|
||||
<div class="space-y-2 text-sm mb-3 border-b pb-3">
|
||||
<div class="flex justify-between"><span>Zwischensumme</span><span>{{ number_format($subtotal, 2, ',', '.') }} €</span></div>
|
||||
<div class="flex justify-between"><span>Versand</span><span>{{ $shippingCost == 0 ? 'Kostenlos' : number_format($shippingCost, 2, ',', '.') . ' €' }}</span></div>
|
||||
</div>
|
||||
<div class="flex justify-between font-bold text-lg">
|
||||
<span>Gesamt</span><span>{{ number_format($total, 2, ',', '.') }} €</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-400 mt-1">inkl. MwSt.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,238 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Kasse')
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">Kasse</h1>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<div class="md:col-span-2">
|
||||
<form method="POST" action="{{ route('checkout.address') }}">
|
||||
@csrf
|
||||
|
||||
{{-- Gastemail --}}
|
||||
@guest
|
||||
<div class="bg-white border rounded-lg p-6 mb-6">
|
||||
<h2 class="font-semibold mb-4">Kontakt</h2>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">E-Mail-Adresse *</label>
|
||||
<input type="email" name="email" value="{{ old('email') }}" class="w-full border rounded px-3 py-2" required>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mt-3">
|
||||
Bereits Kunde? <a href="{{ route('login') }}" class="text-blue-600 hover:underline">Anmelden</a>
|
||||
</p>
|
||||
</div>
|
||||
@endguest
|
||||
|
||||
{{-- Rechnungsadresse --}}
|
||||
@php $defaultAddr = $userAddresses->firstWhere('is_default', true) ?? $userAddresses->first(); @endphp
|
||||
<div class="bg-white border rounded-lg p-6 mb-6" x-data="addressForm({{ $userAddresses->toJson() }})">
|
||||
<h2 class="font-semibold mb-4">Rechnungsadresse</h2>
|
||||
|
||||
{{-- Gespeicherte Adressen --}}
|
||||
@if($userAddresses->count())
|
||||
<div class="mb-5">
|
||||
<p class="text-xs text-gray-500 mb-2">Gespeicherte Adressen:</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||
@foreach($userAddresses as $addr)
|
||||
<button type="button"
|
||||
@click="fill({{ $addr->id }})"
|
||||
:class="selected === {{ $addr->id }} ? 'border-blue-500 bg-blue-50 ring-1 ring-blue-500' : 'border-gray-200 hover:border-blue-300'"
|
||||
class="text-left p-3 border rounded-lg text-sm transition">
|
||||
<p class="font-medium">{{ $addr->first_name }} {{ $addr->last_name }}</p>
|
||||
@if($addr->company)<p class="text-gray-400 text-xs">{{ $addr->company }}</p>@endif
|
||||
<p class="text-gray-500 text-xs mt-0.5">{{ $addr->street }}, {{ $addr->zip }} {{ $addr->city }}</p>
|
||||
</button>
|
||||
@endforeach
|
||||
<button type="button"
|
||||
@click="clear()"
|
||||
:class="selected === null ? 'border-blue-500 bg-blue-50 ring-1 ring-blue-500' : 'border-gray-200 hover:border-gray-300'"
|
||||
class="text-left p-3 border rounded-lg text-sm transition text-gray-500">
|
||||
+ Neue Adresse eingeben
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Vorname *</label>
|
||||
<input type="text" name="billing[first_name]" x-model="form.first_name" value="{{ old('billing.first_name', $defaultAddr?->first_name) }}" class="w-full border rounded px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Nachname *</label>
|
||||
<input type="text" name="billing[last_name]" x-model="form.last_name" value="{{ old('billing.last_name', $defaultAddr?->last_name) }}" class="w-full border rounded px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium mb-1">Firma (optional)</label>
|
||||
<input type="text" name="billing[company]" x-model="form.company" value="{{ old('billing.company', $defaultAddr?->company) }}" class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium mb-1">Straße und Hausnummer *</label>
|
||||
<input type="text" name="billing[street]" x-model="form.street" value="{{ old('billing.street', $defaultAddr?->street) }}" class="w-full border rounded px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">PLZ *</label>
|
||||
<input type="text" name="billing[zip]" x-model="form.zip" value="{{ old('billing.zip', $defaultAddr?->zip) }}" class="w-full border rounded px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Stadt *</label>
|
||||
<input type="text" name="billing[city]" x-model="form.city" value="{{ old('billing.city', $defaultAddr?->city) }}" class="w-full border rounded px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Land *</label>
|
||||
<select name="billing[country]" x-model="form.country" class="w-full border rounded px-3 py-2 text-sm">
|
||||
<option value="DE">Deutschland</option>
|
||||
<option value="AT">Österreich</option>
|
||||
<option value="CH">Schweiz</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Telefon</label>
|
||||
<input type="tel" name="billing[phone]" x-model="form.phone" value="{{ old('billing.phone', $defaultAddr?->phone) }}" class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Lieferadresse --}}
|
||||
<div class="bg-white border rounded-lg p-6 mb-6" x-data="{ same: true }">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="font-semibold">Lieferadresse</h2>
|
||||
<label class="flex items-center gap-2 text-sm cursor-pointer">
|
||||
<input type="checkbox" name="shipping_same" value="1" x-model="same" checked>
|
||||
Gleich wie Rechnungsadresse
|
||||
</label>
|
||||
</div>
|
||||
<div x-show="!same" class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Vorname *</label>
|
||||
<input type="text" name="shipping[first_name]" value="{{ old('shipping.first_name') }}" class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Nachname *</label>
|
||||
<input type="text" name="shipping[last_name]" value="{{ old('shipping.last_name') }}" class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium mb-1">Straße und Hausnummer *</label>
|
||||
<input type="text" name="shipping[street]" value="{{ old('shipping.street') }}" class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">PLZ *</label>
|
||||
<input type="text" name="shipping[zip]" value="{{ old('shipping.zip') }}" class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Stadt *</label>
|
||||
<input type="text" name="shipping[city]" value="{{ old('shipping.city') }}" class="w-full border rounded px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Land *</label>
|
||||
<select name="shipping[country]" class="w-full border rounded px-3 py-2 text-sm">
|
||||
<option value="DE" selected>Deutschland</option>
|
||||
<option value="AT">Österreich</option>
|
||||
<option value="CH">Schweiz</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Zahlungsart --}}
|
||||
<div class="bg-white border rounded-lg p-6 mb-6">
|
||||
<h2 class="font-semibold mb-4">Zahlungsart</h2>
|
||||
<div class="space-y-3">
|
||||
<label class="flex items-start gap-3 p-3 border rounded-lg cursor-pointer hover:bg-gray-50">
|
||||
<input type="radio" name="payment_method" value="prepayment" class="mt-1" checked>
|
||||
<div>
|
||||
<div class="font-medium">Vorkasse (Überweisung)</div>
|
||||
<div class="text-sm text-gray-500">Sie überweisen den Betrag auf unser Bankkonto. Wir versenden nach Zahlungseingang.</div>
|
||||
</div>
|
||||
</label>
|
||||
<label class="flex items-start gap-3 p-3 border rounded-lg cursor-pointer hover:bg-gray-50">
|
||||
<input type="radio" name="payment_method" value="invoice" class="mt-1">
|
||||
<div>
|
||||
<div class="font-medium">Kauf auf Rechnung</div>
|
||||
<div class="text-sm text-gray-500">Sie erhalten die Rechnung per E-Mail. Zahlungsziel: {{ \App\Models\Setting::get('invoice_payment_days', 14) }} Tage.</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Rechtliches --}}
|
||||
<div class="bg-white border rounded-lg p-6 mb-6 space-y-3">
|
||||
<label class="flex items-start gap-3 cursor-pointer">
|
||||
<input type="checkbox" name="agb" value="1" required class="mt-1">
|
||||
<span class="text-sm">Ich habe die <a href="{{ route('page', 'agb') }}" class="text-blue-600 hover:underline" target="_blank">AGB</a> gelesen und akzeptiere sie. Ich habe die <a href="{{ route('page', 'widerrufsbelehrung') }}" class="text-blue-600 hover:underline" target="_blank">Widerrufsbelehrung</a> zur Kenntnis genommen. *</span>
|
||||
</label>
|
||||
<label class="flex items-start gap-3 cursor-pointer">
|
||||
<input type="checkbox" name="privacy" value="1" required class="mt-1">
|
||||
<span class="text-sm">Ich habe die <a href="{{ route('page', 'datenschutz') }}" class="text-blue-600 hover:underline" target="_blank">Datenschutzerklärung</a> gelesen. *</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="bg-red-50 border border-red-200 rounded-lg p-4 mb-4">
|
||||
<ul class="text-sm text-red-700 space-y-1">
|
||||
@foreach($errors->all() as $error)<li>• {{ $error }}</li>@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<button type="submit" class="w-full bg-blue-600 text-white py-3 rounded-lg hover:bg-blue-700 font-semibold text-lg">
|
||||
Bestellung prüfen →
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- Zusammenfassung --}}
|
||||
<div>
|
||||
<div class="bg-white border rounded-lg p-6 sticky top-4">
|
||||
<h2 class="font-semibold mb-4">Zusammenfassung</h2>
|
||||
<div class="space-y-2 text-sm mb-4 border-b pb-4">
|
||||
<div class="flex justify-between"><span>Zwischensumme</span><span>{{ number_format($subtotal, 2, ',', '.') }} €</span></div>
|
||||
<div class="flex justify-between"><span>Versand</span><span>{{ $shippingCost == 0 ? 'Kostenlos' : number_format($shippingCost, 2, ',', '.') . ' €' }}</span></div>
|
||||
</div>
|
||||
<div class="flex justify-between font-bold text-lg">
|
||||
<span>Gesamt</span><span>{{ number_format($total, 2, ',', '.') }} €</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-400 mt-2">inkl. MwSt.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function addressForm(addresses) {
|
||||
@php $defaultAddr = $userAddresses->firstWhere('is_default', true) ?? $userAddresses->first(); @endphp
|
||||
const defaultId = {{ $defaultAddr?->id ?? 'null' }};
|
||||
return {
|
||||
addresses,
|
||||
selected: defaultId,
|
||||
form: {
|
||||
first_name: '{{ old('billing.first_name', $defaultAddr?->first_name) }}',
|
||||
last_name: '{{ old('billing.last_name', $defaultAddr?->last_name) }}',
|
||||
company: '{{ old('billing.company', $defaultAddr?->company) }}',
|
||||
street: '{{ old('billing.street', $defaultAddr?->street) }}',
|
||||
zip: '{{ old('billing.zip', $defaultAddr?->zip) }}',
|
||||
city: '{{ old('billing.city', $defaultAddr?->city) }}',
|
||||
country: '{{ old('billing.country', $defaultAddr?->country ?? 'DE') }}',
|
||||
phone: '{{ old('billing.phone', $defaultAddr?->phone) }}',
|
||||
},
|
||||
fill(id) {
|
||||
const addr = this.addresses.find(a => a.id === id);
|
||||
if (!addr) return;
|
||||
this.selected = id;
|
||||
this.form.first_name = addr.first_name ?? '';
|
||||
this.form.last_name = addr.last_name ?? '';
|
||||
this.form.company = addr.company ?? '';
|
||||
this.form.street = addr.street ?? '';
|
||||
this.form.zip = addr.zip ?? '';
|
||||
this.form.city = addr.city ?? '';
|
||||
this.form.country = addr.country ?? 'DE';
|
||||
this.form.phone = addr.phone ?? '';
|
||||
},
|
||||
clear() {
|
||||
this.selected = null;
|
||||
Object.keys(this.form).forEach(k => this.form[k] = k === 'country' ? 'DE' : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,35 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Bestellung erfolgreich')
|
||||
@section('content')
|
||||
<div class="max-w-2xl mx-auto text-center py-16">
|
||||
<div class="text-6xl mb-6">✅</div>
|
||||
<h1 class="text-3xl font-bold mb-4">Vielen Dank für Ihre Bestellung!</h1>
|
||||
<p class="text-gray-600 mb-2">Ihre Bestellnummer: <strong>{{ $order->order_number }}</strong></p>
|
||||
<p class="text-gray-600 mb-8">Sie erhalten eine Bestätigungsmail mit allen Details.</p>
|
||||
|
||||
@if($order->payment_method === 'prepayment')
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-lg p-6 text-left mb-8">
|
||||
<h2 class="font-semibold mb-3">Überweisungsdaten</h2>
|
||||
<table class="w-full text-sm">
|
||||
<tr><td class="py-1 text-gray-500">Empfänger</td><td class="py-1 font-medium">{{ \App\Models\Setting::get('shop_owner') }}</td></tr>
|
||||
<tr><td class="py-1 text-gray-500">Bank</td><td class="py-1">{{ \App\Models\Setting::get('bank_name') }}</td></tr>
|
||||
<tr><td class="py-1 text-gray-500">IBAN</td><td class="py-1 font-mono">{{ \App\Models\Setting::get('bank_iban') }}</td></tr>
|
||||
<tr><td class="py-1 text-gray-500">BIC</td><td class="py-1 font-mono">{{ \App\Models\Setting::get('bank_bic') }}</td></tr>
|
||||
<tr><td class="py-1 text-gray-500">Verwendungszweck</td><td class="py-1 font-bold">{{ $order->order_number }}</td></tr>
|
||||
<tr><td class="py-1 text-gray-500">Betrag</td><td class="py-1 font-bold text-blue-700">{{ number_format($order->total, 2, ',', '.') }} €</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<div class="bg-green-50 border border-green-200 rounded-lg p-4 text-left mb-8">
|
||||
<p class="text-sm">Sie erhalten Ihre Rechnung per E-Mail. Bitte zahlen Sie innerhalb von {{ \App\Models\Setting::get('invoice_payment_days', 14) }} Tagen.</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex gap-4 justify-center">
|
||||
<a href="{{ route('home') }}" class="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700">Weiter einkaufen</a>
|
||||
@auth
|
||||
<a href="{{ route('account.orders') }}" class="border px-6 py-3 rounded-lg hover:bg-gray-50">Meine Bestellungen</a>
|
||||
@endauth
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,23 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'FAQ')
|
||||
@section('content')
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h1 class="text-3xl font-bold mb-8">Häufige Fragen</h1>
|
||||
@foreach($groups as $group)
|
||||
<h2 class="text-xl font-semibold mb-4 text-blue-700">{{ $group->name }}</h2>
|
||||
<div class="space-y-3 mb-8" x-data>
|
||||
@foreach($group->faqs as $faq)
|
||||
<div class="border rounded-lg" x-data="{ open: false }">
|
||||
<button @click="open = !open" class="w-full text-left px-5 py-4 flex justify-between items-center font-medium">
|
||||
{{ $faq->question }}
|
||||
<span x-text="open ? '▲' : '▼'" class="text-sm text-gray-400"></span>
|
||||
</button>
|
||||
<div x-show="open" x-collapse class="px-5 pb-4 text-gray-600 text-sm">
|
||||
{!! nl2br(e($faq->answer)) !!}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,95 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', \App\Models\Setting::get('shop_name', 'Shop'))
|
||||
@section('content')
|
||||
|
||||
{{-- Banner --}}
|
||||
@if($banners->count())
|
||||
<div class="relative mb-10 -mx-4" x-data="{ current: 0 }">
|
||||
@foreach($banners as $i => $banner)
|
||||
<div x-show="current === {{ $i }}" class="relative">
|
||||
<img src="{{ asset('storage/'.$banner->image) }}" alt="{{ $banner->headline }}" class="w-full h-72 object-cover rounded-lg">
|
||||
@if($banner->headline)
|
||||
<div class="absolute inset-0 bg-black/40 flex items-center justify-center rounded-lg">
|
||||
<div class="text-center text-white">
|
||||
<h2 class="text-3xl font-bold mb-2">{{ $banner->headline }}</h2>
|
||||
@if($banner->subtext)<p class="text-lg mb-4">{{ $banner->subtext }}</p>@endif
|
||||
@if($banner->button_link && $banner->button_label)
|
||||
<a href="{{ $banner->button_link }}" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-semibold">{{ $banner->button_label }}</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@if($banners->count() > 1)
|
||||
<div class="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2">
|
||||
@foreach($banners as $i => $b)
|
||||
<button @click="current = {{ $i }}" :class="current === {{ $i }} ? 'bg-white' : 'bg-white/50'" class="w-3 h-3 rounded-full"></button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Kategorien --}}
|
||||
@if($categories->count())
|
||||
<h2 class="text-2xl font-bold mb-6">Kategorien</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-12">
|
||||
@foreach($categories as $cat)
|
||||
<a href="{{ route('shop.category', $cat->slug) }}" class="group block bg-gray-50 rounded-lg overflow-hidden hover:shadow-md transition">
|
||||
@if($cat->image)
|
||||
<img src="{{ asset('storage/'.$cat->image) }}" alt="{{ $cat->name }}" class="w-full h-32 object-cover group-hover:scale-105 transition">
|
||||
@else
|
||||
<div class="w-full h-32 bg-blue-100 flex items-center justify-center text-4xl">🛍️</div>
|
||||
@endif
|
||||
<div class="p-3 font-semibold">{{ $cat->name }}</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Top Produkte --}}
|
||||
@if($topProducts->count())
|
||||
<div class="mb-12">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<svg class="w-6 h-6 text-yellow-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
|
||||
</svg>
|
||||
<h2 class="text-2xl font-bold">Top Produkte</h2>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
@foreach($topProducts as $product)
|
||||
@include('shop.products._card', ['product' => $product, 'badge' => 'Top'])
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Neue Produkte --}}
|
||||
@if($newProducts->count())
|
||||
<div class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Neu im Sortiment</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
@foreach($newProducts as $product)
|
||||
@include('shop.products._card', ['product' => $product])
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Blog --}}
|
||||
@if($blogPosts->count())
|
||||
<h2 class="text-2xl font-bold mb-6">Aktuelles</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
@foreach($blogPosts as $post)
|
||||
<a href="{{ route('blog.post', $post->slug) }}" class="block bg-white border rounded-lg overflow-hidden hover:shadow-md transition">
|
||||
@if($post->image)<img src="{{ asset('storage/'.$post->image) }}" class="w-full h-40 object-cover">@endif
|
||||
<div class="p-4">
|
||||
<p class="text-xs text-gray-400 mb-1">{{ $post->published_at?->format('d.m.Y') }}</p>
|
||||
<h3 class="font-semibold">{{ $post->title }}</h3>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endsection
|
||||
@@ -0,0 +1,34 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Bestellverfolgung')
|
||||
@section('content')
|
||||
<div class="max-w-xl mx-auto">
|
||||
<h1 class="text-2xl font-bold mb-6">Bestellung verfolgen</h1>
|
||||
|
||||
<div class="bg-white border rounded-lg p-6 mb-6">
|
||||
<form method="POST" action="{{ route('order.track.show') }}" class="space-y-4">
|
||||
@csrf
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Bestellnummer</label>
|
||||
<input type="text" name="order_number" value="{{ old('order_number') }}" class="w-full border rounded px-3 py-2 text-sm font-mono" placeholder="ORD-20240101-XXXXX" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">E-Mail-Adresse</label>
|
||||
<input type="email" name="email" value="{{ old('email') }}" class="w-full border rounded px-3 py-2 text-sm" required>
|
||||
</div>
|
||||
<button class="bg-blue-600 text-white px-6 py-2 rounded hover:bg-blue-700">Suchen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@if(isset($order))
|
||||
<div class="bg-white border rounded-lg p-6">
|
||||
<h2 class="font-semibold mb-4">Bestellung {{ $order->order_number }}</h2>
|
||||
<div class="space-y-2 text-sm mb-4">
|
||||
<div class="flex justify-between"><span class="text-gray-500">Status</span><strong>{{ $order->status_label }}</strong></div>
|
||||
<div class="flex justify-between"><span class="text-gray-500">Zahlungsart</span><span>{{ $order->payment_label }}</span></div>
|
||||
<div class="flex justify-between"><span class="text-gray-500">Gesamtbetrag</span><span>{{ number_format($order->total, 2, ',', '.') }} €</span></div>
|
||||
@if($order->tracking_code)<div class="flex justify-between"><span class="text-gray-500">Tracking-Nr.</span><span class="font-mono">{{ $order->tracking_code }}</span></div>@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,11 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', $page->meta_title ?: $page->title)
|
||||
@section('meta_description', $page->meta_description)
|
||||
@section('content')
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<h1 class="text-3xl font-bold mb-6">{{ $page->title }}</h1>
|
||||
<div class="prose max-w-none text-gray-700">
|
||||
{!! $page->content !!}
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,20 @@
|
||||
<a href="{{ route('shop.product.show', $product->slug) }}" class="group block bg-white border rounded-lg overflow-hidden hover:shadow-md transition relative">
|
||||
@if($product->images->first())
|
||||
<img src="{{ asset('storage/'.$product->images->first()->path) }}" alt="{{ $product->name }}" class="w-full h-48 object-cover group-hover:scale-105 transition">
|
||||
@else
|
||||
<div class="w-full h-48 bg-gray-100 flex items-center justify-center text-5xl">📦</div>
|
||||
@endif
|
||||
@if(isset($badge))
|
||||
<span class="absolute top-2 left-2 bg-yellow-400 text-yellow-900 text-xs font-bold px-2 py-0.5 rounded-full">
|
||||
★ {{ $badge }}
|
||||
</span>
|
||||
@endif
|
||||
<div class="p-4">
|
||||
<p class="text-xs text-gray-400 mb-1">{{ $product->category?->name }}</p>
|
||||
<h3 class="font-semibold text-sm mb-2 group-hover:text-blue-600">{{ $product->name }}</h3>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<span class="text-lg font-bold text-blue-700">{{ number_format($product->base_price, 2, ',', '.') }} €</span>
|
||||
<span class="text-xs text-gray-400">inkl. {{ number_format($product->tax_rate, 0) }}% MwSt.</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@@ -0,0 +1,26 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', isset($category) ? $category->name : 'Alle Produkte')
|
||||
@section('content')
|
||||
<h1 class="text-2xl font-bold mb-6">{{ isset($category) ? $category->name : 'Alle Produkte' }}</h1>
|
||||
|
||||
@if(isset($category) && $category->description)
|
||||
<p class="text-gray-600 mb-6">{{ $category->description }}</p>
|
||||
@endif
|
||||
|
||||
<div class="flex gap-3 mb-6">
|
||||
<form method="GET" class="flex gap-2">
|
||||
<input type="text" name="q" value="{{ request('q') }}" placeholder="Suchen…" class="border rounded px-3 py-2 text-sm">
|
||||
<button class="bg-blue-600 text-white px-4 py-2 rounded text-sm hover:bg-blue-700">Suchen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
@forelse($products as $product)
|
||||
@include('shop.products._card', ['product' => $product])
|
||||
@empty
|
||||
<p class="col-span-4 text-center text-gray-400 py-16">Keine Produkte gefunden.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<div class="mt-8">{{ $products->withQueryString()->links() }}</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,139 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', $product->name)
|
||||
@section('content')
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-10 mb-12" x-data="productDetail(@json($product->variants))">
|
||||
|
||||
{{-- Bilder --}}
|
||||
<div>
|
||||
@if($product->images->count())
|
||||
<img :src="mainImage" x-init="mainImage = '{{ asset('storage/'.$product->images->first()->path) }}'" class="w-full rounded-lg mb-3 border">
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
@foreach($product->images as $img)
|
||||
<img src="{{ asset('storage/'.$img->path) }}" @click="mainImage = '{{ asset('storage/'.$img->path) }}'"
|
||||
class="w-16 h-16 object-cover rounded cursor-pointer border hover:border-blue-500">
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<div class="w-full h-72 bg-gray-100 rounded-lg flex items-center justify-center text-7xl">📦</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Info --}}
|
||||
<div>
|
||||
<p class="text-sm text-gray-400 mb-1">{{ $product->category?->name }}</p>
|
||||
<h1 class="text-2xl font-bold mb-3">{{ $product->name }}</h1>
|
||||
|
||||
{{-- Preis --}}
|
||||
<div class="mb-4">
|
||||
<span class="text-3xl font-bold text-blue-700" x-text="formatPrice(currentPrice)"></span>
|
||||
<span class="text-sm text-gray-500 ml-2">inkl. {{ number_format($product->tax_rate, 0) }}% MwSt.</span>
|
||||
<div class="text-xs text-gray-400 mt-1" x-text="'Netto: ' + formatPrice(currentPrice / (1 + {{ $product->tax_rate }} / 100))"></div>
|
||||
</div>
|
||||
|
||||
{{-- Varianten --}}
|
||||
@php
|
||||
$attributeGroups = $product->variants->flatMap->attributeValues->groupBy(fn($v) => $v->attribute->name)->map->unique('id');
|
||||
$hasAttributes = $attributeGroups->isNotEmpty();
|
||||
$defaultVariant = $product->variants->first();
|
||||
@endphp
|
||||
|
||||
@if($hasAttributes)
|
||||
@foreach($attributeGroups as $attrName => $values)
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium mb-2">{{ $attrName }}</label>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@foreach($values as $val)
|
||||
<button type="button"
|
||||
@click="selectAttr('{{ $attrName }}', {{ $val->id }})"
|
||||
:class="selectedAttrs['{{ $attrName }}'] === {{ $val->id }} ? 'bg-blue-600 text-white border-blue-600' : 'bg-white border-gray-300 hover:border-blue-400'"
|
||||
class="px-4 py-2 text-sm border rounded-lg transition">
|
||||
{{ $val->value }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
<div class="text-sm mb-3" :class="selectedVariant ? ({{ $product->track_stock ? 'true' : 'false' }} ? (selectedVariant.stock > 0 ? 'text-green-600' : 'text-red-600') : 'text-green-600') : 'text-gray-400'">
|
||||
<span x-show="!selectedVariant">Bitte Variante wählen</span>
|
||||
@if($product->track_stock)
|
||||
<span x-show="selectedVariant && selectedVariant.stock > 0" x-text="'✓ Auf Lager (' + selectedVariant?.stock + ' verfügbar)'"></span>
|
||||
<span x-show="selectedVariant && selectedVariant.stock <= 0">✕ Nicht auf Lager</span>
|
||||
@else
|
||||
<span x-show="selectedVariant">✓ Lieferbar</span>
|
||||
@endif
|
||||
</div>
|
||||
@elseif($defaultVariant)
|
||||
@if($product->track_stock)
|
||||
<p class="text-sm mb-3 {{ $defaultVariant->stock > 0 ? 'text-green-600' : 'text-red-600' }}">
|
||||
{{ $defaultVariant->stock > 0 ? '✓ Auf Lager' : '✕ Nicht auf Lager' }}
|
||||
</p>
|
||||
@else
|
||||
<p class="text-sm mb-3 text-green-600">✓ Lieferbar</p>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
{{-- In den Warenkorb --}}
|
||||
<form method="POST" action="{{ route('cart.add') }}">
|
||||
@csrf
|
||||
@if($hasAttributes)
|
||||
<input type="hidden" name="variant_id" :value="selectedVariant?.id ?? 0">
|
||||
@else
|
||||
<input type="hidden" name="variant_id" value="{{ $defaultVariant?->id }}">
|
||||
@endif
|
||||
<div class="flex gap-3 mt-4">
|
||||
<input type="number" name="qty" value="1" min="1" class="w-20 border rounded px-3 py-2 text-sm">
|
||||
<button type="submit"
|
||||
@if($hasAttributes) :disabled="!selectedVariant || ({{ $product->track_stock ? 'true' : 'false' }} && selectedVariant && selectedVariant.stock <= 0)" @endif
|
||||
@if(!$hasAttributes && $product->track_stock && (!$defaultVariant || $defaultVariant->stock <= 0)) disabled @endif
|
||||
class="flex-1 bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed font-semibold">
|
||||
In den Warenkorb
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="mt-6 prose text-sm text-gray-600 max-w-none">
|
||||
{!! nl2br(e($product->description)) !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Ähnliche Produkte --}}
|
||||
@if($related->count())
|
||||
<h2 class="text-xl font-bold mb-4">Ähnliche Produkte</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
@foreach($related as $p)
|
||||
@include('shop.products._card', ['product' => $p])
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<script>
|
||||
function productDetail(variants) {
|
||||
return {
|
||||
variants,
|
||||
selectedAttrs: {},
|
||||
selectedVariant: null,
|
||||
mainImage: '',
|
||||
currentPrice: {{ $product->base_price }},
|
||||
selectAttr(name, id) {
|
||||
this.selectedAttrs[name] = id;
|
||||
this.findVariant();
|
||||
},
|
||||
findVariant() {
|
||||
const selectedIds = Object.values(this.selectedAttrs);
|
||||
this.selectedVariant = this.variants.find(v => {
|
||||
const ids = v.attribute_values.map(a => a.id);
|
||||
return selectedIds.every(id => ids.includes(id)) && ids.length === selectedIds.length;
|
||||
});
|
||||
if (this.selectedVariant) {
|
||||
this.currentPrice = this.selectedVariant.price_override ?? {{ $product->base_price }};
|
||||
}
|
||||
},
|
||||
formatPrice(p) {
|
||||
return new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,176 @@
|
||||
@extends('layouts.shop')
|
||||
@section('title', 'Widerrufsformular')
|
||||
@section('content')
|
||||
<div class="max-w-2xl mx-auto">
|
||||
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl font-bold mb-1">Widerrufsformular</h1>
|
||||
<p class="text-gray-500 text-sm">gemäß § 356 BGB – Füllen Sie dieses Formular aus, um Ihr Widerrufsrecht innerhalb von 14 Tagen ab Warenerhalt auszuüben.</p>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="bg-green-100 text-green-800 px-4 py-4 rounded-lg mb-6 flex items-start gap-3">
|
||||
<svg class="w-5 h-5 mt-0.5 shrink-0" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>
|
||||
<div>
|
||||
<p class="font-semibold">Widerruf erfolgreich übermittelt</p>
|
||||
<p class="text-sm mt-0.5">{{ session('success') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($errors->any())
|
||||
<div class="bg-red-50 border border-red-200 rounded-lg p-4 mb-6 text-sm text-red-700">
|
||||
@foreach($errors->all() as $e)<p>• {{ $e }}</p>@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="bg-white border rounded-xl shadow-sm p-6">
|
||||
<form method="POST" action="{{ route('widerruf.submit') }}" class="space-y-6">
|
||||
@csrf
|
||||
|
||||
{{-- Bestelldaten --}}
|
||||
<fieldset>
|
||||
<legend class="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3">Bestellinformationen</legend>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Kundennummer</label>
|
||||
<input type="text" name="customer_number" value="{{ old('customer_number') }}"
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="z.B. KD-00123">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Bestell- / Rechnungsnummer</label>
|
||||
<input type="text" name="order_number" value="{{ old('order_number') }}"
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Bestelldatum</label>
|
||||
<input type="date" name="order_date" value="{{ old('order_date') }}"
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Datum des Warenerhalts *</label>
|
||||
<input type="date" name="date" value="{{ old('date') }}" required
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium mb-1">Artikelbezeichnung *</label>
|
||||
<input type="text" name="product" value="{{ old('product') }}" required
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="Artikelname, Variante, Menge …">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{-- Kontaktdaten --}}
|
||||
<fieldset>
|
||||
<legend class="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3">Ihre Kontaktdaten</legend>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Vorname *</label>
|
||||
<input type="text" name="first_name" value="{{ old('first_name') }}" required
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Nachname *</label>
|
||||
<input type="text" name="last_name" value="{{ old('last_name') }}" required
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium mb-1">E-Mail-Adresse *</label>
|
||||
<input type="email" name="email" value="{{ old('email') }}" required
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-sm font-medium mb-1">Straße und Hausnummer *</label>
|
||||
<input type="text" name="street" value="{{ old('street') }}" required
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">PLZ *</label>
|
||||
<input type="text" name="zip" value="{{ old('zip') }}" required
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Ort *</label>
|
||||
<input type="text" name="city" value="{{ old('city') }}" required
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{-- Widerrufsgrund --}}
|
||||
<fieldset>
|
||||
<legend class="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3">Widerrufsgrund</legend>
|
||||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Grund (optional)</label>
|
||||
<select name="reason_category" class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<option value="">– Bitte wählen –</option>
|
||||
<option value="falsch_bestellt" {{ old('reason_category') === 'falsch_bestellt' ? 'selected' : '' }}>Falsch bestellt</option>
|
||||
<option value="nicht_gefallen" {{ old('reason_category') === 'nicht_gefallen' ? 'selected' : '' }}>Artikel gefällt mir nicht</option>
|
||||
<option value="beschaedigt" {{ old('reason_category') === 'beschaedigt' ? 'selected' : '' }}>Ware beschädigt erhalten</option>
|
||||
<option value="falsch_geliefert" {{ old('reason_category') === 'falsch_geliefert' ? 'selected' : '' }}>Falsche Ware geliefert</option>
|
||||
<option value="zu_spaet" {{ old('reason_category') === 'zu_spaet' ? 'selected' : '' }}>Lieferung zu spät</option>
|
||||
<option value="sonstiges" {{ old('reason_category') === 'sonstiges' ? 'selected' : '' }}>Sonstiges</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">Anmerkungen (optional)</label>
|
||||
<textarea name="reason" rows="3"
|
||||
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="Weitere Details zu Ihrem Widerruf …">{{ old('reason') }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{-- Erstattungsart --}}
|
||||
<fieldset>
|
||||
<legend class="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3">Erstattung</legend>
|
||||
<div class="space-y-2 text-sm">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="refund_method" value="original" {{ old('refund_method', 'original') === 'original' ? 'checked' : '' }} class="accent-blue-600">
|
||||
Ursprüngliche Zahlungsart
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="refund_method" value="bank" {{ old('refund_method') === 'bank' ? 'checked' : '' }} class="accent-blue-600">
|
||||
Banküberweisung
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="refund_method" value="credit" {{ old('refund_method') === 'credit' ? 'checked' : '' }} class="accent-blue-600">
|
||||
Gutschrift im Shop
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{-- Pflicht-Checkboxen --}}
|
||||
<fieldset class="border-t pt-4 space-y-3">
|
||||
<label class="flex items-start gap-3 text-sm cursor-pointer">
|
||||
<input type="checkbox" name="privacy_accepted" value="1" required
|
||||
class="mt-0.5 accent-blue-600">
|
||||
<span>Ich habe die <a href="{{ route('page', 'datenschutz') }}" class="text-blue-600 underline" target="_blank">Datenschutzerklärung</a> gelesen und stimme der Verarbeitung meiner Daten zur Bearbeitung des Widerrufs zu. *</span>
|
||||
</label>
|
||||
<label class="flex items-start gap-3 text-sm cursor-pointer">
|
||||
<input type="checkbox" name="accuracy_confirmed" value="1" required
|
||||
class="mt-0.5 accent-blue-600">
|
||||
<span>Ich bestätige, dass die angegebenen Informationen korrekt und vollständig sind. *</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<button type="submit"
|
||||
class="w-full bg-blue-600 text-white py-3 rounded-lg font-medium hover:bg-blue-700 transition text-sm">
|
||||
Widerruf verbindlich absenden
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-sm text-gray-500 bg-gray-50 rounded-lg p-4 space-y-2">
|
||||
<p><strong>Hinweis:</strong> Die 14-tägige Widerrufsfrist beginnt ab dem Tag des Erhalts der Ware. Nach Absenden dieses Formulars erhalten Sie eine Bestätigungs-E-Mail.</p>
|
||||
<p>Bitte senden Sie die Ware zurück an:<br>
|
||||
<strong class="text-gray-700">{{ \App\Models\Setting::get('shop_owner') }}</strong><br>
|
||||
{!! nl2br(e(\App\Models\Setting::get('shop_address'))) !!}</p>
|
||||
<p>Alternativ können Sie den Widerruf auch per E-Mail an <a href="mailto:{{ \App\Models\Setting::get('shop_email') }}" class="text-blue-600 underline">{{ \App\Models\Setting::get('shop_email') }}</a> erklären.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user