From 1d5109f96dbcd14533ad1cff1a5be8b5831bbc3b Mon Sep 17 00:00:00 2001 From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com> Date: Mon, 11 May 2026 14:46:19 +0530 Subject: [PATCH 1/6] fix: prevent translation extension crashes across all browsers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the old mutation observer only handled google translate's data-translated attribute. brave translate, safari, and others use different DOM manipulation that was never caught, causing removeChild crashes during react reconciliation. patches Node.prototype.removeChild and insertBefore to gracefully handle nodes moved by any translation extension — the standard react ecosystem fix (facebook/react#11538). --- .../Global/TranslationSafeWrapper.tsx | 16 +--- src/hooks/useTranslationMutationHandler.ts | 81 +++++-------------- 2 files changed, 25 insertions(+), 72 deletions(-) diff --git a/src/components/Global/TranslationSafeWrapper.tsx b/src/components/Global/TranslationSafeWrapper.tsx index 4e77af618..d05006cdd 100644 --- a/src/components/Global/TranslationSafeWrapper.tsx +++ b/src/components/Global/TranslationSafeWrapper.tsx @@ -1,18 +1,8 @@ 'use client' import { useTranslationMutationHandler } from '@/hooks/useTranslationMutationHandler' -import { useRef } from 'react' -// wraps the app to handle google translate dom mutations globally -// prevents "Failed to execute 'insertBefore' on 'Node'" errors -// while still allowing translations to work properly +// patches dom methods globally to prevent translation extension crashes export const TranslationSafeWrapper = ({ children }: { children: React.ReactNode }) => { - const wrapperRef = useRef(null) - // attach mutation observer to handle translation service dom changes - useTranslationMutationHandler(wrapperRef) - - return ( -
- {children} -
- ) + useTranslationMutationHandler() + return <>{children} } diff --git a/src/hooks/useTranslationMutationHandler.ts b/src/hooks/useTranslationMutationHandler.ts index e079660b0..b8062fc9f 100644 --- a/src/hooks/useTranslationMutationHandler.ts +++ b/src/hooks/useTranslationMutationHandler.ts @@ -1,67 +1,30 @@ -import { useEffect, useRef } from 'react' +import { useEffect } from 'react' -// handles translation service dom mutations to prevent errors while allowing translations -export const useTranslationMutationHandler = (targetRef: React.RefObject) => { - // keep reference to observer instance for cleanup - const observerRef = useRef(null) +let patched = false +// patches removeChild and insertBefore to prevent crashes when browser +// translation extensions (google translate, brave translate, etc) move +// dom nodes out of their react-managed parents. without this, react's +// reconciliation throws "not a child of this node" during unmount/update. +export const useTranslationMutationHandler = () => { useEffect(() => { - const setupObserver = () => { - if (!targetRef.current) return + if (patched) return + patched = true - if (observerRef.current) { - observerRef.current.disconnect() + const originalRemoveChild = Node.prototype.removeChild + Node.prototype.removeChild = function (child: T): T { + if (child.parentNode !== this) { + return child } - - observerRef.current = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if (mutation.type === 'childList') { - mutation.addedNodes.forEach((node) => { - if (node.nodeType === 1) { - try { - const element = node as Element - // handle translated content nodes that google translate adds - if (element.hasAttribute('data-translated')) { - const parent = element.parentElement - if (parent) { - // remove any duplicate translations to prevent conflicts - const existingTranslations = parent.querySelectorAll('[data-translated]') - existingTranslations.forEach((el) => { - if (el !== element && el.textContent === element.textContent) { - el.remove() - } - }) - - // append new translation if not already present - if (!parent.contains(element)) { - requestAnimationFrame(() => { - try { - parent.appendChild(element) - } catch (e) { - console.error(e) - } - }) - } - } - } - } catch (e) { - console.error(e) - } - } - }) - } - }) - }) - - // observe changes to dom structure and attributes - observerRef.current.observe(targetRef.current, { - childList: true, - subtree: true, - attributes: true, - }) + return originalRemoveChild.call(this, child) as T } - setupObserver() - return () => observerRef.current?.disconnect() - }, [targetRef]) + const originalInsertBefore = Node.prototype.insertBefore + Node.prototype.insertBefore = function (newNode: T, refNode: Node | null): T { + if (refNode && refNode.parentNode !== this) { + return newNode + } + return originalInsertBefore.call(this, newNode, refNode) as T + } + }, []) } From 49e3d844c26984baea9de816dab6063d351c7198 Mon Sep 17 00:00:00 2001 From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com> Date: Mon, 11 May 2026 19:28:59 +0530 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20address=20review=20=E2=80=94=20windo?= =?UTF-8?q?w=20global=20for=20HMR,=20dev-mode=20logging,=20no-cleanup=20co?= =?UTF-8?q?mment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useTranslationMutationHandler.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hooks/useTranslationMutationHandler.ts b/src/hooks/useTranslationMutationHandler.ts index b8062fc9f..2d7bc525e 100644 --- a/src/hooks/useTranslationMutationHandler.ts +++ b/src/hooks/useTranslationMutationHandler.ts @@ -1,19 +1,27 @@ import { useEffect } from 'react' -let patched = false +const PATCH_KEY = '__peanut_translation_patched__' // patches removeChild and insertBefore to prevent crashes when browser // translation extensions (google translate, brave translate, etc) move // dom nodes out of their react-managed parents. without this, react's // reconciliation throws "not a child of this node" during unmount/update. +// +// intentionally no useEffect cleanup — patches are permanent for the page +// lifetime. removing them on unmount would re-expose the crash. export const useTranslationMutationHandler = () => { useEffect(() => { - if (patched) return - patched = true + // window global survives HMR — module-scoped flag resets on hot reload, + // which would nest patched wrappers around each other + if ((window as any)[PATCH_KEY]) return + ;(window as any)[PATCH_KEY] = true const originalRemoveChild = Node.prototype.removeChild Node.prototype.removeChild = function (child: T): T { if (child.parentNode !== this) { + if (process.env.NODE_ENV !== 'production') { + console.warn('[translation-patch] removeChild: node is not a child, skipping', child) + } return child } return originalRemoveChild.call(this, child) as T @@ -22,6 +30,9 @@ export const useTranslationMutationHandler = () => { const originalInsertBefore = Node.prototype.insertBefore Node.prototype.insertBefore = function (newNode: T, refNode: Node | null): T { if (refNode && refNode.parentNode !== this) { + if (process.env.NODE_ENV !== 'production') { + console.warn('[translation-patch] insertBefore: ref node is not a child, skipping', refNode) + } return newNode } return originalInsertBefore.call(this, newNode, refNode) as T From de346a8740d7d4b8fbde12577aae7ec00f7f4cf8 Mon Sep 17 00:00:00 2001 From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com> Date: Tue, 12 May 2026 14:09:02 +0530 Subject: [PATCH 3/6] fix: gate manteca kyc by selected country --- src/app/(mobile-ui)/withdraw/manteca/page.tsx | 13 +++++++------ src/app/actions/sumsub.ts | 2 ++ .../AddMoney/components/MantecaAddMoney.tsx | 14 +++++++------- src/hooks/useMultiPhaseKycFlow.ts | 4 ++-- src/hooks/useSumsubKycFlow.ts | 3 ++- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/app/(mobile-ui)/withdraw/manteca/page.tsx b/src/app/(mobile-ui)/withdraw/manteca/page.tsx index c8448eaaa..62097d8a9 100644 --- a/src/app/(mobile-ui)/withdraw/manteca/page.tsx +++ b/src/app/(mobile-ui)/withdraw/manteca/page.tsx @@ -27,7 +27,6 @@ import ValidatedInput from '@/components/Global/ValidatedInput' import AmountInput from '@/components/Global/AmountInput' import { formatUnits, parseUnits } from 'viem' import { PaymentInfoRow } from '@/components/Payment/PaymentInfoRow' -import { useAuth } from '@/context/authContext' import { useModalsContext } from '@/context/ModalsContext' import Select from '@/components/Global/Select' import { SoundPlayer } from '@/components/Global/SoundPlayer' @@ -61,6 +60,7 @@ import { useSumsubActionFlow } from '@/hooks/useSumsubActionFlow' import { initiateIncreaseLimits } from '@/app/actions/increase-limits' import { SumsubKycWrapper } from '@/components/Kyc/SumsubKycWrapper' import { useLimits } from '@/hooks/useLimits' +import { useIdentityVerification } from '@/hooks/useIdentityVerification' type MantecaWithdrawStep = 'amountInput' | 'bankDetails' | 'review' | 'success' | 'failure' @@ -88,10 +88,10 @@ export default function MantecaWithdrawFlow() { const { sendMoney, balance } = useWallet() const { signTransferUserOp } = useSignUserOp() const { isLoading, loadingState, setLoadingState } = useContext(loadingStateContext) - const { user } = useAuth() const { setIsSupportModalOpen, openSupportWithMessage } = useModalsContext() const queryClient = useQueryClient() - const { isUserMantecaKycApproved, isUserSumsubKycApproved } = useKycStatus() + const { isUserSumsubKycApproved } = useKycStatus() + const { isVerifiedForCountry } = useIdentityVerification() const { manteca: mantecaRejection } = useProviderRejectionStatus() const { hasPendingTransactions } = usePendingTransactions() @@ -118,6 +118,7 @@ export default function MantecaWithdrawFlow() { if (!selectedCountry) return undefined return MANTECA_COUNTRIES_CONFIG[selectedCountry.id] }, [selectedCountry]) + const isUserMantecaKycApprovedForCountry = selectedCountry ? isVerifiedForCountry(selectedCountry.id) : false const { code: currencyCode, @@ -236,7 +237,7 @@ export default function MantecaWithdrawFlow() { } setErrorMessage(null) - if (!isUserMantecaKycApproved) { + if (!isUserMantecaKycApprovedForCountry) { setShowKycModal(true) return } @@ -281,7 +282,7 @@ export default function MantecaWithdrawFlow() { usdAmount, currencyCode, currencyAmount, - isUserMantecaKycApproved, + isUserMantecaKycApprovedForCountry, isLockingPrice, handleOnboardingError, ]) @@ -537,7 +538,7 @@ export default function MantecaWithdrawFlow() { if (hasRejection) { await sumsubFlow.handleSelfHealResubmit('MANTECA') } else { - await sumsubFlow.handleInitiateKyc('LATAM', undefined, true) + await sumsubFlow.handleInitiateKyc('LATAM', undefined, true, selectedCountry.id) } setShowKycModal(false) }} diff --git a/src/app/actions/sumsub.ts b/src/app/actions/sumsub.ts index 8cb387990..dfb857d99 100644 --- a/src/app/actions/sumsub.ts +++ b/src/app/actions/sumsub.ts @@ -12,6 +12,7 @@ export const initiateSumsubKyc = async (params?: { regionIntent?: KYCRegionIntent levelName?: string crossRegion?: boolean + targetCountry?: string }): Promise<{ data?: InitiateSumsubKycResponse; error?: string }> => { const jwtToken = (await getJWTCookie())?.value @@ -23,6 +24,7 @@ export const initiateSumsubKyc = async (params?: { regionIntent: params?.regionIntent, levelName: params?.levelName, crossRegion: params?.crossRegion, + targetCountry: params?.targetCountry, } try { diff --git a/src/components/AddMoney/components/MantecaAddMoney.tsx b/src/components/AddMoney/components/MantecaAddMoney.tsx index ac03ac285..3a1fba424 100644 --- a/src/components/AddMoney/components/MantecaAddMoney.tsx +++ b/src/components/AddMoney/components/MantecaAddMoney.tsx @@ -6,7 +6,6 @@ import { useParams } from 'next/navigation' import { type CountryData, countryData } from '@/components/AddMoney/consts' import { type MantecaDepositResponseData } from '@/types/manteca.types' import { useCurrency } from '@/hooks/useCurrency' -import { useAuth } from '@/context/authContext' import { mantecaApi } from '@/services/manteca' import { parseUnits } from 'viem' import { useQueryClient } from '@tanstack/react-query' @@ -22,6 +21,7 @@ import { useQueryStates, parseAsString, parseAsStringEnum } from 'nuqs' import { useLimitsValidation } from '@/features/limits/hooks/useLimitsValidation' import posthog from 'posthog-js' import { ANALYTICS_EVENTS } from '@/constants/analytics.consts' +import { useIdentityVerification } from '@/hooks/useIdentityVerification' // Step type for URL state type MantecaStep = 'inputAmount' | 'depositDetails' @@ -64,16 +64,16 @@ const MantecaAddMoney: FC = () => { const selectedCountry = useMemo(() => { return countryData.find((country) => country.type === 'country' && country.path === selectedCountryPath) }, [selectedCountryPath]) - const { isUserMantecaKycApproved, isUserSumsubKycApproved } = useKycStatus() + const { isUserSumsubKycApproved } = useKycStatus() + const { isVerifiedForCountry } = useIdentityVerification() const { manteca: mantecaRejection } = useProviderRejectionStatus() const currencyData = useCurrency(selectedCountry?.currency ?? 'ARS') - const { user } = useAuth() - // inline sumsub kyc flow for manteca users who need LATAM verification // regionIntent is NOT passed here to avoid creating a backend record on mount. // intent is passed at call time: handleInitiateKyc('LATAM') const sumsubFlow = useMultiPhaseKycFlow({}) const [showKycModal, setShowKycModal] = useState(false) + const isUserMantecaKycApprovedForCountry = selectedCountry ? isVerifiedForCountry(selectedCountry.id) : false // validates deposit amount against user's limits // currency comes from country config - hook normalizes it internally @@ -144,7 +144,7 @@ const MantecaAddMoney: FC = () => { if (!selectedCountry?.currency) return if (isCreatingDeposit) return - if (!isUserMantecaKycApproved) { + if (!isUserMantecaKycApprovedForCountry) { setShowKycModal(true) return } @@ -200,7 +200,7 @@ const MantecaAddMoney: FC = () => { currentDenomination, selectedCountry, displayedAmount, - isUserMantecaKycApproved, + isUserMantecaKycApprovedForCountry, isCreatingDeposit, setUrlState, usdAmount, @@ -227,7 +227,7 @@ const MantecaAddMoney: FC = () => { if (hasRejection) { await sumsubFlow.handleSelfHealResubmit('MANTECA') } else { - await sumsubFlow.handleInitiateKyc('LATAM', undefined, true) + await sumsubFlow.handleInitiateKyc('LATAM', undefined, true, selectedCountry.id) } setShowKycModal(false) }} diff --git a/src/hooks/useMultiPhaseKycFlow.ts b/src/hooks/useMultiPhaseKycFlow.ts index 64c6e0664..f044166ea 100644 --- a/src/hooks/useMultiPhaseKycFlow.ts +++ b/src/hooks/useMultiPhaseKycFlow.ts @@ -183,7 +183,7 @@ export const useMultiPhaseKycFlow = ({ onKycSuccess, onManualClose, regionIntent // wrap handleInitiateKyc to reset state for new attempts const handleInitiateKyc = useCallback( - async (overrideIntent?: KYCRegionIntent, levelName?: string, crossRegion?: boolean) => { + async (overrideIntent?: KYCRegionIntent, levelName?: string, crossRegion?: boolean, targetCountry?: string) => { const intent = overrideIntent ?? regionIntent posthog.capture( intent === 'LATAM' ? ANALYTICS_EVENTS.MANTECA_KYC_INITIATED : ANALYTICS_EVENTS.KYC_INITIATED, @@ -199,7 +199,7 @@ export const useMultiPhaseKycFlow = ({ onKycSuccess, onManualClose, regionIntent isRealtimeFlowRef.current = false clearPreparingTimer() - await originalHandleInitiateKyc(overrideIntent, levelName, crossRegion) + await originalHandleInitiateKyc(overrideIntent, levelName, crossRegion, targetCountry) }, [originalHandleInitiateKyc, clearPreparingTimer, regionIntent, acquisitionSource] ) diff --git a/src/hooks/useSumsubKycFlow.ts b/src/hooks/useSumsubKycFlow.ts index 03c119288..2ed36681b 100644 --- a/src/hooks/useSumsubKycFlow.ts +++ b/src/hooks/useSumsubKycFlow.ts @@ -134,7 +134,7 @@ export const useSumsubKycFlow = ({ onKycSuccess, onManualClose, regionIntent }: }, [isVerificationProgressModalOpen]) const handleInitiateKyc = useCallback( - async (overrideIntent?: KYCRegionIntent, levelName?: string, crossRegion?: boolean) => { + async (overrideIntent?: KYCRegionIntent, levelName?: string, crossRegion?: boolean, targetCountry?: string) => { userInitiatedRef.current = true initiatingRef.current = true selfHealProviderRef.current = null @@ -154,6 +154,7 @@ export const useSumsubKycFlow = ({ onKycSuccess, onManualClose, regionIntent }: regionIntent: overrideIntent ?? regionIntent, levelName, crossRegion, + targetCountry, }) if (response.error) { From af6f16cea46f60104e5ce5d108fe35feb633051b Mon Sep 17 00:00:00 2001 From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com> Date: Tue, 12 May 2026 14:52:18 +0530 Subject: [PATCH 4/6] fix: refine manteca kyc document copy --- src/app/(mobile-ui)/qr-pay/page.tsx | 25 +++++++++++++++++++++++-- src/components/Kyc/InitiateKycModal.tsx | 10 +++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/app/(mobile-ui)/qr-pay/page.tsx b/src/app/(mobile-ui)/qr-pay/page.tsx index f02007d2a..eb2e8e761 100644 --- a/src/app/(mobile-ui)/qr-pay/page.tsx +++ b/src/app/(mobile-ui)/qr-pay/page.tsx @@ -116,6 +116,17 @@ export default function QRPayPage() { return null } }, [qrType]) + const targetMantecaCountry = useMemo(() => { + switch (qrType) { + case EQrType.PIX: + return 'BR' + case EQrType.MERCADO_PAGO: + case EQrType.ARGENTINA_QR3: + return 'AR' + default: + return undefined + } + }, [qrType]) // Check if this payment provider is under maintenance const isProviderDisabled = useMemo(() => { @@ -1158,7 +1169,12 @@ export default function QRPayPage() { { text: 'Verify now', onClick: () => - sumsubFlow.handleInitiateKyc('LATAM', undefined, isUserSumsubKycApproved || undefined), + sumsubFlow.handleInitiateKyc( + 'LATAM', + undefined, + isUserSumsubKycApproved || undefined, + targetMantecaCountry + ), variant: 'purple', shadowSize: '4', icon: 'check-circle', @@ -1176,7 +1192,12 @@ export default function QRPayPage() { { text: 'Continue verification', onClick: () => - sumsubFlow.handleInitiateKyc('LATAM', undefined, isUserSumsubKycApproved || undefined), + sumsubFlow.handleInitiateKyc( + 'LATAM', + undefined, + isUserSumsubKycApproved || undefined, + targetMantecaCountry + ), variant: 'purple', shadowSize: '4', icon: 'check-circle', diff --git a/src/components/Kyc/InitiateKycModal.tsx b/src/components/Kyc/InitiateKycModal.tsx index 48926dec0..9c5814432 100644 --- a/src/components/Kyc/InitiateKycModal.tsx +++ b/src/components/Kyc/InitiateKycModal.tsx @@ -21,7 +21,7 @@ interface InitiateKycModalProps { // for fresh KYC: "Verify your identity" // for provider rejections: "We need extra documents" // for blocked: "Verification issue — contact support" -// for cross-region: "Your identity is verified, we need a local ID" +// for cross-region: "Your identity is verified, submit a local ID" export const InitiateKycModal = ({ visible, onClose, @@ -41,6 +41,7 @@ export const InitiateKycModal = ({ if (error) return 'Something went wrong' if (isBlocked) return 'Verification issue' if (isProviderRejection) return 'We need extra documents' + if (isCrossRegion) return 'Submit local ID' return 'Verify your identity' } @@ -70,6 +71,13 @@ export const InitiateKycModal = ({ icon: 'upload' as IconName, } } + if (isCrossRegion) { + return { + text: isLoading ? 'Loading...' : 'Submit document', + onClick: onVerify, + icon: 'upload' as IconName, + } + } return { text: isLoading ? 'Loading...' : 'Start Verification', onClick: onVerify, From e683b21243f9c7f3a435117d47868c7a25d17d3a Mon Sep 17 00:00:00 2001 From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com> Date: Tue, 12 May 2026 16:49:20 +0530 Subject: [PATCH 5/6] fix: refresh manteca kyc target country --- src/app/(mobile-ui)/withdraw/manteca/page.tsx | 2 +- src/components/AddMoney/components/MantecaAddMoney.tsx | 2 +- src/hooks/useSumsubKycFlow.ts | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app/(mobile-ui)/withdraw/manteca/page.tsx b/src/app/(mobile-ui)/withdraw/manteca/page.tsx index 62097d8a9..ca73a76d6 100644 --- a/src/app/(mobile-ui)/withdraw/manteca/page.tsx +++ b/src/app/(mobile-ui)/withdraw/manteca/page.tsx @@ -538,7 +538,7 @@ export default function MantecaWithdrawFlow() { if (hasRejection) { await sumsubFlow.handleSelfHealResubmit('MANTECA') } else { - await sumsubFlow.handleInitiateKyc('LATAM', undefined, true, selectedCountry.id) + await sumsubFlow.handleInitiateKyc('LATAM', undefined, true, selectedCountry?.id) } setShowKycModal(false) }} diff --git a/src/components/AddMoney/components/MantecaAddMoney.tsx b/src/components/AddMoney/components/MantecaAddMoney.tsx index 3a1fba424..171537246 100644 --- a/src/components/AddMoney/components/MantecaAddMoney.tsx +++ b/src/components/AddMoney/components/MantecaAddMoney.tsx @@ -227,7 +227,7 @@ const MantecaAddMoney: FC = () => { if (hasRejection) { await sumsubFlow.handleSelfHealResubmit('MANTECA') } else { - await sumsubFlow.handleInitiateKyc('LATAM', undefined, true, selectedCountry.id) + await sumsubFlow.handleInitiateKyc('LATAM', undefined, true, selectedCountry?.id) } setShowKycModal(false) }} diff --git a/src/hooks/useSumsubKycFlow.ts b/src/hooks/useSumsubKycFlow.ts index 2ed36681b..3fe38a3e1 100644 --- a/src/hooks/useSumsubKycFlow.ts +++ b/src/hooks/useSumsubKycFlow.ts @@ -31,6 +31,8 @@ export const useSumsubKycFlow = ({ onKycSuccess, onManualClose, regionIntent }: const regionIntentRef = useRef(regionIntent) // tracks the level name across initiate + refresh (e.g. 'peanut-additional-docs') const levelNameRef = useRef(undefined) + // tracks the selected target country across initiate + refresh for country-scoped Manteca actions + const targetCountryRef = useRef(undefined) // guards fetchCurrentStatus from running while handleInitiateKyc is in progress const initiatingRef = useRef(false) // guard: only fire onKycSuccess when the user initiated a kyc flow in this session. @@ -120,6 +122,7 @@ export const useSumsubKycFlow = ({ onKycSuccess, onManualClose, regionIntent }: const response = await initiateSumsubKyc({ regionIntent: regionIntentRef.current, levelName: levelNameRef.current, + targetCountry: targetCountryRef.current, }) if (response.data?.status) { setLiveKycStatus(response.data.status) @@ -175,6 +178,7 @@ export const useSumsubKycFlow = ({ onKycSuccess, onManualClose, regionIntent }: const effectiveIntent = overrideIntent ?? regionIntent if (effectiveIntent) regionIntentRef.current = effectiveIntent levelNameRef.current = levelName + targetCountryRef.current = targetCountry // cross-region: bridge-direct means no SDK needed — backend is handling // rail enrollment + submission. go straight to the post-approval flow. @@ -247,6 +251,7 @@ export const useSumsubKycFlow = ({ onKycSuccess, onManualClose, regionIntent }: const response = await initiateSumsubKyc({ regionIntent: regionIntentRef.current, levelName: levelNameRef.current, + targetCountry: targetCountryRef.current, }) if (response.error || !response.data?.token) { From 091eaa63eab56f74b2b2e5c77d18ed8e3a98d88d Mon Sep 17 00:00:00 2001 From: kushagrasarathe <76868364+kushagrasarathe@users.noreply.github.com> Date: Tue, 12 May 2026 17:08:43 +0530 Subject: [PATCH 6/6] fix: require country for manteca withdraw route --- src/app/(mobile-ui)/qr-pay/page.tsx | 2 +- src/app/(mobile-ui)/withdraw/manteca/page.tsx | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/app/(mobile-ui)/qr-pay/page.tsx b/src/app/(mobile-ui)/qr-pay/page.tsx index eb2e8e761..ff91f1a7b 100644 --- a/src/app/(mobile-ui)/qr-pay/page.tsx +++ b/src/app/(mobile-ui)/qr-pay/page.tsx @@ -134,7 +134,7 @@ export default function QRPayPage() { }, [paymentProcessor]) const { shouldBlockPay, kycGateState } = useQrKycGate(paymentProcessor) - const { isUserMantecaKycApproved, isUserSumsubKycApproved } = useKycStatus() + const { isUserSumsubKycApproved } = useKycStatus() const sumsubFlow = useMultiPhaseKycFlow({}) const queryClient = useQueryClient() const [isShaking, setIsShaking] = useState(false) diff --git a/src/app/(mobile-ui)/withdraw/manteca/page.tsx b/src/app/(mobile-ui)/withdraw/manteca/page.tsx index ca73a76d6..e94d0a0f9 100644 --- a/src/app/(mobile-ui)/withdraw/manteca/page.tsx +++ b/src/app/(mobile-ui)/withdraw/manteca/page.tsx @@ -105,12 +105,11 @@ export default function MantecaWithdrawFlow() { // 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. - - // Determine country and currency from URL params or context - const countryPath = countryFromUrl || 'argentina' + const countryPath = countryFromUrl // Map country path to CountryData for KYC const selectedCountry = useMemo(() => { + if (!countryPath) return undefined return countryData.find((country) => country.type === 'country' && country.path === countryPath) }, [countryPath]) @@ -445,12 +444,12 @@ export default function MantecaWithdrawFlow() { } }, [step, queryClient]) - // redirect to withdraw page if country is not supported by manteca + // redirect to withdraw page if country is missing or not supported by manteca useEffect(() => { - if (!selectedCountry || !MANTECA_COUNTRIES_CONFIG[selectedCountry.id]) { + if (!countryFromUrl || !selectedCountry || !MANTECA_COUNTRIES_CONFIG[selectedCountry.id]) { router.replace('/withdraw') } - }, [selectedCountry, router]) + }, [countryFromUrl, selectedCountry, router]) if (isCurrencyLoading || !currencyPrice || !selectedCountry || !countryConfig) { return