Compare commits

...

2 Commits

Author SHA1 Message Date
DanielS
ed654f542c feat(wizard): optimize step 3 layout and add category navigation
Some checks failed
Staging Build / build (push) Failing after 28s
2026-08-10 22:50:24 +02:00
DanielS
be3b0f615d fix(header) change text color from blue to white 2026-08-10 22:36:36 +02:00
4 changed files with 231 additions and 145 deletions

View File

@@ -197,7 +197,7 @@ export function NavbarClient({ user, role = "partner" }: NavbarClientProps) {
</div> </div>
) : ( ) : (
<Button asChild className="bg-primary hover:bg-primary/95 text-white dark:text-blue-500"> <Button asChild className="bg-primary hover:bg-primary/95 text-white">
<Link href={`/auth/login?next=${pathname}`}>Anmelden</Link> <Link href={`/auth/login?next=${pathname}`}>Anmelden</Link>
</Button> </Button>
)} )}
@@ -287,7 +287,7 @@ export function NavbarClient({ user, role = "partner" }: NavbarClientProps) {
<LogOut className="w-4 h-4" /> Abmelden <LogOut className="w-4 h-4" /> Abmelden
</Button> </Button>
) : ( ) : (
<Button asChild className="w-full bg-primary hover:bg-primary/95 text-white dark:text-blue-500" onClick={() => setIsMobileMenuOpen(false)}> <Button asChild className="w-full bg-primary hover:bg-primary/95 text-white" onClick={() => setIsMobileMenuOpen(false)}>
<Link href={`/auth/login?next=${pathname}`}>Anmelden</Link> <Link href={`/auth/login?next=${pathname}`}>Anmelden</Link>
</Button> </Button>
)} )}

View File

@@ -168,6 +168,7 @@ export function OrderWizard({
const [editingIdx, setEditingIdx] = useState<number | null>(null) const [editingIdx, setEditingIdx] = useState<number | null>(null)
const [orderNotes, setOrderNotes] = useState<string>('') 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)
const [activeCategoryId, setActiveCategoryId] = useState<string | null>(null)
useEffect(() => { useEffect(() => {
if (toast) { if (toast) {
@@ -235,6 +236,12 @@ export function OrderWizard({
}) })
}, [categories, selectedBillingInterval]) }, [categories, selectedBillingInterval])
useEffect(() => {
if (visibleCategories.length > 0 && !visibleCategories.some(c => c.id === activeCategoryId)) {
setActiveCategoryId(visibleCategories[0].id)
}
}, [visibleCategories, activeCategoryId])
// Endkunden Filterung // Endkunden Filterung
const filteredEndCustomers = useMemo(() => { const filteredEndCustomers = useMemo(() => {
const term = searchTerm.toLowerCase().trim() const term = searchTerm.toLowerCase().trim()
@@ -843,8 +850,6 @@ export function OrderWizard({
nextStep={nextStep} nextStep={nextStep}
/> />
</motion.div> </motion.div>
)}
{/* Step 3: Software Selector */} {/* Step 3: Software Selector */}
{step === 3 && ( {step === 3 && (
<motion.div <motion.div
@@ -852,23 +857,76 @@ export function OrderWizard({
initial={{ opacity: 0, x: 20 }} initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }} exit={{ opacity: 0, x: -20 }}
className="h-[calc(100vh-140px)] overflow-hidden"
> >
<div className="grid grid-cols-1 lg:grid-cols-6 gap-6 items-start"> <div className="grid grid-cols-1 lg:grid-cols-6 gap-6 h-full items-stretch">
{/* FAR LEFT: License Lookup Panel (sticky) */} {/* LEFT: Categories Sidebar Menu */}
<div className="lg:col-span-2 sticky top-6"> <div className="lg:col-span-2 flex flex-col justify-start pr-4 space-y-6">
<LicenseLookupPanel /> <div>
</div> <h1 className="text-3xl font-extrabold tracking-tight mb-2 text-gradient">
Software konfigurieren
{/* CENTER: Sticky stepper + scrollable categories */} </h1>
<div className="lg:col-span-2 flex flex-col max-h-[calc(100vh-4rem)] overflow-hidden"> <p className="text-slate-400 text-sm">
{/* Sticky stepper header — only covers center column */} Klicken Sie sich durch die Kategorien und wählen Sie Ihre Lizenzen.
<div className="shrink-0 bg-slate-950/80 backdrop-blur-md pb-4 pt-2 border-b border-white/5 mb-4"> </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} />
</div> </div>
{/* Scrollable category content area */} <div className="flex flex-col gap-2">
{visibleCategories.map((cat) => {
const sel = selections[cat.id]
const hasSelection = sel?.productIds?.length > 0 || !!sel?.productId
const isRequired = cat.is_required
const isActive = activeCategoryId === cat.id
return (
<button
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'
}`}
>
{/* Left glow line for active category */}
{isActive && (
<div className="absolute left-0 top-0 bottom-0 w-1 bg-primary" />
)}
<div className={`p-2 rounded-lg transition-colors ${
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" />
</div>
<div className="flex-1 min-w-0">
<p className={`text-sm font-semibold truncate ${isActive ? 'text-white' : 'text-slate-300 group-hover:text-white'}`}>
{cat.name}
</p>
<p className="text-[11px] text-slate-500 truncate mt-0.5">
{cat.description || 'Optionen ansehen'}
</p>
</div>
{/* Status indicators */}
{hasSelection ? (
<div className="w-5 h-5 rounded-full bg-green-500/20 border border-green-500/35 flex items-center justify-center text-green-400 shrink-0">
<Check className="w-3 h-3" />
</div>
) : isRequired ? (
<div className="w-2 h-2 rounded-full bg-red-500 shrink-0 animate-pulse" />
) : (
<span className="text-[10px] text-slate-600 uppercase tracking-wider shrink-0 font-medium">Opt</span>
)}
</button>
)
})}
</div>
</div>
{/* CENTER: Scrollable Category Selection */}
<div className="lg:col-span-2 flex flex-col h-full overflow-hidden border-x border-white/5 px-4">
<div className="flex-1 overflow-y-auto pr-2 subpixel-antialiased scrollbar-thin scrollbar-thumb-white/10 scrollbar-track-transparent"> <div className="flex-1 overflow-y-auto pr-2 subpixel-antialiased scrollbar-thin scrollbar-thumb-white/10 scrollbar-track-transparent">
{/* Upgrade-Modus Hinweis-Banner */} {/* Upgrade-Modus Hinweis-Banner */}
{upgradeMode && lockedDeviceId && ( {upgradeMode && lockedDeviceId && (
@@ -895,46 +953,59 @@ export function OrderWizard({
billingLabel={billingLabel} billingLabel={billingLabel}
billingBadgeClass={billingBadgeClass} billingBadgeClass={billingBadgeClass}
existingModuleIds={existingModuleIds} existingModuleIds={existingModuleIds}
activeCategoryId={activeCategoryId}
/> />
</div> </div>
</div> </div>
{/* RIGHT: Summary sidebar (sticky) */} {/* RIGHT: Stepper Header + Summary sidebar */}
<div className="lg:col-span-2 sticky top-6"> <div className="lg:col-span-2 flex flex-col h-full overflow-hidden pl-4">
<SummarySidebar {/* Steps indicator at the top right */}
visibleCategories={visibleCategories} <div className="shrink-0 pb-4 border-b border-white/5 mb-4">
selections={selections} <p className="text-right text-slate-400 text-xs mb-2">Schritt 3 von 4 Software konfigurieren</p>
products={products} <ProgressStepper step={step} basketItemsCount={basketItems.length} />
moduleQuantities={moduleQuantities} </div>
billingLabel={billingLabel}
oneTimeTotal={oneTimeTotal} <div className="flex-1 overflow-y-auto pr-1">
monthlyTotal={monthlyTotal} <SummarySidebar
oneTimeNet={oneTimeNet} visibleCategories={visibleCategories}
oneTimeTax={oneTimeTax} selections={selections}
oneTimeGross={oneTimeGross} products={products}
monthlyNet={monthlyNet} moduleQuantities={moduleQuantities}
monthlyTax={monthlyTax} billingLabel={billingLabel}
monthlyGross={monthlyGross} oneTimeTotal={oneTimeTotal}
updatePriceModifier={updatePriceModifier} monthlyTotal={monthlyTotal}
allCategoriesFilled={allCategoriesFilled} oneTimeNet={oneTimeNet}
productValidationErrors={productValidationErrors} oneTimeTax={oneTimeTax}
basketItems={basketItems} oneTimeGross={oneTimeGross}
editingIdx={editingIdx} monthlyNet={monthlyNet}
editBasketItem={editBasketItem} monthlyTax={monthlyTax}
deleteBasketItem={deleteBasketItem} monthlyGross={monthlyGross}
deviceName={deviceName} updatePriceModifier={updatePriceModifier}
setDeviceName={setDeviceName} allCategoriesFilled={allCategoriesFilled}
addToBasket={addToBasket} productValidationErrors={productValidationErrors}
isNextStepDisabled={isNextStepDisabled} basketItems={basketItems}
hasActiveSelection={hasActiveSelection} editingIdx={editingIdx}
nextStep={nextStep} editBasketItem={editBasketItem}
prevStep={prevStep} deleteBasketItem={deleteBasketItem}
/> deviceName={deviceName}
setDeviceName={setDeviceName}
addToBasket={addToBasket}
isNextStepDisabled={isNextStepDisabled}
hasActiveSelection={hasActiveSelection}
nextStep={nextStep}
prevStep={prevStep}
/>
</div>
</div> </div>
</div> </div>
</motion.div> </motion.div>
)} )}
{/* Step 4: Verification & Submit */} {/* Step 4: Verification & Submit */}
{step === 4 && ( {step === 4 && (
<motion.div <motion.div

View File

@@ -49,22 +49,47 @@ export function StepBilling({
: 'border-white/5 bg-white/5 hover:border-white/20' : 'border-white/5 bg-white/5 hover:border-white/20'
}`} }`}
> >
<div> <div className="flex flex-col justify-between h-full">
<div className="flex items-center gap-3 mb-3"> <div>
<div className={`p-3 rounded-xl ${selectedBillingInterval === 'one_time' ? 'bg-primary/20 text-primary' : 'bg-white/5 text-slate-400'}`}> <div className="flex items-center gap-3 mb-3">
<CreditCard className="w-6 h-6" /> <div className={`p-3 rounded-xl ${selectedBillingInterval === 'one_time' ? 'bg-primary/20 text-primary' : 'bg-white/5 text-slate-400'}`}>
<CreditCard className="w-6 h-6" />
</div>
<h3 className="text-lg font-bold text-white">Einmaliger Kauf</h3>
</div> </div>
<h3 className="text-lg font-bold text-white">Einmaliger Kauf</h3> <p className="text-slate-400 text-sm">
Einmalige Anschaffungskosten für die Softwarelizenz. Keine monatlichen Mietgebühren.
</p>
</div> </div>
<p className="text-slate-400 text-sm">
Einmalige Anschaffungskosten für die Softwarelizenz. Keine monatlichen Mietgebühren. {selectedBillingInterval === 'one_time' && (
</p> <div className="absolute top-4 right-4 w-6 h-6 rounded-full bg-primary flex items-center justify-center text-white">
<Check className="w-4 h-4" />
</div>
)}
{selectedBillingInterval === 'one_time' && customerMode === 'select' && selectedEndCustomerId && (
<div
onClick={(e) => e.stopPropagation()}
className="mt-4 pt-4 border-t border-white/5 space-y-2 cursor-default"
>
<Label htmlFor="last-license-date" className="text-white text-xs font-medium flex items-center gap-2">
<Calendar className="w-3.5 h-3.5 text-primary" />
Datum der letzten CASPOS-Lizenz
</Label>
<Input
id="last-license-date"
type="date"
value={lastLicenseDate}
onChange={e => setLastLicenseDate(e.target.value)}
className="bg-[#0b1329] border-white/10 text-white text-xs h-8 focus:border-primary"
/>
<p className="text-[10px] text-slate-500">
Ermöglicht automatische Ermittlung von Update-Gebühren.
</p>
</div>
)}
</div> </div>
{selectedBillingInterval === 'one_time' && (
<div className="absolute top-4 right-4 w-6 h-6 rounded-full bg-primary flex items-center justify-center text-white">
<Check className="w-4 h-4" />
</div>
)}
</div> </div>
{/* Option 2: Abo */} {/* Option 2: Abo */}
@@ -92,26 +117,6 @@ export function StepBilling({
</div> </div>
)} )}
</div> </div>
</div>
{/* Alte Lizenznummereingabe / Datum vorerst ausgeblendet */}
{/* {selectedBillingInterval === 'one_time' && customerMode === 'select' && selectedEndCustomerId && (
<div className="p-4 rounded-xl bg-white/5 border border-white/10 space-y-3 mt-6 max-w-md animate-in fade-in slide-in-from-top-2 duration-300">
<Label htmlFor="last-license-date" className="text-white font-medium flex items-center gap-2">
<Calendar className="w-4 h-4 text-primary" />
Datum der letzten CASPOS-Lizenz (falls vorhanden)
</Label>
<Input
id="last-license-date"
type="date"
value={lastLicenseDate}
onChange={e => setLastLicenseDate(e.target.value)}
className="bg-[#0b1329] border-white/10 text-white focus:border-primary"
/>
<p className="text-xs text-slate-400">
Falls dieser Kunde bereits Lizenzen besitzt, tragen Sie das Datum der letzten Lizenzierung ein. Damit werden die korrekten Update-Gebühren ermittelt.
</p>
</div>
)} */}
</CardContent> </CardContent>
<CardFooter className="flex justify-between border-t border-white/10 pt-6"> <CardFooter className="flex justify-between border-t border-white/10 pt-6">
<Button variant="ghost" className="text-white" onClick={prevStep}> <Button variant="ghost" className="text-white" onClick={prevStep}>

View File

@@ -10,6 +10,7 @@ import { Input } from '@/components/ui/input'
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import { ShoppingCart, Check, AlertCircle, Lock } from 'lucide-react' import { ShoppingCart, Check, AlertCircle, Lock } from 'lucide-react'
import * as Icons from 'lucide-react' import * as Icons from 'lucide-react'
import { motion, AnimatePresence } from 'framer-motion'
import { Category, Product, CategorySelection } from '@/lib/types' import { Category, Product, CategorySelection } from '@/lib/types'
interface StepSoftwareProps { interface StepSoftwareProps {
@@ -27,6 +28,7 @@ interface StepSoftwareProps {
billingBadgeClass: (interval: string) => string billingBadgeClass: (interval: string) => string
/** Modul-IDs, die bereits lizenziert sind (Upgrade-Modus) */ /** Modul-IDs, die bereits lizenziert sind (Upgrade-Modus) */
existingModuleIds?: string[] existingModuleIds?: string[]
activeCategoryId: string | null
} }
function CategoryIcon({ icon, className }: { icon?: string | null; className?: string }) { function CategoryIcon({ icon, className }: { icon?: string | null; className?: string }) {
@@ -49,76 +51,85 @@ export function StepSoftware({
billingLabel, billingLabel,
billingBadgeClass, billingBadgeClass,
existingModuleIds = [], existingModuleIds = [],
activeCategoryId,
}: StepSoftwareProps) { }: StepSoftwareProps) {
const currentCategory = visibleCategories.find(c => c.id === activeCategoryId) ?? visibleCategories[0] ?? null
if (!currentCategory) return null
const catProducts = products.filter(p => {
if (p.category_id !== currentCategory.id) return false
return selectedBillingInterval === 'one_time'
? p.show_in_kauf !== false
: p.show_in_abo !== false
})
const sel = selections[currentCategory.id]
const selectedProduct = catProducts.find(p => p.id === sel?.productId) ?? null
return ( return (
<Card className="glass-dark border-white/10"> <Card className="glass-dark border-white/10 h-full flex flex-col">
<CardHeader> <CardHeader className="border-b border-white/5 pb-4">
<CardTitle className="text-2xl flex items-center gap-2 text-white"> <CardTitle className="text-xl flex items-center gap-2 text-white">
<ShoppingCart className="w-6 h-6 text-blue-400" /> <ShoppingCart className="w-5 h-5 text-blue-400" />
Software wählen Optionen wählen
</CardTitle> </CardTitle>
<CardDescription className="text-slate-300"> <CardDescription className="text-slate-400">
Wählen Sie pro Kategorie mindestens einen Artikel aus. Passen Sie die Konfiguration für {currentCategory.name} an.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-8"> <CardContent className="flex-1 overflow-y-auto pt-6 space-y-6">
{visibleCategories.map((cat, idx) => { <AnimatePresence mode="wait">
const catProducts = products.filter(p => { <motion.div
if (p.category_id !== cat.id) return false key={currentCategory.id}
return selectedBillingInterval === 'one_time' initial={{ opacity: 0, y: 10 }}
? p.show_in_kauf !== false animate={{ opacity: 1, y: 0 }}
: p.show_in_abo !== false exit={{ opacity: 0, y: -10 }}
}) transition={{ duration: 0.2 }}
const sel = selections[cat.id] className="space-y-6"
const selectedProduct = catProducts.find(p => p.id === sel?.productId) ?? null >
{/* Category header */}
return ( <div className="flex items-center gap-3">
<div key={cat.id}> <div className="w-8 h-8 rounded-lg bg-primary/20 flex items-center justify-center">
{idx > 0 && <Separator className="bg-white/10 mb-8" />} <CategoryIcon icon={currentCategory.icon} className="w-4 h-4 text-primary" />
</div>
{/* Category header */} <div>
<div className="flex items-center gap-3 mb-4"> <h3 className="font-bold text-white text-base">{currentCategory.name}</h3>
<div className="w-8 h-8 rounded-lg bg-primary/20 flex items-center justify-center"> {currentCategory.description && (
<CategoryIcon icon={cat.icon} className="w-4 h-4 text-primary" /> <p className="text-slate-400 text-xs">{currentCategory.description}</p>
</div> )}
<div> </div>
<h3 className="font-bold text-white text-lg">{cat.name}</h3> {sel?.productIds && sel.productIds.length > 0 ? (
{cat.description && ( <Badge className="ml-auto bg-green-500/20 text-green-400 border border-green-500/30">
<p className="text-slate-400 text-xs">{cat.description}</p> <Check className="w-3 h-3 mr-1" /> {sel.productIds.length} Ausgewählt
)} </Badge>
</div> ) : sel?.productId ? (
{sel?.productIds && sel.productIds.length > 0 ? ( <Badge className="ml-auto bg-green-500/20 text-green-400 border border-green-500/30">
<Badge className="ml-auto bg-green-500/20 text-green-400 border border-green-500/30"> <Check className="w-3 h-3 mr-1" /> Ausgewählt
<Check className="w-3 h-3 mr-1" /> {sel.productIds.length} Ausgewählt </Badge>
</Badge> ) : currentCategory.is_required ? (
) : sel?.productId ? ( <Badge variant="destructive" className="ml-auto opacity-80">
<Badge className="ml-auto bg-green-500/20 text-green-400 border border-green-500/30"> <AlertCircle className="w-3 h-3 mr-1" /> Pflichtfeld
<Check className="w-3 h-3 mr-1" /> Ausgewählt </Badge>
</Badge> ) : (
) : cat.is_required ? ( <Badge variant="outline" className="ml-auto border-white/20 text-slate-400">
<Badge variant="destructive" className="ml-auto opacity-80"> Optional
<AlertCircle className="w-3 h-3 mr-1" /> Pflichtfeld </Badge>
</Badge> )}
) : ( </div>
<Badge variant="outline" className="ml-auto border-white/20 text-slate-400">
Optional
</Badge>
)}
</div>
{catProducts.length === 0 ? ( {catProducts.length === 0 ? (
<p className="text-slate-500 text-sm italic"> <p className="text-slate-500 text-sm italic">
Keine Produkte in dieser Kategorie im aktuellen Abrechnungsmodell vorhanden. Keine Produkte in dieser Kategorie im aktuellen Abrechnungsmodell vorhanden.
</p> </p>
) : cat.allow_multiselect ? ( ) : currentCategory.allow_multiselect ? (
<div className="grid gap-3"> <div className="grid gap-3">
{catProducts.map(product => { {catProducts.map(product => {
const isChecked = sel?.productIds?.includes(product.id) ?? false const isChecked = sel?.productIds?.includes(product.id) ?? false
const disabled = isProductDisabled(product, cat.id) const disabled = isProductDisabled(product, currentCategory.id)
return ( return (
<div key={product.id} className="relative"> <div key={product.id} className="relative">
<Label <Label
onClick={() => !disabled && selectProduct(cat.id, product.id)} onClick={() => !disabled && selectProduct(currentCategory.id, product.id)}
className={`flex flex-col items-start p-4 rounded-xl border-2 transition-all ${disabled className={`flex flex-col items-start p-4 rounded-xl border-2 transition-all ${disabled
? 'border-white/5 bg-white/5 opacity-50 cursor-not-allowed' ? 'border-white/5 bg-white/5 opacity-50 cursor-not-allowed'
: isChecked : isChecked
@@ -163,21 +174,21 @@ export function StepSoftware({
) : ( ) : (
<RadioGroup <RadioGroup
value={sel?.productId ?? ''} value={sel?.productId ?? ''}
onValueChange={id => selectProduct(cat.id, id)} onValueChange={id => selectProduct(currentCategory.id, id)}
className="grid gap-3" className="grid gap-3"
> >
{catProducts.map(product => { {catProducts.map(product => {
const disabled = isProductDisabled(product, cat.id) const disabled = isProductDisabled(product, currentCategory.id)
return ( return (
<div key={product.id} className="relative"> <div key={product.id} className="relative">
<RadioGroupItem <RadioGroupItem
value={product.id} value={product.id}
id={`${cat.id}-${product.id}`} id={`${currentCategory.id}-${product.id}`}
disabled={disabled} disabled={disabled}
className="peer sr-only" className="peer sr-only"
/> />
<Label <Label
htmlFor={disabled ? undefined : `${cat.id}-${product.id}`} htmlFor={disabled ? undefined : `${currentCategory.id}-${product.id}`}
className={`flex flex-col items-start p-4 rounded-xl border-2 border-white/5 bg-white/5 transition-all ${disabled className={`flex flex-col items-start p-4 rounded-xl border-2 border-white/5 bg-white/5 transition-all ${disabled
? 'opacity-50 cursor-not-allowed' ? 'opacity-50 cursor-not-allowed'
: 'hover:bg-white/10 peer-data-[state=checked]:border-primary peer-data-[state=checked]:bg-primary/5 cursor-pointer' : 'hover:bg-white/10 peer-data-[state=checked]:border-primary peer-data-[state=checked]:bg-primary/5 cursor-pointer'
@@ -234,14 +245,14 @@ export function StepSoftware({
> >
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<Checkbox <Checkbox
id={`mod-${cat.id}-${module.id}`} id={`mod-${currentCategory.id}-${module.id}`}
checked={checked} checked={checked}
onCheckedChange={() => !isExistingLicense && toggleModule(cat.id, module.id)} onCheckedChange={() => !isExistingLicense && toggleModule(currentCategory.id, module.id)}
disabled={disabled} disabled={disabled}
/> />
<div className="flex-1"> <div className="flex-1">
<Label <Label
htmlFor={isExistingLicense ? undefined : `mod-${cat.id}-${module.id}`} htmlFor={isExistingLicense ? undefined : `mod-${currentCategory.id}-${module.id}`}
className={`font-medium flex justify-between text-white ${ className={`font-medium flex justify-between text-white ${
isExistingLicense ? 'cursor-default' : disabled ? 'cursor-not-allowed' : 'cursor-pointer' isExistingLicense ? 'cursor-default' : disabled ? 'cursor-not-allowed' : 'cursor-pointer'
}`} }`}
@@ -309,9 +320,8 @@ export function StepSoftware({
})} })}
</div> </div>
)} )}
</div> </motion.div>
) </AnimatePresence>
})}
</CardContent> </CardContent>
</Card> </Card>
) )