@@ -9,33 +9,32 @@ import { useOnrampFlow } from '@/context/OnrampFlowContext'
99import { useWallet } from '@/hooks/wallet/useWallet'
1010import { formatAmount } from '@/utils/general.utils'
1111import { countryData } from '@/components/AddMoney/consts'
12- import { type BridgeKycStatus } from '@/utils/bridge-accounts.utils'
13- import { useWebSocket } from '@/hooks/useWebSocket'
1412import { useAuth } from '@/context/authContext'
13+ import useKycStatus from '@/hooks/useKycStatus'
1514import { useCreateOnramp } from '@/hooks/useCreateOnramp'
1615import { useRouter , useParams } from 'next/navigation'
17- import { useCallback , useEffect , useMemo , useRef , useState } from 'react'
16+ import { useCallback , useEffect , useMemo , useState } from 'react'
1817import countryCurrencyMappings , { isNonEuroSepaCountry , isUKCountry } from '@/constants/countryCurrencyMapping'
1918import { formatUnits } from 'viem'
2019import PeanutLoading from '@/components/Global/PeanutLoading'
2120import EmptyState from '@/components/Global/EmptyStates/EmptyState'
22- import { UserDetailsForm , type UserDetailsFormData } from '@/components/AddMoney/UserDetailsForm'
23- import { updateUserById } from '@/app/actions/users'
2421import AddMoneyBankDetails from '@/components/AddMoney/components/AddMoneyBankDetails'
2522import { getCurrencyConfig , getCurrencySymbol , getMinimumAmount } from '@/utils/bridge.utils'
2623import { OnrampConfirmationModal } from '@/components/AddMoney/components/OnrampConfirmationModal'
27- import { InitiateBridgeKYCModal } from '@/components/Kyc/InitiateBridgeKYCModal'
2824import InfoCard from '@/components/Global/InfoCard'
2925import { useQueryStates , parseAsString , parseAsStringEnum } from 'nuqs'
3026import { useLimitsValidation } from '@/features/limits/hooks/useLimitsValidation'
3127import LimitsWarningCard from '@/features/limits/components/LimitsWarningCard'
3228import { getLimitsWarningCardProps } from '@/features/limits/utils'
3329import { useExchangeRate } from '@/hooks/useExchangeRate'
30+ import { useMultiPhaseKycFlow } from '@/hooks/useMultiPhaseKycFlow'
31+ import { SumsubKycModals } from '@/components/Kyc/SumsubKycModals'
32+ import { InitiateKycModal } from '@/components/Kyc/InitiateKycModal'
3433import posthog from 'posthog-js'
3534import { ANALYTICS_EVENTS } from '@/constants/analytics.consts'
3635
3736// Step type for URL state
38- type BridgeBankStep = 'inputAmount' | 'kyc' | 'collectUserDetails' | ' showDetails'
37+ type BridgeBankStep = 'inputAmount' | 'showDetails'
3938
4039export default function OnrampBankPage ( ) {
4140 const router = useRouter ( )
@@ -45,7 +44,7 @@ export default function OnrampBankPage() {
4544 // Example: /add-money/mexico/bank?step=inputAmount&amount=500
4645 const [ urlState , setUrlState ] = useQueryStates (
4746 {
48- step : parseAsStringEnum < BridgeBankStep > ( [ 'inputAmount' , 'kyc' , 'collectUserDetails' , ' showDetails'] ) ,
47+ step : parseAsStringEnum < BridgeBankStep > ( [ 'inputAmount' , 'showDetails' ] ) ,
4948 amount : parseAsString ,
5049 } ,
5150 { history : 'push' }
@@ -56,20 +55,23 @@ export default function OnrampBankPage() {
5655
5756 // Local UI state (not URL-appropriate - transient)
5857 const [ showWarningModal , setShowWarningModal ] = useState < boolean > ( false )
58+ const [ showKycModal , setShowKycModal ] = useState < boolean > ( false )
5959 const [ isRiskAccepted , setIsRiskAccepted ] = useState < boolean > ( false )
60- const [ isKycModalOpen , setIsKycModalOpen ] = useState ( false )
61- const [ liveKycStatus , setLiveKycStatus ] = useState < BridgeKycStatus | undefined > ( undefined )
62- const [ isUpdatingUser , setIsUpdatingUser ] = useState ( false )
63- const [ userUpdateError , setUserUpdateError ] = useState < string | null > ( null )
64- const [ isUserDetailsFormValid , setIsUserDetailsFormValid ] = useState ( false )
65-
6660 const { setError, error, setOnrampData, onrampData } = useOnrampFlow ( )
67- const formRef = useRef < { handleSubmit : ( ) => void } > ( null )
6861
6962 const { balance } = useWallet ( )
7063 const { user, fetchUser } = useAuth ( )
7164 const { createOnramp, isLoading : isCreatingOnramp , error : onrampError } = useCreateOnramp ( )
7265
66+ // inline sumsub kyc flow for bridge bank onramp
67+ // regionIntent is NOT passed here to avoid creating a backend record on mount.
68+ // intent is passed at call time: handleInitiateKyc('STANDARD')
69+ const sumsubFlow = useMultiPhaseKycFlow ( {
70+ onKycSuccess : ( ) => {
71+ setUrlState ( { step : 'inputAmount' } )
72+ } ,
73+ } )
74+
7375 const selectedCountryPath = params . country as string
7476
7577 const selectedCountry = useMemo ( ( ) => {
@@ -89,19 +91,7 @@ export default function OnrampBankPage() {
8991 // uk-specific check
9092 const isUK = isUKCountry ( selectedCountryPath )
9193
92- useWebSocket ( {
93- username : user ?. user . username ?? undefined ,
94- autoConnect : ! ! user ?. user . username ,
95- onKycStatusUpdate : ( newStatus ) => {
96- setLiveKycStatus ( newStatus as BridgeKycStatus )
97- } ,
98- } )
99-
100- useEffect ( ( ) => {
101- if ( user ?. user . bridgeKycStatus ) {
102- setLiveKycStatus ( user . user . bridgeKycStatus as BridgeKycStatus )
103- }
104- } , [ user ?. user . bridgeKycStatus ] )
94+ const { isUserKycApproved } = useKycStatus ( )
10595
10696 useEffect ( ( ) => {
10797 fetchUser ( )
@@ -152,30 +142,12 @@ export default function OnrampBankPage() {
152142 currency : 'USD' ,
153143 } )
154144
155- // Determine initial step based on KYC status (only when URL has no step)
145+ // Default to inputAmount step when no step in URL
156146 useEffect ( ( ) => {
157- // If URL already has a step, respect it (allows deep linking)
158147 if ( urlState . step ) return
159-
160- // Wait for user to be fetched before determining initial step
161148 if ( user === null ) return
162-
163- const currentKycStatus = liveKycStatus || user ?. user . bridgeKycStatus
164- const isUserKycVerified = currentKycStatus === 'approved'
165-
166- if ( ! isUserKycVerified ) {
167- setUrlState ( { step : 'collectUserDetails' } )
168- } else {
169- setUrlState ( { step : 'inputAmount' } )
170- }
171- } , [ liveKycStatus , user , urlState . step , setUrlState ] )
172-
173- // Handle KYC completion
174- useEffect ( ( ) => {
175- if ( urlState . step === 'kyc' && liveKycStatus === 'approved' ) {
176- setUrlState ( { step : 'inputAmount' } )
177- }
178- } , [ liveKycStatus , urlState . step , setUrlState ] )
149+ setUrlState ( { step : 'inputAmount' } )
150+ } , [ user , urlState . step , setUrlState ] )
179151
180152 const validateAmount = useCallback (
181153 ( amountStr : string ) : boolean => {
@@ -217,14 +189,19 @@ export default function OnrampBankPage() {
217189 } , [ rawTokenAmount , validateAmount , setError ] )
218190
219191 const handleAmountContinue = ( ) => {
220- if ( validateAmount ( rawTokenAmount ) ) {
221- posthog . capture ( ANALYTICS_EVENTS . DEPOSIT_AMOUNT_ENTERED , {
222- amount_usd : usdEquivalent ,
223- method_type : 'bank' ,
224- country : selectedCountryPath ,
225- } )
226- setShowWarningModal ( true )
192+ if ( ! validateAmount ( rawTokenAmount ) ) return
193+
194+ if ( ! isUserKycApproved ) {
195+ setShowKycModal ( true )
196+ return
227197 }
198+
199+ posthog . capture ( ANALYTICS_EVENTS . DEPOSIT_AMOUNT_ENTERED , {
200+ amount_usd : usdEquivalent ,
201+ method_type : 'bank' ,
202+ country : selectedCountryPath ,
203+ } )
204+ setShowWarningModal ( true )
228205 }
229206
230207 const handleWarningConfirm = async ( ) => {
@@ -278,39 +255,6 @@ export default function OnrampBankPage() {
278255 setIsRiskAccepted ( false )
279256 }
280257
281- const handleKycSuccess = ( ) => {
282- setIsKycModalOpen ( false )
283- setUrlState ( { step : 'inputAmount' } )
284- }
285-
286- const handleKycModalClose = ( ) => {
287- setIsKycModalOpen ( false )
288- }
289-
290- const handleUserDetailsSubmit = async ( data : UserDetailsFormData ) => {
291- setIsUpdatingUser ( true )
292- setUserUpdateError ( null )
293- try {
294- if ( ! user ?. user . userId ) throw new Error ( 'User not found' )
295- const result = await updateUserById ( {
296- userId : user . user . userId ,
297- fullName : data . fullName ,
298- email : data . email ,
299- } )
300- if ( result . error ) {
301- throw new Error ( result . error )
302- }
303- await fetchUser ( )
304- setUrlState ( { step : 'kyc' } )
305- } catch ( error : any ) {
306- setUserUpdateError ( error . message )
307- return { error : error . message }
308- } finally {
309- setIsUpdatingUser ( false )
310- }
311- return { }
312- }
313-
314258 const handleBack = ( ) => {
315259 if ( selectedCountry ) {
316260 router . push ( `/add-money/${ selectedCountry . path } ` )
@@ -319,20 +263,6 @@ export default function OnrampBankPage() {
319263 }
320264 }
321265
322- const initialUserDetails : Partial < UserDetailsFormData > = useMemo (
323- ( ) => ( {
324- fullName : user ?. user . fullName ?? '' ,
325- email : user ?. user . email ?? '' ,
326- } ) ,
327- [ user ?. user . fullName , user ?. user . email ]
328- )
329-
330- useEffect ( ( ) => {
331- if ( urlState . step === 'kyc' ) {
332- setIsKycModalOpen ( true )
333- }
334- } , [ urlState . step ] )
335-
336266 // Redirect to inputAmount if showDetails is accessed without required data (deep link / back navigation)
337267 useEffect ( ( ) => {
338268 if ( urlState . step === 'showDetails' && ! onrampData ?. transferId ) {
@@ -359,49 +289,6 @@ export default function OnrampBankPage() {
359289 return < PeanutLoading />
360290 }
361291
362- if ( urlState . step === 'collectUserDetails' ) {
363- return (
364- < div className = "flex flex-col justify-start space-y-8" >
365- < NavHeader onPrev = { handleBack } title = "Identity Verification" />
366- < div className = "flex flex-grow flex-col justify-center space-y-4" >
367- < h3 className = "text-sm font-bold" > Verify your details</ h3 >
368- < UserDetailsForm
369- ref = { formRef }
370- onSubmit = { handleUserDetailsSubmit }
371- isSubmitting = { isUpdatingUser }
372- onValidChange = { setIsUserDetailsFormValid }
373- initialData = { initialUserDetails }
374- />
375- < Button
376- onClick = { ( ) => formRef . current ?. handleSubmit ( ) }
377- loading = { isUpdatingUser }
378- variant = "purple"
379- shadowSize = "4"
380- className = "w-full"
381- disabled = { ! isUserDetailsFormValid || isUpdatingUser }
382- >
383- Continue
384- </ Button >
385- { userUpdateError && < ErrorAlert description = { userUpdateError } /> }
386- </ div >
387- </ div >
388- )
389- }
390-
391- if ( urlState . step === 'kyc' ) {
392- return (
393- < div className = "flex flex-col justify-start space-y-8" >
394- < InitiateBridgeKYCModal
395- isOpen = { isKycModalOpen }
396- onClose = { handleKycModalClose }
397- onKycSuccess = { handleKycSuccess }
398- onManualClose = { ( ) => router . push ( `/add-money/${ selectedCountry . path } ` ) }
399- flow = "add"
400- />
401- </ div >
402- )
403- }
404-
405292 if ( urlState . step === 'showDetails' ) {
406293 // Show loading while useEffect redirects if data is missing
407294 if ( ! onrampData ?. transferId ) {
@@ -494,6 +381,18 @@ export default function OnrampBankPage() {
494381 amount = { rawTokenAmount }
495382 currency = { getCurrencySymbol ( getCurrencyConfig ( selectedCountry . id , 'onramp' ) . currency ) }
496383 />
384+
385+ < InitiateKycModal
386+ visible = { showKycModal }
387+ onClose = { ( ) => setShowKycModal ( false ) }
388+ onVerify = { async ( ) => {
389+ await sumsubFlow . handleInitiateKyc ( 'STANDARD' )
390+ setShowKycModal ( false )
391+ } }
392+ isLoading = { sumsubFlow . isLoading }
393+ />
394+
395+ < SumsubKycModals flow = { sumsubFlow } autoStartSdk />
497396 </ div >
498397 )
499398 }
0 commit comments