@@ -18,6 +18,7 @@ import { CategoryStep } from './steps/CategoryStep';
1818import { PrivacyStep } from './steps/PrivacyStep' ;
1919import { ComplementStep } from './steps/ComplementStep' ;
2020import StatementPreview from './StatementPreview' ;
21+ import { Button } from '../ui/button' ;
2122
2223interface StatementWizardProps {
2324 username : string ;
@@ -36,11 +37,11 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
3637 const isPreset = Boolean ( presetQuestion ) ;
3738
3839 // Define steps: if preset, skip "category" and add "complement"
39- const steps : Step [ ] = isPreset
40+ const steps : Exclude < Step , 'closed' > [ ] = isPreset
4041 ? [ 'subject' , 'verb' , 'object' , 'privacy' , 'complement' ]
4142 : [ 'subject' , 'verb' , 'object' , 'category' , 'privacy' ] ;
4243
43- //
44+ // Use design tokens for border colors via Tailwind’s arbitrary value syntax:
4445 const stepBorderColors : Record < Exclude < Step , 'closed' > , string > = {
4546 subject : 'border-[var(--subject-selector)]' ,
4647 verb : 'border-[var(--verb-selector)]' ,
@@ -63,8 +64,8 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
6364 } ,
6465 category : '' ,
6566 } ) ;
67+ const [ isSubmitting , setIsSubmitting ] = useState ( false ) ;
6668
67- // If using a preset that presets subject, set it to username
6869 useEffect ( ( ) => {
6970 if ( presetQuestion ?. steps ?. subject ?. preset ) {
7071 setSelection ( ( prev ) => ( {
@@ -76,10 +77,7 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
7677
7778 const currentStep = steps [ currentStepIndex ] ;
7879
79- const [ isSubmitting , setIsSubmitting ] = useState ( false ) ;
80-
8180 const handleComplete = async ( ) => {
82- // Prevent multiple clicks if already submitting
8381 if ( isSubmitting ) return ;
8482 setIsSubmitting ( true ) ;
8583 const { subject, verb, object, adverbial } = selection . atoms ;
@@ -110,7 +108,6 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
110108 }
111109 } ;
112110
113- // Advance to the next step or finish if on the last step
114111 const goNext = ( ) => {
115112 if ( currentStepIndex < steps . length - 1 ) {
116113 setCurrentStepIndex ( ( prev ) => prev + 1 ) ;
@@ -127,6 +124,30 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
127124 }
128125 } ;
129126
127+ // Optional: Define a validation function for the current step.
128+ // This function should return true if the current step’s required data is valid.
129+ const isStepValid = ( step : Exclude < Step , 'closed' > ) : boolean => {
130+ switch ( step ) {
131+ case 'subject' :
132+ return selection . atoms . subject . trim ( ) . length > 0 ;
133+ case 'verb' :
134+ return selection . atoms . verb . trim ( ) . length > 0 ;
135+ case 'object' :
136+ return selection . atoms . object . trim ( ) . length > 0 ;
137+ case 'category' :
138+ return selection . category . trim ( ) . length > 0 ;
139+ case 'privacy' :
140+ // Always valid since it's a boolean toggle.
141+ return true ;
142+ case 'complement' :
143+ // Complement is optional; consider it valid.
144+ return true ;
145+ default :
146+ return false ;
147+ }
148+ } ;
149+
150+ // Render the current step component without navigation buttons.
130151 const renderStep = ( ) => {
131152 switch ( currentStep ) {
132153 case 'subject' :
@@ -141,8 +162,6 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
141162 atoms : { ...prev . atoms , subject : val } ,
142163 } ) )
143164 }
144- onNext = { goNext }
145- onBack = { goBack }
146165 />
147166 ) ;
148167 case 'verb' :
@@ -156,8 +175,6 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
156175 atoms : { ...prev . atoms , verb : val } ,
157176 } ) )
158177 }
159- onNext = { goNext }
160- onBack = { goBack }
161178 />
162179 ) ;
163180 case 'object' :
@@ -172,8 +189,6 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
172189 atoms : { ...prev . atoms , object : val } ,
173190 } ) )
174191 }
175- onNext = { goNext }
176- onBack = { goBack }
177192 />
178193 ) ;
179194 case 'category' :
@@ -186,27 +201,10 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
186201 category : val ,
187202 } ) )
188203 }
189- onNext = { goNext }
190- onBack = { goBack }
191204 />
192205 ) ;
193206 case 'privacy' :
194- return isPreset ? (
195- // In preset flow, privacy isn't final (next goes to complement)
196- < PrivacyStep
197- isPublic = { selection . isPublic }
198- onUpdate = { ( val ) =>
199- setSelection ( ( prev ) => ( {
200- ...prev ,
201- isPublic : val ,
202- } ) )
203- }
204- onNext = { goNext }
205- onBack = { goBack }
206- isSubmitting = { isSubmitting }
207- />
208- ) : (
209- // In custom flow, privacy is the final step so we call handleComplete
207+ return (
210208 < PrivacyStep
211209 isPublic = { selection . isPublic }
212210 onUpdate = { ( val ) =>
@@ -215,32 +213,26 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
215213 isPublic : val ,
216214 } ) )
217215 }
218- onNext = { handleComplete }
219- onBack = { goBack }
220- isSubmitting = { isSubmitting }
221216 />
222217 ) ;
223218 case 'complement' :
224- return (
225- < ComplementStep
226- onComplete = { handleComplete }
227- onBack = { goBack }
228- isSubmitting = { isSubmitting }
229- />
230- ) ;
219+ return < ComplementStep /> ;
231220 default :
232221 return null ;
233222 }
234223 } ;
235224
225+ // Helper function to get the border color class
226+ const getBorderColor = ( step : Exclude < Step , 'closed' > ) : string => {
227+ return stepBorderColors [ step ] ;
228+ } ;
229+
236230 return (
237231 < Dialog open onOpenChange = { onClose } >
238232 < DialogContent
239- className = { `sm:max-w-[600px] p-0 w-full border-8 ${
240- currentStep !== 'closed'
241- ? stepBorderColors [ currentStep as Exclude < Step , 'closed' > ]
242- : ''
243- } `}
233+ className = { `sm:max-w-[600px] p-0 w-full border-8 ${ getBorderColor (
234+ currentStep
235+ ) } `}
244236 >
245237 { presetQuestion && (
246238 < div className = 'px-4 py-3 bg-gray-200 border-b' >
@@ -261,6 +253,31 @@ const StatementWizard: React.FC<StatementWizardProps> = ({
261253 </ motion . div >
262254 </ AnimatePresence >
263255 < StatementPreview selection = { selection } />
256+ { /* Navigation Panel */ }
257+ < div className = 'flex justify-between p-4 border-t' >
258+ < Button
259+ onClick = { goBack }
260+ disabled = { currentStepIndex === 0 }
261+ variant = 'pink'
262+ className = 'mx-auto'
263+ >
264+ Back
265+ </ Button >
266+ < Button
267+ variant = 'pink'
268+ className = 'mx-auto'
269+ onClick = {
270+ currentStepIndex === steps . length - 1 ? handleComplete : goNext
271+ }
272+ disabled = { ! isStepValid ( currentStep ) || isSubmitting }
273+ >
274+ { isSubmitting
275+ ? 'Submitting...'
276+ : currentStepIndex === steps . length - 1
277+ ? 'Create Statement'
278+ : 'Next' }
279+ </ Button >
280+ </ div >
264281 </ DialogContent >
265282 </ Dialog >
266283 ) ;
0 commit comments