feat(wizard): add order notes field and scroll container

This commit is contained in:
DanielS
2026-08-06 17:42:05 +02:00
parent b40f8018f7
commit 6a95896361
2 changed files with 52 additions and 27 deletions

View File

@@ -166,6 +166,7 @@ export function OrderWizard({
return '' return ''
}) })
const [editingIdx, setEditingIdx] = useState<number | null>(null) const [editingIdx, setEditingIdx] = useState<number | null>(null)
const [orderNotes, setOrderNotes] = useState<string>('')
const [toast, setToast] = useState<{ message: string; type: 'error' | 'success' } | null>(null) const [toast, setToast] = useState<{ message: string; type: 'error' | 'success' } | null>(null)
useEffect(() => { useEffect(() => {
@@ -687,6 +688,7 @@ export function OrderWizard({
endCustomerId: selectedEndCustomerId, endCustomerId: selectedEndCustomerId,
endCustomer: selectedEndCustomer, endCustomer: selectedEndCustomer,
lastLicenseDate: lastLicenseDate || null, lastLicenseDate: lastLicenseDate || null,
notes: orderNotes || null,
}) })
}) })
@@ -859,40 +861,42 @@ export function OrderWizard({
</div> </div>
{/* CENTER: Sticky stepper + scrollable categories */} {/* CENTER: Sticky stepper + scrollable categories */}
<div className="lg:col-span-2 space-y-0"> <div className="lg:col-span-2 flex flex-col max-h-[calc(100vh-4rem)] overflow-hidden">
{/* Sticky stepper header — only covers center column */} {/* Sticky stepper header — only covers center column */}
<div className="sticky top-0 z-20 bg-slate-950/80 backdrop-blur-md pb-4 pt-6 border-b border-white/5 mb-6"> <div className="shrink-0 bg-slate-950/80 backdrop-blur-md pb-4 pt-2 border-b border-white/5 mb-4">
<p className="text-center text-slate-400 text-sm mb-4">Schritt 3 von 4 Software konfigurieren</p> <p className="text-center text-slate-400 text-sm mb-4">Schritt 3 von 4 Software konfigurieren</p>
<ProgressStepper step={step} basketItemsCount={basketItems.length} /> <ProgressStepper step={step} basketItemsCount={basketItems.length} />
</div> </div>
{/* Upgrade-Modus Hinweis-Banner */} {/* Scrollable category content area */}
{upgradeMode && lockedDeviceId && ( <div className="flex-1 overflow-y-auto pr-2 subpixel-antialiased scrollbar-thin scrollbar-thumb-white/10 scrollbar-track-transparent">
<div className="mb-4 p-3 rounded-xl bg-primary/10 border border-primary/20 text-xs text-primary/90 flex items-start gap-2"> {/* Upgrade-Modus Hinweis-Banner */}
<span className="text-primary mt-0.5"></span> {upgradeMode && lockedDeviceId && (
<div> <div className="mb-4 p-3 rounded-xl bg-primary/10 border border-primary/20 text-xs text-primary/90 flex items-start gap-2">
<p className="font-semibold">Upgrade-Modus: {lockedDeviceId}</p> <span className="text-primary mt-0.5"></span>
<p className="text-primary/70 mt-0.5">Bereits lizenzierte Module sind ausgegraut und können nicht doppelt gebucht werden.</p> <div>
<p className="font-semibold">Upgrade-Modus: {lockedDeviceId}</p>
<p className="text-primary/70 mt-0.5">Bereits lizenzierte Module sind ausgegraut und können nicht doppelt gebucht werden.</p>
</div>
</div> </div>
</div> )}
)}
{/* Scrollable category content */} <StepSoftware
<StepSoftware visibleCategories={visibleCategories}
visibleCategories={visibleCategories} products={products}
products={products} selections={selections}
selections={selections} selectProduct={selectProduct}
selectProduct={selectProduct} isProductDisabled={isProductDisabled}
isProductDisabled={isProductDisabled} isModuleDisabled={isModuleDisabled}
isModuleDisabled={isModuleDisabled} toggleModule={toggleModule}
toggleModule={toggleModule} moduleQuantities={moduleQuantities}
moduleQuantities={moduleQuantities} setModuleQuantities={setModuleQuantities}
setModuleQuantities={setModuleQuantities} selectedBillingInterval={selectedBillingInterval}
selectedBillingInterval={selectedBillingInterval} billingLabel={billingLabel}
billingLabel={billingLabel} billingBadgeClass={billingBadgeClass}
billingBadgeClass={billingBadgeClass} existingModuleIds={existingModuleIds}
existingModuleIds={existingModuleIds} />
/> </div>
</div> </div>
{/* RIGHT: Summary sidebar (sticky) */} {/* RIGHT: Summary sidebar (sticky) */}
@@ -961,6 +965,8 @@ export function OrderWizard({
initialOrder={initialOrder} initialOrder={initialOrder}
prevStep={prevStep} prevStep={prevStep}
linkedFeeProducts={linkedFeeProducts} linkedFeeProducts={linkedFeeProducts}
orderNotes={orderNotes}
setOrderNotes={setOrderNotes}
/> />
</motion.div> </motion.div>
)} )}

View File

@@ -29,6 +29,8 @@ interface StepSummaryProps {
initialOrder: any initialOrder: any
prevStep: () => void prevStep: () => void
linkedFeeProducts?: Product[] linkedFeeProducts?: Product[]
orderNotes: string
setOrderNotes: (notes: string) => void
} }
function CategoryIcon({ icon, className }: { icon?: string | null; className?: string }) { function CategoryIcon({ icon, className }: { icon?: string | null; className?: string }) {
@@ -58,6 +60,8 @@ export function StepSummary({
initialOrder, initialOrder,
prevStep, prevStep,
linkedFeeProducts = [], linkedFeeProducts = [],
orderNotes,
setOrderNotes,
}: StepSummaryProps) { }: StepSummaryProps) {
return ( return (
<Card className="glass-dark border-primary/30 max-w-2xl mx-auto shadow-primary/10 shadow-2xl"> <Card className="glass-dark border-primary/30 max-w-2xl mx-auto shadow-primary/10 shadow-2xl">
@@ -263,6 +267,21 @@ export function StepSummary({
</div> </div>
</div> </div>
)} )}
{/* Anmerkungen / Notizfeld */}
<div className="space-y-2 border-t border-white/10 pt-4">
<label htmlFor="order-notes" className="block text-sm font-semibold text-white flex items-center gap-2">
<span>Anmerkungen / Hinweise zur Bestellung (optional)</span>
</label>
<textarea
id="order-notes"
rows={3}
value={orderNotes}
onChange={e => setOrderNotes(e.target.value)}
placeholder="Besondere Hinweise, Ansprechpartner oder Terminwünsche hier eintragen..."
className="w-full p-3 rounded-xl bg-slate-900/80 border border-slate-800 text-sm text-white placeholder-slate-500 focus:border-sky-400 focus:outline-none transition-colors duration-200 resize-none"
/>
</div>
<p className="text-xs text-slate-500 italic"> <p className="text-xs text-slate-500 italic">
Mit dem Klick auf Kostenpflichtig bestellen" akzeptieren Sie unsere AGB und die{' '} Mit dem Klick auf Kostenpflichtig bestellen" akzeptieren Sie unsere AGB und die{' '}
<a href="/datenschutz" target="_blank" rel="noopener noreferrer" className="underline hover:text-slate-400"> <a href="/datenschutz" target="_blank" rel="noopener noreferrer" className="underline hover:text-slate-400">