@@ -57,7 +57,8 @@ interface AnswerState {
5757export function SurveyForm ( { slug, fingerprint = 'anonymous' , autoAdvance = false , onSuccess, onError } : SurveyFormProps ) {
5858 const { colors, radius, typography, spacing } = useAppgramTheme ( )
5959 const { survey, nodes, isLoading, error } = useSurvey ( slug )
60- const { isSubmitting, submitResponse } = useSurveySubmit ( { onSuccess : ( ) => onSuccess ?.( ) , onError } )
60+ // Don't pass onSuccess to hook - we'll call it after showing success screen
61+ const { isSubmitting, submitResponse } = useSurveySubmit ( { onError } )
6162 const [ answers , setAnswers ] = useState < Map < string , AnswerState > > ( new Map ( ) )
6263 const [ visitedNodes , setVisitedNodes ] = useState < string [ ] > ( [ ] )
6364 const [ submitted , setSubmitted ] = useState ( false )
@@ -145,6 +146,11 @@ export function SurveyForm({ slug, fingerprint = 'anonymous', autoAdvance = fals
145146 return nodes . find ( n => n . id === node . next_node_id ) || null
146147 }
147148
149+ // If node has result_message, this is an endpoint - survey ends here
150+ if ( node . result_message ) {
151+ return null
152+ }
153+
148154 // Tree-based routing: find child node (node whose parent_id equals this node's id)
149155 const childNode = nodes . find ( n => n . parent_id === node . id )
150156 if ( childNode ) {
@@ -192,9 +198,9 @@ export function SurveyForm({ slug, fingerprint = 'anonymous', autoAdvance = fals
192198 } )
193199 }
194200
195- const handleSubmit = useCallback ( async ( ) => {
201+ const submitSurvey = useCallback ( async ( finalAnswers : Map < string , AnswerState > ) => {
196202 if ( ! survey ) return
197- const answerEntries = Array . from ( answers . entries ( ) ) . map ( ( [ nodeId , ans ] ) => ( {
203+ const answerEntries = Array . from ( finalAnswers . entries ( ) ) . map ( ( [ nodeId , ans ] ) => ( {
198204 node_id : nodeId ,
199205 answer : ans . answer ,
200206 answer_text : ans . answer_text ,
@@ -203,12 +209,18 @@ export function SurveyForm({ slug, fingerprint = 'anonymous', autoAdvance = fals
203209 } ) )
204210 const result = await submitResponse ( survey . id , { fingerprint, answers : answerEntries } )
205211 if ( result ) setSubmitted ( true )
206- } , [ survey , answers , submitResponse , fingerprint ] )
212+ } , [ survey , submitResponse , fingerprint ] )
207213
208- const goNext = useCallback ( ( ) => {
209- if ( ! currentNode || ! canProceed ) return
214+ // Handle answer and navigate - passes answer directly to avoid state timing issues
215+ const handleAnswer = useCallback ( ( answer : AnswerState ) => {
216+ if ( ! currentNode ) return
210217
211- const answer = answers . get ( currentNode . id )
218+ // Store answer
219+ const newAnswers = new Map ( answers )
220+ newAnswers . set ( currentNode . id , answer )
221+ setAnswers ( newAnswers )
222+
223+ // Determine next node using the answer directly (not from state)
212224 const nextNode = getNextNode ( currentNode , answer )
213225
214226 if ( nextNode ) {
@@ -217,9 +229,25 @@ export function SurveyForm({ slug, fingerprint = 'anonymous', autoAdvance = fals
217229 } )
218230 } else {
219231 // No next node — submit the survey
220- handleSubmit ( )
232+ submitSurvey ( newAnswers )
233+ }
234+ } , [ currentNode , answers , getNextNode , submitSurvey ] )
235+
236+ // For OK button - uses stored answer
237+ const goNext = useCallback ( ( ) => {
238+ if ( ! currentNode || ! canProceed ) return
239+ const answer = answers . get ( currentNode . id )
240+ if ( answer ) {
241+ const nextNode = getNextNode ( currentNode , answer )
242+ if ( nextNode ) {
243+ animateTransition ( 'next' , ( ) => {
244+ setVisitedNodes ( prev => [ ...prev , nextNode . id ] )
245+ } )
246+ } else {
247+ submitSurvey ( answers )
248+ }
221249 }
222- } , [ currentNode , canProceed , answers , getNextNode , handleSubmit ] )
250+ } , [ currentNode , canProceed , answers , getNextNode , submitSurvey ] )
223251
224252 const goPrev = useCallback ( ( ) => {
225253 if ( visitedNodes . length > 0 ) {
@@ -284,8 +312,8 @@ export function SurveyForm({ slug, fingerprint = 'anonymous', autoAdvance = fals
284312 < TouchableOpacity
285313 key = { opt }
286314 onPress = { ( ) => {
287- updateAnswer ( node . id , { answer_text : optValue , answer : opt === 'Yes' } )
288- if ( autoAdvance ) setTimeout ( goNext , 300 )
315+ // Use handleAnswer to avoid state timing issues
316+ handleAnswer ( { answer_text : optValue , answer : opt === 'Yes' } )
289317 } }
290318 style = { {
291319 flex : 1 ,
@@ -318,8 +346,8 @@ export function SurveyForm({ slug, fingerprint = 'anonymous', autoAdvance = fals
318346 < TouchableOpacity
319347 key = { i }
320348 onPress = { ( ) => {
321- updateAnswer ( node . id , { answer_options : [ opt . value ] } )
322- if ( autoAdvance ) setTimeout ( goNext , 300 )
349+ // Use handleAnswer to avoid state timing issues
350+ handleAnswer ( { answer_options : [ opt . value ] } )
323351 } }
324352 style = { {
325353 flexDirection : 'row' ,
@@ -417,8 +445,8 @@ export function SurveyForm({ slug, fingerprint = 'anonymous', autoAdvance = fals
417445 < TouchableOpacity
418446 key = { i }
419447 onPress = { ( ) => {
420- updateAnswer ( node . id , { answer_rating : i + 1 } )
421- if ( autoAdvance ) setTimeout ( goNext , 300 )
448+ // Use handleAnswer to avoid state timing issues
449+ handleAnswer ( { answer_rating : i + 1 } )
422450 } }
423451 style = { { padding : spacing . xs } }
424452 >
@@ -460,31 +488,18 @@ export function SurveyForm({ slug, fingerprint = 'anonymous', autoAdvance = fals
460488
461489 if ( ! survey || nodes . length === 0 ) return null
462490
463- // Show result message if current node has one (terminal node)
464- if ( currentNode ?. result_message ) {
465- return (
466- < View style = { { flex : 1 , justifyContent : 'center' , alignItems : 'center' , padding : spacing . xl } } >
467- < View style = { { width : 80 , height : 80 , borderRadius : 40 , backgroundColor : colors . primary + '20' , alignItems : 'center' , justifyContent : 'center' , marginBottom : spacing . lg } } >
468- < CheckCircle2 size = { 40 } color = { colors . primary } />
469- </ View >
470- < Text style = { { fontSize : typography [ '2xl' ] , fontWeight : '700' , color : colors . foreground , marginBottom : spacing . sm , textAlign : 'center' } } >
471- { currentNode . result_message }
472- </ Text >
473- </ View >
474- )
475- }
476-
477491 if ( submitted ) {
492+ // Show custom result_message from the last answered node, or default message
493+ const lastNodeId = visitedNodes [ visitedNodes . length - 1 ] || currentNodeId
494+ const lastNode = nodes . find ( n => n . id === lastNodeId )
495+ const resultMessage = lastNode ?. result_message || 'Thank you for your feedback!'
478496 return (
479497 < View style = { { flex : 1 , justifyContent : 'center' , alignItems : 'center' , padding : spacing . xl } } >
480498 < View style = { { width : 80 , height : 80 , borderRadius : 40 , backgroundColor : colors . primary + '20' , alignItems : 'center' , justifyContent : 'center' , marginBottom : spacing . lg } } >
481499 < CheckCircle2 size = { 40 } color = { colors . primary } />
482500 </ View >
483501 < Text style = { { fontSize : typography [ '2xl' ] , fontWeight : '700' , color : colors . foreground , marginBottom : spacing . sm , textAlign : 'center' } } >
484- Survey Submitted
485- </ Text >
486- < Text style = { { fontSize : typography . base , color : colors . mutedForeground , textAlign : 'center' } } >
487- Thank you for your feedback!
502+ { resultMessage }
488503 </ Text >
489504 </ View >
490505 )
0 commit comments