refactor: improve wizard layouts and animations

This commit is contained in:
DanielS
2026-08-10 23:29:42 +02:00
parent 2f63d716f2
commit f9cb3c0685
3 changed files with 459 additions and 434 deletions

View File

@@ -17,14 +17,7 @@ export default async function OrderPage({ searchParams }: PageProps) {
return ( return (
<div className="min-h-screen bg-[#0a0a0a] text-white selection:bg-primary/30"> <div className="min-h-screen bg-[#0a0a0a] text-white selection:bg-primary/30">
<div className="container mx-auto py-10"> <div className="container mx-auto py-10">
<div className="text-center mb-12">
<h1 className="text-5xl font-extrabold tracking-tight mb-4 text-gradient">
Konfigurieren Sie Ihre Lösung
</h1>
<p className="text-slate-400 text-lg max-w-2xl mx-auto">
Wählen Sie das passende Paket und die benötigten Module für Ihr Business.
</p>
</div>
<Suspense fallback={<div className="h-96 w-full animate-pulse bg-white/5 rounded-2xl" />}> <Suspense fallback={<div className="h-96 w-full animate-pulse bg-white/5 rounded-2xl" />}>
<OrderDataWrapper <OrderDataWrapper

View File

@@ -792,6 +792,18 @@ export function OrderWizard({
return ( return (
<div className={`mx-auto px-4 ${step === 3 ? 'max-w-screen-2xl' : 'max-w-5xl'}`}> <div className={`mx-auto px-4 ${step === 3 ? 'max-w-screen-2xl' : 'max-w-5xl'}`}>
{/* Dynamic Header */}
{step !== 3 && (
<div className="text-center mb-12">
<h1 className="text-5xl font-extrabold tracking-tight mb-4 text-gradient">
Konfigurieren Sie Ihre Lösung
</h1>
<p className="text-slate-400 text-lg max-w-2xl mx-auto">
Wählen Sie das passende Paket und die benötigten Module für Ihr Business.
</p>
</div>
)}
{/* Global Stepper for Steps 1, 2, 4 */} {/* Global Stepper for Steps 1, 2, 4 */}
{step !== 3 && ( {step !== 3 && (
<div className="pt-12 pb-6"> <div className="pt-12 pb-6">
@@ -867,10 +879,10 @@ export function OrderWizard({
<div className="lg:col-span-2 flex flex-col justify-start pr-4 space-y-6"> <div className="lg:col-span-2 flex flex-col justify-start pr-4 space-y-6">
<div> <div>
<h1 className="text-3xl font-extrabold tracking-tight mb-2 text-gradient"> <h1 className="text-3xl font-extrabold tracking-tight mb-2 text-gradient">
Software konfigurieren Konfigurieren Sie Ihre Lösung
</h1> </h1>
<p className="text-slate-400 text-sm"> <p className="text-slate-400 text-sm">
Klicken Sie sich durch die Kategorien und wählen Sie Ihre Lizenzen. Wählen Sie das passende Paket und die benötigten Module für Ihr Business.
</p> </p>
</div> </div>
@@ -885,8 +897,7 @@ export function OrderWizard({
<button <button
key={cat.id} key={cat.id}
onClick={() => setActiveCategoryId(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 ${ className={`flex items-center gap-3 p-3.5 rounded-xl border transition-all duration-300 text-left relative overflow-hidden group ${isActive
isActive
? 'bg-primary/10 border-primary text-white shadow-[0_0_20px_rgba(59,130,246,0.15)]' ? '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-white/5 border-white/5 text-slate-400 hover:bg-white/10 hover:border-white/10'
}`} }`}
@@ -896,8 +907,7 @@ export function OrderWizard({
<div className="absolute left-0 top-0 bottom-0 w-1 bg-primary" /> <div className="absolute left-0 top-0 bottom-0 w-1 bg-primary" />
)} )}
<div className={`p-2 rounded-lg transition-colors ${ <div className={`p-2 rounded-lg transition-colors ${isActive ? 'bg-primary/20 text-primary' : 'bg-white/5 text-slate-400 group-hover:text-white'
isActive ? 'bg-primary/20 text-primary' : 'bg-white/5 text-slate-400 group-hover:text-white'
}`}> }`}>
<CategoryIcon icon={cat.icon} className="w-4 h-4" /> <CategoryIcon icon={cat.icon} className="w-4 h-4" />
</div> </div>

View File

@@ -1,6 +1,7 @@
'use client' 'use client'
import React, { useState, useMemo, useEffect } from 'react' import React, { useState, useMemo, useEffect } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@/components/ui/card' import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@/components/ui/card'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
@@ -154,6 +155,7 @@ export function StepCustomer({
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-8"> <CardContent className="space-y-8">
<div className={isAdmin ? 'grid grid-cols-1 lg:grid-cols-2 gap-8 items-start' : 'space-y-8'}>
{/* ─── 1. ADMIN PARTNER SELECTION ─── */} {/* ─── 1. ADMIN PARTNER SELECTION ─── */}
{isAdmin && ( {isAdmin && (
<div className="p-5 rounded-2xl bg-white/5 border border-white/10 space-y-4"> <div className="p-5 rounded-2xl bg-white/5 border border-white/10 space-y-4">
@@ -199,7 +201,7 @@ export function StepCustomer({
</div> </div>
{/* Partner Card List */} {/* Partner Card List */}
<div className="space-y-2 max-h-72 overflow-y-auto pr-1"> <div className="space-y-2 max-h-[30rem] overflow-y-auto pr-1">
{/* Reserved Fixed Card: Alle Partner */} {/* Reserved Fixed Card: Alle Partner */}
<div <div
onClick={() => { onClick={() => {
@@ -347,6 +349,8 @@ export function StepCustomer({
</div> </div>
)} )}
{/* ─── 2. CUSTOMER WRAPPER ─── */}
<div className="space-y-6">
{/* Modus-Toggle: Bestandskunde vs. Neuer Kunde */} {/* Modus-Toggle: Bestandskunde vs. Neuer Kunde */}
<div className="flex gap-2"> <div className="flex gap-2">
<Button <Button
@@ -367,9 +371,17 @@ export function StepCustomer({
</Button> </Button>
</div> </div>
<AnimatePresence mode="wait">
{/* ─── 2. CUSTOMER SELECTION ─── */} {/* ─── 2. CUSTOMER SELECTION ─── */}
{customerMode === 'select' && ( {customerMode === 'select' && (
<div className="p-5 rounded-2xl bg-white/5 border border-white/10 space-y-4"> <motion.div
key="select"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
className="p-5 rounded-2xl bg-white/5 border border-white/10 space-y-4"
>
<div className="flex items-center justify-between gap-4 flex-wrap"> <div className="flex items-center justify-between gap-4 flex-wrap">
<div> <div>
<Label className="text-white font-bold text-base flex items-center gap-2"> <Label className="text-white font-bold text-base flex items-center gap-2">
@@ -437,7 +449,7 @@ export function StepCustomer({
) : ( ) : (
<> <>
{/* Customer Card List */} {/* Customer Card List */}
<div className="space-y-2 max-h-80 overflow-y-auto pr-1"> <div className="space-y-2 max-h-[30rem] overflow-y-auto pr-1">
{paginatedCustomers.map((customer) => { {paginatedCustomers.map((customer) => {
const isSelected = selectedEndCustomerId === customer.id const isSelected = selectedEndCustomerId === customer.id
@@ -479,7 +491,7 @@ export function StepCustomer({
</div> </div>
{isSelected && <Check className="w-5 h-5 text-primary mt-0.5 shrink-0" />} {isSelected && <Check className="w-5 h-5 text-primary mt-0.5 shrink-0" />}
</div> </div>
) );
})} })}
</div> </div>
@@ -540,12 +552,19 @@ export function StepCustomer({
)} )}
</div> </div>
)} )}
</div> </motion.div>
)} )}
{/* ─── MODUS B: NEUEN KUNDEN ANLEGEN ─── */} {/* ─── MODUS B: NEUEN KUNDEN ANLEGEN ─── */}
{customerMode === 'create' && ( {customerMode === 'create' && (
<div className="grid md:grid-cols-2 gap-4 p-4 rounded-xl bg-white/5 border border-white/10"> <motion.div
key="create"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
className="grid grid-cols-1 md:grid-cols-2 gap-4 p-4 rounded-xl bg-white/5 border border-white/10"
>
{( {(
[ [
{ label: 'Firmenname *', key: 'company_name', span: true, placeholder: 'GmbH / Einzelunternehmen' }, { label: 'Firmenname *', key: 'company_name', span: true, placeholder: 'GmbH / Einzelunternehmen' },
@@ -594,8 +613,11 @@ export function StepCustomer({
Abbrechen Abbrechen
</Button> </Button>
</div> </div>
</div> </motion.div>
)} )}
</AnimatePresence>
</div>
</div>
</CardContent> </CardContent>
<CardFooter className="flex justify-end border-t border-white/10 pt-6"> <CardFooter className="flex justify-end border-t border-white/10 pt-6">
<Button <Button