From 1478c61ea80b1d429eee5c11b77c98ba77f21c71 Mon Sep 17 00:00:00 2001 From: DanielS Date: Tue, 11 Aug 2026 17:26:49 +0200 Subject: [PATCH 1/4] feat(wizard): move progress stepper to left sidebar --- shop/components/order-wizard.tsx | 215 +++++++++----------- shop/components/wizard/progress-stepper.tsx | 60 +++++- shop/components/wizard/step-summary.tsx | 35 +--- shop/components/wizard/summary-sidebar.tsx | 23 +-- 4 files changed, 164 insertions(+), 169 deletions(-) diff --git a/shop/components/order-wizard.tsx b/shop/components/order-wizard.tsx index 3d2104c..3510362 100644 --- a/shop/components/order-wizard.tsx +++ b/shop/components/order-wizard.tsx @@ -844,138 +844,110 @@ export function OrderWizard({ } return ( -
- {/* Dynamic Header */} - {step !== 3 && ( -
-

- Konfigurieren Sie Ihre Lösung -

-

- Wählen Sie das passende Paket und die benötigten Module für Ihr Business. -

+
+
+ {/* Left Side Status Stepper for ALL steps */} +
+
+

+ Fortschritt +

+

+ Bestell-Wizard +

+
+
- )} - {/* Global Stepper for Steps 1, 2, 4 */} - {step !== 3 && ( -
- -
- )} + {/* Right Main Content Column */} +
+ {/* Dynamic Header */} + {step !== 3 && ( +
+

+ Konfigurieren Sie Ihre Lösung +

+

+ Wählen Sie das passende Paket und die benötigten Module für Ihr Business. +

+
+ )} - - {/* Step 1: Customer */} - {step === 1 && ( - - - - )} + + {/* Step 1: Customer */} + {step === 1 && ( + + + + )} - {/* Step 2: Billing Model */} - {step === 2 && ( - - - - )} - {/* Step 3: Software Selector */} + {/* Step 2: Billing Model */} + {step === 2 && ( + + + + )} {step === 3 && (
- {/* LEFT: Categories Sidebar Menu */} -
-
-

- Konfigurieren Sie Ihre Lösung -

-

- Wählen Sie das passende Paket und die benötigten Module für Ihr Business. -

-
+ {/* LEFT inside step 3: Categories Sidebar Menu */} +
+
+

+ Kategorien & Optionen +

+

+ Wählen Sie das passende Paket und die benötigten Module für Ihr Business. +

+
- {/* Left Sidebar Status Stepper (matching ProgressStepper sky-blue design) */} -
-

- Status -

-
-
-
- -
- Kunde -
-
-
-
- -
- Modell -
-
-
-
- 3 -
- Software -
-
-
-
- 4 -
- Abschluss -
-
-
- -
+
{visibleCategories.map((cat) => { const sel = selections[cat.id] const hasSelection = (sel?.productIds && sel.productIds.length > 0) || !!sel?.productId @@ -1059,9 +1031,8 @@ export function OrderWizard({
- {/* RIGHT: Stepper Header + Summary sidebar */} -
- + {/* RIGHT: Summary sidebar */} +
setToast(null)} /> +
+
) } diff --git a/shop/components/wizard/progress-stepper.tsx b/shop/components/wizard/progress-stepper.tsx index f571f6c..30b44c6 100644 --- a/shop/components/wizard/progress-stepper.tsx +++ b/shop/components/wizard/progress-stepper.tsx @@ -7,14 +7,70 @@ import { Check } from 'lucide-react' interface ProgressStepperProps { step: number basketItemsCount: number + orientation?: 'horizontal' | 'vertical' } const STEP_LABELS = ['Kunde', 'Modell', 'Software', 'Abschluss'] -export function ProgressStepper({ step, basketItemsCount }: ProgressStepperProps) { - // Calculate progress percentage for active line (Step 1: 0%, Step 2: 33.3%, Step 3: 66.6%, Step 4: 100%) +export function ProgressStepper({ step, basketItemsCount, orientation = 'horizontal' }: ProgressStepperProps) { const progressPercent = ((step - 1) / 3) * 100 + if (orientation === 'vertical') { + return ( +
+ {/* Background Line */} +
+ + {/* Animated Active Line */} + + + {[1, 2, 3, 4].map(s => { + const isDone = step > s + const isActive = step === s + + return ( +
+ + {isDone ? : s} + + + + {STEP_LABELS[s - 1]} + {s === 3 && basketItemsCount > 0 && ( + + {basketItemsCount} + + )} + +
+ ) + })} +
+ ) + } + return (
diff --git a/shop/components/wizard/step-summary.tsx b/shop/components/wizard/step-summary.tsx index d8669cd..bc605db 100644 --- a/shop/components/wizard/step-summary.tsx +++ b/shop/components/wizard/step-summary.tsx @@ -70,7 +70,7 @@ export function StepSummary({
- {/* Header & Status Stepper */} + {/* Header */}
@@ -85,39 +85,6 @@ export function StepSummary({

- - {/* Vertikaler Status-Stepper */} -
-

- Schritt 4 von 4 — Zusammenfassung & Abschluss -

-
-
-
- -
- Kunde -
-
-
- -
- Modell -
-
-
- -
- Software -
-
-
- 4 -
- Abschluss -
-
-
{/* Kunden-Info Card */} diff --git a/shop/components/wizard/summary-sidebar.tsx b/shop/components/wizard/summary-sidebar.tsx index 1fd62c3..464c01c 100644 --- a/shop/components/wizard/summary-sidebar.tsx +++ b/shop/components/wizard/summary-sidebar.tsx @@ -253,14 +253,14 @@ export function SummarySidebar({ {/* Kassen-Liste unten (selectable) */} {basketItems.length > 0 && ( -
+

Kassen ({basketItems.length}):

-
+
{basketItems.map((item, idx) => ( - - From 866c5522f2835d3ed5ceae34ea1e2a1d6f6d6047 Mon Sep 17 00:00:00 2001 From: DanielS Date: Tue, 11 Aug 2026 17:27:14 +0200 Subject: [PATCH 2/4] fix(setup): make SMTP optional and adjust setup check --- shop/components/SetupWizard.tsx | 9 ++++---- shop/lib/actions/setup.ts | 39 +++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/shop/components/SetupWizard.tsx b/shop/components/SetupWizard.tsx index 7f0ba2a..172a499 100644 --- a/shop/components/SetupWizard.tsx +++ b/shop/components/SetupWizard.tsx @@ -44,14 +44,13 @@ export function SetupWizard() { adminForm.firstName.trim().length > 0 && adminForm.lastName.trim().length > 0 - // Validation checks for SMTP form + // Validation checks for SMTP form (optional step) const isSmtpFormValid = - smtpForm.host.trim().length > 0 && - !isNaN(Number(smtpForm.port)) && - smtpForm.user.trim().length > 0 + smtpForm.host.trim().length === 0 || + (!isNaN(Number(smtpForm.port)) && smtpForm.user.trim().length > 0) const handleFinishSetup = async () => { - if (!isAdminFormValid || !isSmtpFormValid) return + if (!isAdminFormValid) return setLoading(true) setErrorMsg('') diff --git a/shop/lib/actions/setup.ts b/shop/lib/actions/setup.ts index 045e23f..c0bd7cc 100644 --- a/shop/lib/actions/setup.ts +++ b/shop/lib/actions/setup.ts @@ -34,10 +34,10 @@ export async function isSetupNeeded(): Promise { if (authError) { console.error('Error checking auth users list:', authError) - return false + return true } - if (authData.users.length > 0) { + if (authData && authData.users && authData.users.length > 0) { return false } @@ -48,13 +48,13 @@ export async function isSetupNeeded(): Promise { if (dbError) { console.error('Error checking users table status:', dbError) - return false + return true } return count === 0 } catch (e) { console.error('Exception checking setup status:', e) - return false + return true } } @@ -113,22 +113,23 @@ export async function completeSetup( console.error('Error updating admin profile:', profileError) } - // 5. Store SMTP configuration in public.settings - const { error: smtpError } = await admin - .from('settings') - .upsert({ - id: 'smtp', - host: smtpData.host, - port: smtpData.port, - secure: smtpData.secure, - user: smtpData.user, - pass: smtpData.pass, - updated_at: new Date().toISOString(), - }) + // 5. Store SMTP configuration in public.settings (optional) + if (smtpData.host && smtpData.host.trim().length > 0) { + const { error: smtpError } = await admin + .from('settings') + .upsert({ + id: 'smtp', + host: smtpData.host, + port: smtpData.port, + secure: smtpData.secure, + user: smtpData.user, + pass: smtpData.pass, + updated_at: new Date().toISOString(), + }) - if (smtpError) { - console.error('Error saving SMTP settings:', smtpError) - return { success: false, error: `Fehler beim Speichern der SMTP-Einstellungen: ${smtpError.message}` } + if (smtpError) { + console.error('Error saving SMTP settings:', smtpError) + } } revalidatePath('/') From 46699e8bf32595949c85d526f9446d51ed7160e6 Mon Sep 17 00:00:00 2001 From: DanielS Date: Tue, 11 Aug 2026 17:30:17 +0200 Subject: [PATCH 3/4] style(wizard): refine step 3 UI styling and micro interactions --- shop/components/order-wizard.tsx | 22 +-- shop/components/wizard/step-software.tsx | 26 ++-- shop/components/wizard/summary-sidebar.tsx | 166 +++++++++++---------- 3 files changed, 108 insertions(+), 106 deletions(-) diff --git a/shop/components/order-wizard.tsx b/shop/components/order-wizard.tsx index 3510362..d4a390f 100644 --- a/shop/components/order-wizard.tsx +++ b/shop/components/order-wizard.tsx @@ -932,12 +932,12 @@ export function OrderWizard({ initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }} - className="h-[calc(100vh-100px)] overflow-hidden" + className="h-[calc(100vh-100px)] overflow-hidden bg-slate-950/70 backdrop-blur-xl border border-slate-800/80 rounded-2xl shadow-2xl p-2" > -
+
{/* LEFT inside step 3: Categories Sidebar Menu */} -
+

Kategorien & Optionen @@ -947,7 +947,7 @@ export function OrderWizard({

-
+
{visibleCategories.map((cat) => { const sel = selections[cat.id] const hasSelection = (sel?.productIds && sel.productIds.length > 0) || !!sel?.productId @@ -959,8 +959,8 @@ export function OrderWizard({ key={cat.id} onClick={() => setActiveCategoryId(cat.id)} className={`flex items-center gap-3 p-3.5 rounded-xl border transition-all duration-300 text-left relative overflow-hidden group ${isActive - ? 'bg-primary/10 border-primary text-white shadow-[0_0_20px_rgba(59,130,246,0.15)]' - : 'bg-white/5 border-white/5 text-slate-400 hover:bg-white/10 hover:border-white/10' + ? 'bg-primary/10 border-primary text-white shadow-[0_0_20px_rgba(59,130,246,0.2)]' + : 'bg-slate-900/50 border-white/5 text-slate-400 hover:bg-slate-900 hover:border-white/20 hover:text-white' }`} > {/* Left glow line for active category */} @@ -984,11 +984,11 @@ export function OrderWizard({ {/* Status indicators */} {hasSelection ? ( - + Ausgewählt ) : isRequired ? ( - + Erforderlich ) : null} @@ -999,8 +999,8 @@ export function OrderWizard({
{/* CENTER: Scrollable Category Selection */} -
-
+
+
{/* Upgrade-Modus Hinweis-Banner */} {upgradeMode && lockedDeviceId && (
@@ -1032,7 +1032,7 @@ export function OrderWizard({
{/* RIGHT: Summary sidebar */} -
+
0 && ( -
-

- +

+

+ Zusatzmodule für {selectedProduct.name}

-
+
{selectedProduct.modules.map(module => { const isExistingLicense = existingModuleIds.includes(module.id) const disabled = isExistingLicense || isModuleDisabled(module, sel?.moduleIds ?? []) @@ -242,14 +242,14 @@ export function StepSoftware({ return (
@@ -258,19 +258,19 @@ export function StepSoftware({ checked={checked} onCheckedChange={() => !isExistingLicense && toggleModule(currentCategory.id, module.id)} disabled={disabled} - className="rounded border-white/20 data-[state=checked]:bg-primary" + className="rounded border-slate-700 data-[state=checked]:bg-primary data-[state=checked]:border-primary transition-colors" />