Deploy to Production (witstore.wende.it) / deploy (push) Successful in 8s
- Gutscheincodes: DB-Verwaltung (%, €-Rabatt, Mindestbestellwert, Ablauf), Eingabefeld im Checkout, Admin unter Marketing → Gutscheine - Newsletter: Double-Opt-In per E-Mail, Formular im Footer, Admin-Liste mit CSV-Export - Länderzonen-Versand: DE / DACH / EU / WORLD, Versandkosten nach Lieferland dynamisch berechnet, Coupon-Rabatt in Bestellung gespeichert - Sale-Preise: sale_price auf Produkten, durchgestrichener UVP auf Produktkarte, Sonderangebote-Sektion auf Startseite - USP-Leiste auf Startseite: Versand, Zahlung, Rückgabe, Service Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
270 lines
16 KiB
PHP
270 lines
16 KiB
PHP
@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>
|
|
@if($discount > 0)
|
|
<div class="flex justify-between text-green-600">
|
|
<span>Gutschein ({{ $couponCode }})</span>
|
|
<span>- {{ number_format($discount, 2, ',', '.') }} €</span>
|
|
</div>
|
|
@endif
|
|
<div class="flex justify-between"><span>Versand</span><span id="shipping-display">{{ $shippingCost == 0 ? 'Kostenlos' : number_format($shippingCost, 2, ',', '.') . ' €' }}</span></div>
|
|
</div>
|
|
<div class="flex justify-between font-bold text-lg">
|
|
<span>Gesamt</span><span id="total-display">{{ number_format($total, 2, ',', '.') }} €</span>
|
|
</div>
|
|
<p class="text-xs text-gray-400 mt-2">inkl. MwSt.</p>
|
|
|
|
{{-- Gutscheincode --}}
|
|
<div class="mt-4 border-t pt-4">
|
|
@if(session('coupon_error'))
|
|
<p class="text-red-600 text-xs mb-2">{{ session('coupon_error') }}</p>
|
|
@endif
|
|
@if(session('coupon_success'))
|
|
<p class="text-green-600 text-xs mb-2">{{ session('coupon_success') }}</p>
|
|
@endif
|
|
@if($couponCode)
|
|
<div class="flex items-center justify-between text-sm mb-2">
|
|
<span class="font-mono bg-green-50 text-green-700 px-2 py-0.5 rounded">{{ $couponCode }}</span>
|
|
<form method="POST" action="{{ route('checkout.coupon.remove') }}">@csrf
|
|
<button class="text-red-500 text-xs hover:underline">Entfernen</button>
|
|
</form>
|
|
</div>
|
|
@else
|
|
<form method="POST" action="{{ route('checkout.coupon.apply') }}" class="flex gap-2">
|
|
@csrf
|
|
<input type="text" name="coupon_code" placeholder="Gutscheincode"
|
|
class="flex-1 border rounded px-3 py-1.5 text-sm uppercase" style="text-transform:uppercase">
|
|
<button class="bg-gray-700 text-white px-3 py-1.5 rounded text-sm hover:bg-gray-800">OK</button>
|
|
</form>
|
|
@endif
|
|
</div>
|
|
</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
|