feat(wizard): add order notes field and scroll container
This commit is contained in:
@@ -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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user