From 46935f010d289d18a21fb304cf2bde53cbd91c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Ram=C3=ADrez?= Date: Wed, 18 Mar 2026 15:36:14 -0300 Subject: [PATCH 1/2] fix: redirect to onboarding when manteca reports missing fund origin - Detect onboarding-incomplete errors (fund origin, profile incomplete) - Auto-generate onboarding URL and redirect user to complete their profile - Return URL set to current page so user lands back in withdraw flow - Fallback message if onboarding URL generation fails --- src/app/(mobile-ui)/withdraw/manteca/page.tsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/app/(mobile-ui)/withdraw/manteca/page.tsx b/src/app/(mobile-ui)/withdraw/manteca/page.tsx index baac44283..aa6141afa 100644 --- a/src/app/(mobile-ui)/withdraw/manteca/page.tsx +++ b/src/app/(mobile-ui)/withdraw/manteca/page.tsx @@ -94,6 +94,7 @@ export default function MantecaWithdrawFlow() { // intent is passed at call time: handleInitiateKyc('LATAM') const sumsubFlow = useMultiPhaseKycFlow({}) const [showKycModal, setShowKycModal] = useState(false) + const [isRedirectingToOnboarding, setIsRedirectingToOnboarding] = useState(false) // Get method and country from URL parameters const selectedMethodType = searchParams.get('method') // mercadopago, pix, bank-transfer, etc. const countryFromUrl = searchParams.get('country') // argentina, brazil, etc. @@ -174,6 +175,28 @@ export default function MantecaWithdrawFlow() { return isValid } + /** + * Detect Manteca onboarding-incomplete errors and redirect user to complete their profile. + * Returns true if the error was handled (caller should return early). + */ + const handleOnboardingError = useCallback(async (error: string): Promise => { + const onboardingErrors = ['fund origin', 'onboarding', 'profile incomplete'] + const isOnboardingError = onboardingErrors.some((keyword) => error.toLowerCase().includes(keyword)) + if (!isOnboardingError) return false + + setIsRedirectingToOnboarding(true) + try { + const result = await mantecaApi.initiateOnboarding({ + returnUrl: window.location.href, + }) + window.location.href = result.url + } catch { + setErrorMessage('Please complete your account setup. Go to Settings to update your profile.') + setIsRedirectingToOnboarding(false) + } + return true + }, []) + const isCompleteBankDetails = useMemo(() => { return ( !!destinationAddress.trim() && @@ -213,6 +236,7 @@ export default function MantecaWithdrawFlow() { }) if (result.error) { + if (await handleOnboardingError(result.error)) return setErrorMessage(result.error) return } @@ -301,6 +325,8 @@ export default function MantecaWithdrawFlow() { }) if (result.error) { + // handle onboarding-incomplete errors by redirecting to complete profile + if (await handleOnboardingError(result.error)) return // handle third-party account error with user-friendly message if (result.error === 'TAX_ID_MISMATCH' || result.error === 'CUIT_MISMATCH') { setErrorMessage('You can only withdraw to accounts under your name.') From 5997aca15aad735544ee1e8d14b4d13e7e2706f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Ram=C3=ADrez?= Date: Wed, 18 Mar 2026 15:49:06 -0300 Subject: [PATCH 2/2] fix: address review feedback on onboarding error handling - Tighten error matching (remove broad 'onboarding', use 'onboarding required') - Add handleOnboardingError to useCallback deps - Wire isRedirectingToOnboarding into button (disabled + loading + 'Redirecting...') - Check result.message in withdraw path for onboarding errors --- src/app/(mobile-ui)/withdraw/manteca/page.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/app/(mobile-ui)/withdraw/manteca/page.tsx b/src/app/(mobile-ui)/withdraw/manteca/page.tsx index 969d8cb97..85e17af0a 100644 --- a/src/app/(mobile-ui)/withdraw/manteca/page.tsx +++ b/src/app/(mobile-ui)/withdraw/manteca/page.tsx @@ -182,8 +182,9 @@ export default function MantecaWithdrawFlow() { * Returns true if the error was handled (caller should return early). */ const handleOnboardingError = useCallback(async (error: string): Promise => { - const onboardingErrors = ['fund origin', 'onboarding', 'profile incomplete'] - const isOnboardingError = onboardingErrors.some((keyword) => error.toLowerCase().includes(keyword)) + const onboardingErrorPatterns = ['fund origin', 'profile incomplete', 'onboarding required'] + const normalizedError = error.toLowerCase() + const isOnboardingError = onboardingErrorPatterns.some((pattern) => normalizedError.includes(pattern)) if (!isOnboardingError) return false setIsRedirectingToOnboarding(true) @@ -268,6 +269,7 @@ export default function MantecaWithdrawFlow() { currencyAmount, isUserMantecaKycApproved, isLockingPrice, + handleOnboardingError, ]) const handleWithdraw = async () => { @@ -339,7 +341,7 @@ export default function MantecaWithdrawFlow() { }) // handle onboarding-incomplete errors by redirecting to complete profile - if (await handleOnboardingError(result.error)) return + if (await handleOnboardingError(result.message ?? result.error)) return // handle third-party account error with user-friendly message if (result.error === 'TAX_ID_MISMATCH' || result.error === 'CUIT_MISMATCH') { @@ -691,13 +693,18 @@ export default function MantecaWithdrawFlow() { !isCompleteBankDetails || isDestinationAddressChanging || !isDestinationAddressValid || - isLockingPrice + isLockingPrice || + isRedirectingToOnboarding } - loading={isDestinationAddressChanging || isLockingPrice} + loading={isDestinationAddressChanging || isLockingPrice || isRedirectingToOnboarding} className="w-full" shadowSize="4" > - {isLockingPrice ? 'Locking rate...' : 'Review'} + {isRedirectingToOnboarding + ? 'Redirecting...' + : isLockingPrice + ? 'Locking rate...' + : 'Review'} {errorMessage && }