diff --git a/src/app/coffee-abonnements/page.tsx b/src/app/coffee-abonnements/page.tsx index e068fb5..c45f87f 100644 --- a/src/app/coffee-abonnements/page.tsx +++ b/src/app/coffee-abonnements/page.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { useState, useMemo } from 'react'; import PageLayout from '../components/PageLayout'; +import { useRouter } from 'next/navigation'; interface Coffee { id: string; @@ -27,18 +28,11 @@ const coffees: Coffee[] = [ export default function CoffeeAbonnementPage() { const [selections, setSelections] = useState>({}); - const [bump, setBump] = useState>({}); // added: bump animation flags - const [form, setForm] = useState({ - firstName: '', - lastName: '', - email: '', - street: '', - postalCode: '', - city: '', - frequency: 'monatlich', - startDate: '' - }); - const TAX_RATE = 0.07; // 7% Steuer + const [bump, setBump] = useState>({}); + // removed: form state and handlers (moved to summary page) + // removed: canSubmit depending on form + + const router = useRouter(); // added const selectedEntries = useMemo( () => @@ -57,16 +51,18 @@ export default function CoffeeAbonnementPage() { ), [selectedEntries] ); + const TAX_RATE = 0.07; // 7% Steuer const taxAmount = useMemo(() => totalPrice * TAX_RATE, [totalPrice]); const totalWithTax = useMemo(() => totalPrice + taxAmount, [totalPrice, taxAmount]); - const canSubmit = - selectedEntries.length > 0 && - Object.values(form).every(v => v.trim() !== ''); + const canProceed = selectedEntries.length > 0; // added - const handleInput = (e: React.ChangeEvent) => { - const { name, value } = e.target; - setForm(prev => ({ ...prev, [name]: value })); + const proceedToSummary = () => { + if (!canProceed) return; + try { + sessionStorage.setItem('coffeeSelections', JSON.stringify(selections)); + } catch {} + router.push('/coffee-abonnements/summary'); }; const toggleCoffee = (id: string) => { @@ -95,8 +91,25 @@ export default function CoffeeAbonnementPage() { return ( -
-

Kaffee Abonnement konfigurieren

+
+

+ + Kaffee Abonnement konfigurieren + +

+ + {/* Stepper */} +
+
+ 1 + Auswahl +
+
+
+ 2 + Zusammenfassung +
+
{/* Section 1: Multi coffee selection + per-coffee quantity */}
@@ -109,7 +122,7 @@ export default function CoffeeAbonnementPage() {
@@ -119,17 +132,18 @@ export default function CoffeeAbonnementPage() { className="h-36 w-full object-cover transition-transform duration-300 group-hover:scale-105" loading="lazy" /> - {/* CHANGED: enhanced price badge */} + {/* price badge */}
€{coffee.pricePer10} - + {/* CHANGED: solid, readable over images */} + pro 10 Stk
@@ -145,7 +159,7 @@ export default function CoffeeAbonnementPage() { onClick={() => toggleCoffee(coffee.id)} className={`mt-3 w-full text-xs font-medium rounded px-3 py-2 border transition ${ active - ? 'border-emerald-600 text-emerald-700 bg-white hover:bg-emerald-100' + ? 'border-[#1C2B4A] text-[#1C2B4A] bg-white hover:bg-[#1C2B4A]/10' : 'border-gray-300 hover:bg-gray-100' }`} > @@ -156,9 +170,7 @@ export default function CoffeeAbonnementPage() {
Menge (10–120) {qty} Stk @@ -186,7 +198,7 @@ export default function CoffeeAbonnementPage() { className="w-full appearance-none cursor-pointer bg-transparent" style={{ background: - 'linear-gradient(to right,#059669 0%,#059669 ' + + 'linear-gradient(to right,#1C2B4A 0%,#1C2B4A ' + ((qty - 10) / (120 - 10)) * 100 + '%,#e5e7eb ' + ((qty - 10) / (120 - 10)) * 100 + @@ -217,107 +229,19 @@ export default function CoffeeAbonnementPage() {
- {/* Section 2: Form (light styling) */} + {/* Section 2: Compact preview + next steps */}
-

2. Deine Daten

-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- - {/* Section 3: Summary (light styling) */} -
-

3. Zusammenfassung

-
+

2. Vorschau

+
{selectedEntries.length === 0 && (

Noch keine Kaffees ausgewählt.

)} {selectedEntries.map(entry => ( -
+
{entry.coffee.name} - {entry.quantity} Stk • €{entry.coffee.pricePer10}/10 + {entry.quantity} Stk • €{entry.coffee.pricePer10}/10
@@ -327,31 +251,23 @@ export default function CoffeeAbonnementPage() { ))}
Gesamt (Netto) - €{totalPrice.toFixed(2)} -
-
- Steuer ({(TAX_RATE * 100).toFixed(0)}%) - €{taxAmount.toFixed(2)} -
-
- Gesamt inkl. Steuer - €{totalWithTax.toFixed(2)} + €{totalPrice.toFixed(2)}
- {!canSubmit && ( -

- Bitte mindestens eine Kaffeesorte wählen und alle Felder ausfüllen. -

- )} + {!canProceed &&

Bitte mindestens eine Kaffeesorte wählen.

}
diff --git a/src/app/coffee-abonnements/summary/page.tsx b/src/app/coffee-abonnements/summary/page.tsx new file mode 100644 index 0000000..18886b8 --- /dev/null +++ b/src/app/coffee-abonnements/summary/page.tsx @@ -0,0 +1,286 @@ +'use client'; +import React, { useEffect, useMemo, useState } from 'react'; +import PageLayout from '../../components/PageLayout'; +import { useRouter } from 'next/navigation'; + +interface Coffee { + id: string; + name: string; + description: string; + pricePer10: number; + image: string; +} + +// duplicated from selection page to resolve details by id +const coffees: Coffee[] = [ + { id: 'espresso', name: 'Espresso Roast', description: '', pricePer10: 12, image: '' }, + { id: 'crema', name: 'Caffè Crema', description: '', pricePer10: 11, image: '' }, + { id: 'colombia', name: 'Colombia Single Origin', description: '', pricePer10: 13, image: '' }, + { id: 'ethiopia', name: 'Ethiopia Sidamo', description: '', pricePer10: 14, image: '' }, + { id: 'sumatra', name: 'Sumatra Mandheling', description: '', pricePer10: 13, image: '' }, + { id: 'kenya', name: 'Kenya AA', description: '', pricePer10: 15, image: '' }, + { id: 'brazil', name: 'Brazil Santos', description: '', pricePer10: 11, image: '' }, + { id: 'italian', name: 'Italian Roast', description: '', pricePer10: 12, image: '' }, + { id: 'house', name: 'House Blend', description: '', pricePer10: 10, image: '' }, + { id: 'decaf', name: 'Decaf Blend', description: '', pricePer10: 12, image: '' }, + { id: 'guatemala', name: 'Guatemala Huehuetenango', description: '', pricePer10: 14, image: '' }, + { id: 'limited', name: 'Limited Reserve', description: '', pricePer10: 18, image: '' } +]; + +export default function SummaryPage() { + const router = useRouter(); + const [selections, setSelections] = useState>({}); + const [form, setForm] = useState({ + firstName: '', + lastName: '', + email: '', + street: '', + postalCode: '', + city: '', + frequency: 'monatlich', + startDate: '' + }); + const [showThanks, setShowThanks] = useState(false); + const [confetti, setConfetti] = useState<{ left: number; delay: number; color: string }[]>([]); + const COLORS = ['#1C2B4A', '#233357', '#2A3B66', '#314475', '#3A4F88', '#5B6C9A']; // dark blue palette + + useEffect(() => { + try { + const raw = sessionStorage.getItem('coffeeSelections'); + if (raw) setSelections(JSON.parse(raw)); + } catch {} + }, []); + + useEffect(() => { + if (!showThanks) return; + const items = Array.from({ length: 40 }).map(() => ({ + left: Math.random() * 100, + delay: Math.random() * 0.6, + color: COLORS[Math.floor(Math.random() * COLORS.length)], + })); + setConfetti(items); + }, [showThanks]); + + const selectedEntries = useMemo( + () => + Object.entries(selections).map(([id, qty]) => { + const coffee = coffees.find(c => c.id === id); + return coffee ? { coffee, quantity: qty } : null; + }).filter(Boolean) as { coffee: Coffee; quantity: number }[], + [selections] + ); + + const TAX_RATE = 0.07; + const totalPrice = useMemo( + () => selectedEntries.reduce((sum, e) => sum + (e.quantity / 10) * e.coffee.pricePer10, 0), + [selectedEntries] + ); + const taxAmount = useMemo(() => totalPrice * TAX_RATE, [totalPrice]); + const totalWithTax = useMemo(() => totalPrice + taxAmount, [totalPrice, taxAmount]); + + const handleInput = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setForm(prev => ({ ...prev, [name]: value })); + }; + + const canSubmit = + selectedEntries.length > 0 && + Object.values(form).every(v => (typeof v === 'string' ? v.trim() !== '' : true)); + + const backToSelection = () => router.push('/coffee-abonnements'); + + const submit = () => { + if (!canSubmit) return; + setShowThanks(true); + try { sessionStorage.removeItem('coffeeSelections'); } catch {} + // here you would post data to your API + }; + + return ( + +
+
+

+ Zusammenfassung & Daten +

+ +
+ + {/* Stepper */} +
+
+ 1 + Auswahl +
+
+
+ 2 + Zusammenfassung +
+
+ + {selectedEntries.length === 0 ? ( +
+

Keine Auswahl gefunden.

+ +
+ ) : ( +
+ {/* Left: Customer data */} +
+

1. Deine Daten

+
+
+ {/* replace focus rings */} +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + {!canSubmit &&

Bitte mindestens eine Kaffeesorte wählen und alle Felder ausfüllen.

} +
+
+ + {/* Right: Order summary */} +
+

2. Deine Auswahl

+
+ {selectedEntries.map(entry => ( +
+
+ {entry.coffee.name} + + {entry.quantity} Stk • €{entry.coffee.pricePer10}/10 + +
+
€{((entry.quantity / 10) * entry.coffee.pricePer10).toFixed(2)}
+
+ ))} +
+ Gesamt (Netto) + €{totalPrice.toFixed(2)} +
+
+ Steuer ({(TAX_RATE * 100).toFixed(0)}%) + €{taxAmount.toFixed(2)} +
+
+ Gesamt inkl. Steuer + €{totalWithTax.toFixed(2)} +
+
+
+
+ )} +
+ + {/* Thank you overlay */} + {showThanks && ( +
+
+
+ {confetti.map((c, i) => ( + + ))} +
+ +
+ + + +
+

Danke für dein Abo!

+

Wir haben deine Bestellung erhalten.

+ +
+ + +
+ + +
+
+ )} + + ); +}