fix(onboarding): require fields before advancing steps
- Validate each step before allowing goNext - Show required error message on name step if empty - Clear error on input change 💘 Generated with Crush Assisted-by: MiniMax-M2.7 via Crush <crush@charm.land>
This commit is contained in:
@@ -25,14 +25,31 @@ export default function OnboardingWizard({ api, onComplete }) {
|
|||||||
})
|
})
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
|
const [requiredError, setRequiredError] = useState(false)
|
||||||
|
|
||||||
const current = STEPS[step]
|
const current = STEPS[step]
|
||||||
const layouts = getLayoutList()
|
const layouts = getLayoutList()
|
||||||
|
|
||||||
const goNext = () => {
|
const goNext = () => {
|
||||||
if (step < STEPS.length - 1) setStep(step + 1)
|
if (step < STEPS.length - 1) {
|
||||||
|
if (!canProceed) { setRequiredError(true); return }
|
||||||
|
setRequiredError(false)
|
||||||
|
setStep(step + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const canProceed = (() => {
|
||||||
|
switch (current.key) {
|
||||||
|
case 'welcome': return true
|
||||||
|
case 'name': return answers.name.trim().length > 0
|
||||||
|
case 'language': return !!answers.language
|
||||||
|
case 'keyboard': return !!answers.keyboard
|
||||||
|
case 'editor': return true
|
||||||
|
case 'done': return true
|
||||||
|
default: return true
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
const goPrev = () => {
|
const goPrev = () => {
|
||||||
if (step > 0) setStep(step - 1)
|
if (step > 0) setStep(step - 1)
|
||||||
}
|
}
|
||||||
@@ -103,9 +120,10 @@ export default function OnboardingWizard({ api, onComplete }) {
|
|||||||
className="onboarding-input"
|
className="onboarding-input"
|
||||||
placeholder="Votre nom..."
|
placeholder="Votre nom..."
|
||||||
value={answers.name}
|
value={answers.name}
|
||||||
onChange={e => setAnswers(a => ({ ...a, name: e.target.value }))}
|
onChange={e => { setAnswers(a => ({ ...a, name: e.target.value })); setRequiredError(false) }}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
|
{requiredError && <div className="onboarding-required">Veuillez entrer votre nom</div>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -205,6 +223,11 @@ export default function OnboardingWizard({ api, onComplete }) {
|
|||||||
Suivant <ArrowRight size={14} />
|
Suivant <ArrowRight size={14} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
{step === STEPS.length - 1 && !saving && !error && (
|
||||||
|
<button className="primary" onClick={handleSave}>
|
||||||
|
Commencer
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -256,6 +279,9 @@ export default function OnboardingWizard({ api, onComplete }) {
|
|||||||
padding: 16px 20px; border-top: 1px solid var(--border);
|
padding: 16px 20px; border-top: 1px solid var(--border);
|
||||||
background: var(--bg-surface);
|
background: var(--bg-surface);
|
||||||
}
|
}
|
||||||
|
.onboarding-required {
|
||||||
|
font-size: 12px; color: var(--error); margin-top: 4px;
|
||||||
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user