@@ -9,35 +9,80 @@ interface ProgressModalProps {
99 error ?: string | null ;
1010 steps ?: string [ ] ;
1111 eventName ?: string ;
12+ description ?: string ;
1213 onStepChange ?: ( index : number ) => void ;
1314 /** Called after the realtime subscription is attached — start the API call here */
1415 onReady ?: ( ) => void ;
16+ /** Frappe setup_task status === "ok" (background setup) */
17+ onComplete ?: ( ) => void ;
18+ onFail ?: ( message : string ) => void ;
19+ }
20+
21+ type SetupTaskPayload = {
22+ step ?: number ;
23+ status ?: string ;
24+ progress ?: [ number , number ] ;
25+ stage_status ?: string ;
26+ fail_msg ?: string ;
27+ message ?: SetupTaskPayload ;
28+ } ;
29+
30+ function unwrapPayload ( data : unknown ) : SetupTaskPayload {
31+ if ( ! data || typeof data !== 'object' ) {
32+ return { } ;
33+ }
34+ const obj = data as SetupTaskPayload ;
35+ if ( obj . message && typeof obj . message === 'object' ) {
36+ return obj . message ;
37+ }
38+ return obj ;
1539}
1640
1741export function ProgressModal ( {
1842 visible,
1943 activeIndex,
2044 error,
2145 steps = PROGRESS_STEPS ,
22- eventName = 'ury_setup_progress' ,
46+ eventName = 'setup_task' ,
47+ description = 'Setting things up, this usually takes less than a minute.' ,
2348 onStepChange,
2449 onReady,
50+ onComplete,
51+ onFail,
2552} : ProgressModalProps ) {
26- // Keep onStepChange stable in a ref so the socket handler closure doesn't
27- // capture a stale version on every render.
2853 const onStepChangeRef = useRef ( onStepChange ) ;
2954 const onReadyRef = useRef ( onReady ) ;
55+ const onCompleteRef = useRef ( onComplete ) ;
56+ const onFailRef = useRef ( onFail ) ;
3057 useEffect ( ( ) => {
3158 onStepChangeRef . current = onStepChange ;
3259 onReadyRef . current = onReady ;
60+ onCompleteRef . current = onComplete ;
61+ onFailRef . current = onFail ;
3362 } ) ;
3463
3564 useEffect ( ( ) => {
3665 if ( ! visible ) return ;
3766
3867 const handler = ( data : unknown ) => {
39- const payload = data as { step ?: number ; status ?: string } ;
40- if ( typeof payload ?. step !== 'number' ) return ;
68+ const payload = unwrapPayload ( data ) ;
69+
70+ if ( payload . fail_msg || payload . status === 'fail' ) {
71+ onFailRef . current ?.( payload . fail_msg || 'Setup failed' ) ;
72+ return ;
73+ }
74+
75+ if ( payload . status === 'ok' ) {
76+ onCompleteRef . current ?.( ) ;
77+ return ;
78+ }
79+
80+ if ( Array . isArray ( payload . progress ) && typeof payload . progress [ 0 ] === 'number' ) {
81+ onStepChangeRef . current ?.( payload . progress [ 0 ] ) ;
82+ return ;
83+ }
84+
85+ if ( typeof payload . step !== 'number' ) return ;
4186
4287 if ( payload . status === 'loading' ) {
4388 onStepChangeRef . current ?.( payload . step ) ;
@@ -46,17 +91,11 @@ export function ProgressModal({
4691 }
4792 } ;
4893
49- // Subscribe first, then signal the parent that it is safe to start the
50- // backend API call. subscribeRealtimeEvent is async internally (connects
51- // the socket then calls .on()), but it registers the handler synchronously
52- // on the socket once the connection resolves. We call onReady() after
53- // kicking off the subscription so the caller can await the socket before
54- // starting the API. subscribeRealtimeEvent returns a cleanup fn.
5594 const unsubscribe = subscribeRealtimeEvent ( eventName , handler , ( ) => {
5695 onReadyRef . current ?.( ) ;
5796 } ) ;
97+
5898 return unsubscribe ;
59- // Re-subscribe only if the event name changes or visibility toggles
6099 } , [ visible , eventName ] ) ;
61100
62101 if ( ! visible ) return null ;
@@ -69,7 +108,7 @@ export function ProgressModal({
69108
70109 { /* Segmented Top Bar */ }
71110 < div className = "flex px-10 pt-10 pb-6 gap-1" >
72- { Array . from ( { length : totalSteps } ) . map ( ( _ , i ) => {
111+ { Array . from ( { length : Math . max ( totalSteps , 1 ) } ) . map ( ( _ , i ) => {
73112 const segmentProgress = i <= activeIndex ? 'bg-primary' : 'bg-gray-200' ;
74113 return (
75114 < div key = { i } className = { `flex-1 h-1.5 rounded-full ${ segmentProgress } ` } />
@@ -80,16 +119,16 @@ export function ProgressModal({
80119 < div className = "px-10 pb-8" >
81120 < h2 className = "text-2xl font-semibold text-foreground mb-1" > Setting up your restaurant</ h2 >
82121 < p className = "text-sm text-muted-foreground mb-6" >
83- Setting things up ,this usually takes less than a minute.
122+ { description }
84123 </ p >
85124
86- < div className = "flex flex-col mb-4" >
125+ < div className = "flex flex-col mb-4 max-h-[50vh] overflow-y-auto " >
87126 { steps . map ( ( step , idx ) => {
88127 const isDone = idx < activeIndex ;
89128 const isActive = idx === activeIndex ;
90129
91130 return (
92- < div key = { idx } className = "flex items-center gap-4 py-3 border-b border-gray-100 last:border-0 h-12" >
131+ < div key = { idx } className = "flex items-center gap-4 py-3 border-b border-gray-100 last:border-0 min- h-12" >
93132 < div className = "w-6 h-6 flex items-center justify-center shrink-0" >
94133 { isDone ? (
95134 < CheckCircle2 className = "w-6 h-6 text-white fill-green-500" />
0 commit comments