@@ -25,25 +25,40 @@ import { getCurrencyConfig, getCurrencySymbol, getMinimumAmount } from '@/utils/
2525import { OnrampConfirmationModal } from '@/components/AddMoney/components/OnrampConfirmationModal'
2626import { InitiateBridgeKYCModal } from '@/components/Kyc/InitiateBridgeKYCModal'
2727import InfoCard from '@/components/Global/InfoCard'
28+ import { useQueryStates , parseAsString , parseAsStringEnum } from 'nuqs'
2829
29- type AddStep = 'inputAmount' | 'kyc' | 'loading' | 'collectUserDetails' | 'showDetails'
30+ // Step type for URL state
31+ type BridgeBankStep = 'inputAmount' | 'kyc' | 'collectUserDetails' | 'showDetails'
3032
3133export default function OnrampBankPage ( ) {
3234 const router = useRouter ( )
3335 const params = useParams ( )
34- const [ step , setStep ] = useState < AddStep > ( 'loading' )
35- const [ rawTokenAmount , setRawTokenAmount ] = useState < string > ( '' )
36+
37+ // URL state - persisted in query params
38+ // Example: /add-money/mexico/bank?step=inputAmount&amount=500
39+ const [ urlState , setUrlState ] = useQueryStates (
40+ {
41+ step : parseAsStringEnum < BridgeBankStep > ( [ 'inputAmount' , 'kyc' , 'collectUserDetails' , 'showDetails' ] ) ,
42+ amount : parseAsString ,
43+ } ,
44+ { history : 'push' }
45+ )
46+
47+ // Amount from URL
48+ const rawTokenAmount = urlState . amount ?? ''
49+
50+ // Local UI state (not URL-appropriate - transient)
3651 const [ showWarningModal , setShowWarningModal ] = useState < boolean > ( false )
3752 const [ isRiskAccepted , setIsRiskAccepted ] = useState < boolean > ( false )
38-
3953 const [ isKycModalOpen , setIsKycModalOpen ] = useState ( false )
4054 const [ liveKycStatus , setLiveKycStatus ] = useState < BridgeKycStatus | undefined > ( undefined )
41- const { amountToOnramp : amountFromContext , setAmountToOnramp, setError, error, setOnrampData } = useOnrampFlow ( )
42- const formRef = useRef < { handleSubmit : ( ) => void } > ( null )
4355 const [ isUpdatingUser , setIsUpdatingUser ] = useState ( false )
4456 const [ userUpdateError , setUserUpdateError ] = useState < string | null > ( null )
4557 const [ isUserDetailsFormValid , setIsUserDetailsFormValid ] = useState ( false )
4658
59+ const { setError, error, setOnrampData, onrampData } = useOnrampFlow ( )
60+ const formRef = useRef < { handleSubmit : ( ) => void } > ( null )
61+
4762 const { balance } = useWallet ( )
4863 const { user, fetchUser } = useAuth ( )
4964 const { createOnramp, isLoading : isCreatingOnramp , error : onrampError } = useCreateOnramp ( )
@@ -82,32 +97,30 @@ export default function OnrampBankPage() {
8297 return getMinimumAmount ( selectedCountry . id )
8398 } , [ selectedCountry ?. id ] )
8499
100+ // Determine initial step based on KYC status (only when URL has no step)
85101 useEffect ( ( ) => {
86- if ( user === null ) return // wait for user to be fetched
87- if ( step === 'loading' ) {
88- const currentKycStatus = liveKycStatus || user ?. user . bridgeKycStatus
89- const isUserKycVerified = currentKycStatus === 'approved'
102+ // If URL already has a step, respect it (allows deep linking)
103+ if ( urlState . step ) return
90104
91- if ( ! isUserKycVerified ) {
92- setStep ( 'collectUserDetails' )
93- } else {
94- setStep ( 'inputAmount' )
95- if ( amountFromContext && ! rawTokenAmount ) {
96- setRawTokenAmount ( amountFromContext )
97- }
98- }
105+ // Wait for user to be fetched before determining initial step
106+ if ( user === null ) return
107+
108+ const currentKycStatus = liveKycStatus || user ?. user . bridgeKycStatus
109+ const isUserKycVerified = currentKycStatus === 'approved'
110+
111+ if ( ! isUserKycVerified ) {
112+ setUrlState ( { step : 'collectUserDetails' } )
113+ } else {
114+ setUrlState ( { step : 'inputAmount' } )
99115 }
100- } , [ liveKycStatus , user , step , amountFromContext , rawTokenAmount ] )
116+ } , [ liveKycStatus , user , urlState . step , setUrlState ] )
101117
102118 // Handle KYC completion
103119 useEffect ( ( ) => {
104- if ( step === 'kyc' && liveKycStatus === 'approved' ) {
105- setStep ( 'inputAmount' )
106- if ( amountFromContext && ! rawTokenAmount ) {
107- setRawTokenAmount ( amountFromContext )
108- }
120+ if ( urlState . step === 'kyc' && liveKycStatus === 'approved' ) {
121+ setUrlState ( { step : 'inputAmount' } )
109122 }
110- } , [ liveKycStatus , step , amountFromContext , rawTokenAmount ] )
123+ } , [ liveKycStatus , urlState . step , setUrlState ] )
111124
112125 const validateAmount = useCallback (
113126 ( amountStr : string ) : boolean => {
@@ -130,22 +143,23 @@ export default function OnrampBankPage() {
130143 [ setError , minimumAmount ]
131144 )
132145
146+ // Handle amount change - sync to URL state
133147 const handleTokenAmountChange = useCallback (
134148 ( value : string | undefined ) => {
135- setRawTokenAmount ( value || '' )
149+ const newAmount = value || null // null removes from URL
150+ setUrlState ( { amount : newAmount } )
136151 } ,
137- [ setRawTokenAmount ]
152+ [ setUrlState ]
138153 )
139154
155+ // Validate amount when it changes
140156 useEffect ( ( ) => {
141157 if ( rawTokenAmount === '' ) {
142- if ( ! amountFromContext ) {
143- setError ( { showError : false , errorMessage : '' } )
144- }
158+ setError ( { showError : false , errorMessage : '' } )
145159 } else {
146160 validateAmount ( rawTokenAmount )
147161 }
148- } , [ rawTokenAmount , validateAmount , setError , amountFromContext ] )
162+ } , [ rawTokenAmount , validateAmount , setError ] )
149163
150164 const handleAmountContinue = ( ) => {
151165 if ( validateAmount ( rawTokenAmount ) ) {
@@ -161,7 +175,6 @@ export default function OnrampBankPage() {
161175 } )
162176 return
163177 }
164- setAmountToOnramp ( rawTokenAmount )
165178 setShowWarningModal ( false )
166179 setIsRiskAccepted ( false )
167180 try {
@@ -172,7 +185,7 @@ export default function OnrampBankPage() {
172185 setOnrampData ( onrampDataResponse )
173186
174187 if ( onrampDataResponse . transferId ) {
175- setStep ( 'showDetails' )
188+ setUrlState ( { step : 'showDetails' } )
176189 } else {
177190 setError ( {
178191 showError : true ,
@@ -195,13 +208,9 @@ export default function OnrampBankPage() {
195208 setIsRiskAccepted ( false )
196209 }
197210
198- const handleKycModalOpen = ( ) => {
199- setIsKycModalOpen ( true )
200- }
201-
202211 const handleKycSuccess = ( ) => {
203212 setIsKycModalOpen ( false )
204- setStep ( 'inputAmount' )
213+ setUrlState ( { step : 'inputAmount' } )
205214 }
206215
207216 const handleKycModalClose = ( ) => {
@@ -222,7 +231,7 @@ export default function OnrampBankPage() {
222231 throw new Error ( result . error )
223232 }
224233 await fetchUser ( )
225- setStep ( 'kyc' )
234+ setUrlState ( { step : 'kyc' } )
226235 } catch ( error : any ) {
227236 setUserUpdateError ( error . message )
228237 return { error : error . message }
@@ -240,24 +249,29 @@ export default function OnrampBankPage() {
240249 }
241250 }
242251
243- const [ firstName , ...lastNameParts ] = ( user ?. user . fullName ?? '' ) . split ( ' ' )
244- const lastName = lastNameParts . join ( ' ' )
245-
246252 const initialUserDetails : Partial < UserDetailsFormData > = useMemo (
247253 ( ) => ( {
248254 fullName : user ?. user . fullName ?? '' ,
249255 email : user ?. user . email ?? '' ,
250256 } ) ,
251- [ user ?. user . fullName , user ?. user . email , firstName , lastName ]
257+ [ user ?. user . fullName , user ?. user . email ]
252258 )
253259
254260 useEffect ( ( ) => {
255- if ( step === 'kyc' ) {
261+ if ( urlState . step === 'kyc' ) {
256262 setIsKycModalOpen ( true )
257263 }
258- } , [ step ] )
264+ } , [ urlState . step ] )
259265
260- if ( step === 'loading' ) {
266+ // Redirect to inputAmount if showDetails is accessed without required data (deep link / back navigation)
267+ useEffect ( ( ) => {
268+ if ( urlState . step === 'showDetails' && ! onrampData ?. transferId ) {
269+ setUrlState ( { step : 'inputAmount' } )
270+ }
271+ } , [ urlState . step , onrampData ?. transferId , setUrlState ] )
272+
273+ // Show loading while user is being fetched and no step in URL yet
274+ if ( ! urlState . step && user === null ) {
261275 return < PeanutLoading />
262276 }
263277
@@ -270,7 +284,12 @@ export default function OnrampBankPage() {
270284 )
271285 }
272286
273- if ( step === 'collectUserDetails' ) {
287+ // Still determining initial step
288+ if ( ! urlState . step ) {
289+ return < PeanutLoading />
290+ }
291+
292+ if ( urlState . step === 'collectUserDetails' ) {
274293 return (
275294 < div className = "flex flex-col justify-start space-y-8" >
276295 < NavHeader onPrev = { handleBack } title = "Identity Verification" />
@@ -299,7 +318,7 @@ export default function OnrampBankPage() {
299318 )
300319 }
301320
302- if ( step === 'kyc' ) {
321+ if ( urlState . step === 'kyc' ) {
303322 return (
304323 < div className = "flex flex-col justify-start space-y-8" >
305324 < InitiateBridgeKYCModal
@@ -313,11 +332,15 @@ export default function OnrampBankPage() {
313332 )
314333 }
315334
316- if ( step === 'showDetails' ) {
335+ if ( urlState . step === 'showDetails' ) {
336+ // Show loading while useEffect redirects if data is missing
337+ if ( ! onrampData ?. transferId ) {
338+ return < PeanutLoading />
339+ }
317340 return < AddMoneyBankDetails />
318341 }
319342
320- if ( step === 'inputAmount' ) {
343+ if ( urlState . step === 'inputAmount' ) {
321344 return (
322345 < div className = "flex flex-col justify-start space-y-8" >
323346 < NavHeader title = "Add Money" onPrev = { handleBack } />
0 commit comments