11"use client" ;
22
3- import React , { useCallback , useEffect , useRef , useState } from "react" ;
3+ import React , { useCallback , useEffect , useRef , useReducer } from "react" ;
44import { motion , AnimatePresence , useReducedMotion , type Variants } from "framer-motion" ;
55import confetti from "canvas-confetti" ;
66import { useTranslations } from "next-intl" ;
@@ -71,6 +71,55 @@ const checkVariantsReduced: Variants = {
7171 visible : { opacity : 1 , transition : { duration : 0.2 } } ,
7272} ;
7373
74+ interface AnimationState {
75+ isDismissing : boolean ;
76+ announcementText : string ;
77+ }
78+
79+ type AnimationAction =
80+ | { type : "RESET" }
81+ | { type : "SET_ANNOUNCEMENT" ; payload : string }
82+ | { type : "START_DISMISS" ; payload : string }
83+ | { type : "DISMISS_ERROR" ; payload : string }
84+ | { type : "DISMISS_SUCCESS" } ;
85+
86+ const initialState : AnimationState = {
87+ isDismissing : false ,
88+ announcementText : "" ,
89+ } ;
90+
91+ function animationReducer ( state : AnimationState , action : AnimationAction ) : AnimationState {
92+ switch ( action . type ) {
93+ case "RESET" :
94+ return {
95+ isDismissing : false ,
96+ announcementText : "" ,
97+ } ;
98+ case "SET_ANNOUNCEMENT" :
99+ return {
100+ ...state ,
101+ announcementText : action . payload ,
102+ } ;
103+ case "START_DISMISS" :
104+ return {
105+ isDismissing : true ,
106+ announcementText : action . payload ,
107+ } ;
108+ case "DISMISS_ERROR" :
109+ return {
110+ isDismissing : false ,
111+ announcementText : action . payload ,
112+ } ;
113+ case "DISMISS_SUCCESS" :
114+ return {
115+ ...state ,
116+ isDismissing : false ,
117+ } ;
118+ default :
119+ return state ;
120+ }
121+ }
122+
74123export const PaymentSuccessAnimation : React . FC < PaymentSuccessAnimationProps > = ( {
75124 show,
76125 onComplete,
@@ -88,44 +137,43 @@ export const PaymentSuccessAnimation: React.FC<PaymentSuccessAnimationProps> = (
88137 const containerRef = useRef < HTMLDivElement > ( null ) ;
89138 const prevIsOptimisticRef = useRef ( isOptimistic ) ;
90139
91- // Optimistic dismiss state (#981)
92- const [ isDismissing , setIsDismissing ] = useState ( false ) ;
93- // Dynamic live-region text for state transitions (#980, #981)
94- const [ announcementText , setAnnouncementText ] = useState ( "" ) ;
140+ const [ state , dispatch ] = useReducer ( animationReducer , initialState ) ;
141+ const { isDismissing, announcementText } = state ;
95142
96143 // Reset dismiss state when dialog closes
97144 useEffect ( ( ) => {
98145 if ( ! show ) {
99- setIsDismissing ( false ) ;
100- setAnnouncementText ( "" ) ;
146+ dispatch ( { type : "RESET" } ) ;
101147 }
102148 } , [ show ] ) ;
103149
104150 // Announce network confirmation when optimistic state resolves (#980)
105151 useEffect ( ( ) => {
106152 if ( ! show ) return ;
107153 if ( prevIsOptimisticRef . current === true && ! isOptimistic ) {
108- setAnnouncementText (
109- t ( "payment.networkConfirmed" ) || "Payment confirmed on the Stellar network."
110- ) ;
154+ dispatch ( {
155+ type : "SET_ANNOUNCEMENT" ,
156+ payload : t ( "payment.networkConfirmed" ) || "Payment confirmed on the Stellar network." ,
157+ } ) ;
111158 }
112159 prevIsOptimisticRef . current = isOptimistic ;
113160 } , [ isOptimistic , show , t ] ) ;
114161
115162 // Optimistic dismiss handler — UI responds immediately, rolls back on error (#981)
116163 const handleDismiss = useCallback ( async ( ) => {
117164 if ( isDismissing ) return ;
118- setIsDismissing ( true ) ;
119- setAnnouncementText ( t ( "payment.dismissing" ) || "Processing…" ) ;
165+ dispatch ( {
166+ type : "START_DISMISS" ,
167+ payload : t ( "payment.dismissing" ) || "Processing…" ,
168+ } ) ;
120169 try {
121170 await onComplete ?.( ) ;
122171 } catch ( err ) {
123172 const msg =
124173 err instanceof Error
125174 ? err . message
126175 : t ( "common.error" ) || "Something went wrong. Please try again." ;
127- setIsDismissing ( false ) ;
128- setAnnouncementText ( msg ) ;
176+ dispatch ( { type : "DISMISS_ERROR" , payload : msg } ) ;
129177 }
130178 } , [ isDismissing , onComplete , t ] ) ;
131179
0 commit comments