Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import { Button } from '@/components/0_Bruddle'
import { countryCodeMap } from '@/components/AddMoney/consts'
import { ALL_COUNTRIES_ALPHA3_TO_ALPHA2 } from '@/components/AddMoney/consts'
import Card from '@/components/Global/Card'
import ErrorAlert from '@/components/Global/ErrorAlert'
import NavHeader from '@/components/Global/NavHeader'
Expand Down Expand Up @@ -183,7 +183,8 @@ export default function WithdrawBankPage() {

const countryCodeForFlag = () => {
if (!bankAccount?.details?.countryCode) return ''
const code = countryCodeMap[bankAccount.details.countryCode ?? ''] ?? bankAccount.details.countryCode
const code =
ALL_COUNTRIES_ALPHA3_TO_ALPHA2[bankAccount.details.countryCode ?? ''] ?? bankAccount.details.countryCode
return code.toLowerCase()
}

Expand Down
7 changes: 4 additions & 3 deletions src/app/(mobile-ui)/withdraw/manteca/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,16 @@ export default function MantecaWithdrawFlow() {
const [usdAmount, setUsdAmount] = useState<string | undefined>(undefined)
const [step, setStep] = useState<MantecaWithdrawStep>('amountInput')
const [balanceErrorMessage, setBalanceErrorMessage] = useState<string | null>(null)
const [destinationAddress, setDestinationAddress] = useState<string>('')
const searchParams = useSearchParams()
const paramAddress = searchParams.get('destination')
const [destinationAddress, setDestinationAddress] = useState<string>(paramAddress ?? '')
const [selectedBank, setSelectedBank] = useState<MantecaBankCode | null>(null)
const [accountType, setAccountType] = useState<MantecaAccountType | null>(null)
const [errorMessage, setErrorMessage] = useState<string | null>(null)
const [isKycModalOpen, setIsKycModalOpen] = useState(false)
const [isDestinationAddressValid, setIsDestinationAddressValid] = useState(false)
const [isDestinationAddressChanging, setIsDestinationAddressChanging] = useState(false)
const router = useRouter()
const searchParams = useSearchParams()
const { sendMoney, balance } = useWallet()
const { isLoading, loadingState, setLoadingState } = useContext(loadingStateContext)
const { user, fetchUser } = useAuth()
Expand Down Expand Up @@ -223,7 +224,7 @@ export default function MantecaWithdrawFlow() {
setAmount(undefined)
setCurrencyAmount(undefined)
setUsdAmount(undefined)
setDestinationAddress('')
setDestinationAddress(paramAddress ?? '')
setSelectedBank(null)
setAccountType(null)
setErrorMessage(null)
Expand Down
4 changes: 2 additions & 2 deletions src/components/AddMoney/components/AddMoneyBankDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { PEANUT_WALLET_TOKEN_SYMBOL } from '@/constants'
import { useOnrampFlow } from '@/context/OnrampFlowContext'
import { useRouter, useParams } from 'next/navigation'
import { useCallback, useEffect, useMemo } from 'react'
import { countryCodeMap, CountryData, countryData } from '@/components/AddMoney/consts'
import { ALL_COUNTRIES_ALPHA3_TO_ALPHA2, CountryData, countryData } from '@/components/AddMoney/consts'
import { formatCurrencyAmount } from '@/utils/currency'
import { formatBankAccountDisplay } from '@/utils/format.utils'
import Icon from '@/components/Global/Icon'
Expand Down Expand Up @@ -93,7 +93,7 @@ export default function AddMoneyBankDetails({ flow = 'add-money' }: IAddMoneyBan

const countryCodeForFlag = useMemo(() => {
const countryId = currentCountryDetails?.id || 'USA'
const countryCode = countryCodeMap[countryId] || countryId // if countryId is not in countryCodeMap, use countryId because for some countries countryId is of 2 digit and countryCodeMap is a mapping of 3 digit to 2 digit country codes
const countryCode = ALL_COUNTRIES_ALPHA3_TO_ALPHA2[countryId] || countryId // if countryId is not in countryCodeMap, use countryId because for some countries countryId is of 2 digit and countryCodeMap is a mapping of 3 digit to 2 digit country codes
return countryCode?.toLowerCase() || 'us'
}, [currentCountryDetails])

Expand Down
5 changes: 3 additions & 2 deletions src/components/AddMoney/components/DepositMethodList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import AvatarWithBadge from '@/components/Profile/AvatarWithBadge'
import { SearchResultCard } from '@/components/SearchUsers/SearchResultCard'
import Image from 'next/image'
import { twMerge } from 'tailwind-merge'
import { countryCodeMap } from '../consts'
import { ALL_COUNTRIES_ALPHA3_TO_ALPHA2 } from '../consts'

export interface DepositMethod {
type: 'crypto' | 'country'
Expand Down Expand Up @@ -54,7 +54,8 @@ export const DepositMethodList = ({ methods, onItemClick, isAllMethodsView = fal
}

const threeLetterCountryCode = (method.id ?? '').toUpperCase()
const twoLetterCountryCode = countryCodeMap[threeLetterCountryCode] ?? threeLetterCountryCode
const twoLetterCountryCode =
ALL_COUNTRIES_ALPHA3_TO_ALPHA2[threeLetterCountryCode] ?? threeLetterCountryCode

const countryCodeForFlag = twoLetterCountryCode.toLowerCase() ?? ''

Expand Down
19 changes: 15 additions & 4 deletions src/components/AddMoney/consts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2484,7 +2484,7 @@ const LATAM_COUNTRY_CODES = [

// bridge EAA country codes, source: https://apidocs.bridge.xyz/docs/sepa-euro-transactions
// note: this is a map of 3-letter country codes to 2-letter country codes, for flags to work, bridge expects 3 letter codes
export const countryCodeMap: { [key: string]: string } = {
export const BRIDGE_ALPHA3_TO_ALPHA2: { [key: string]: string } = {
ALA: 'AX',
AND: 'AD',
AUT: 'AT',
Expand Down Expand Up @@ -2528,9 +2528,20 @@ export const countryCodeMap: { [key: string]: string } = {
USA: 'US',
}

const enabledBankWithdrawCountries = new Set([...Object.values(countryCodeMap), 'US', 'MX', 'AR', 'BO'])
export const MANTECA_ALPHA3_TO_ALPHA2: { [key: string]: string } = {
ARG: 'AR',
BOL: 'BO',
BRA: 'BR',
}

export const ALL_COUNTRIES_ALPHA3_TO_ALPHA2: { [key: string]: string } = {
...BRIDGE_ALPHA3_TO_ALPHA2,
...MANTECA_ALPHA3_TO_ALPHA2,
}

const enabledBankWithdrawCountries = new Set([...Object.values(BRIDGE_ALPHA3_TO_ALPHA2), 'US', 'MX', 'AR', 'BO'])

const enabledBankDepositCountries = new Set([...Object.values(countryCodeMap), 'US', 'AR'])
const enabledBankDepositCountries = new Set([...Object.values(BRIDGE_ALPHA3_TO_ALPHA2), 'US', 'AR'])

// Helper function to check if a country code is enabled for bank transfers
// Handles both 2-letter and 3-letter country codes
Expand All @@ -2542,7 +2553,7 @@ const isCountryEnabledForBankTransfer = (countryCode: string, direction: 'withdr
}

// Check if it's a 3-letter code that maps to an enabled 2-letter code
const mappedCode = countryCodeMap[countryCode]
const mappedCode = ALL_COUNTRIES_ALPHA3_TO_ALPHA2[countryCode]
return mappedCode ? enabledCountries.has(mappedCode) : false
}

Expand Down
73 changes: 38 additions & 35 deletions src/components/AddWithdraw/AddWithdrawRouterView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,27 @@ interface AddWithdrawRouterViewProps {

const MAX_RECENT_METHODS = 5

function saveRecentMethod(method: DepositMethod) {
const newRecentMethod: RecentMethod = {
id: method.id,
type: method.type as 'crypto' | 'country',
title: method.title,
description: method.description,
iconUrl: method.iconUrl,
currency: method.currency,
path: method.path,
}

const prefs = getUserPreferences() || {}
const currentRecentList = prefs.recentAddMethods || []

const filteredList = currentRecentList.filter((m) => m.id !== newRecentMethod.id)

const updatedRecentList = [newRecentMethod, ...filteredList].slice(0, MAX_RECENT_METHODS)

updateUserPreferences({ ...prefs, recentAddMethods: updatedRecentList })
}

export const AddWithdrawRouterView: FC<AddWithdrawRouterViewProps> = ({
flow,
pageTitle,
Expand Down Expand Up @@ -57,7 +78,10 @@ export const AddWithdrawRouterView: FC<AddWithdrawRouterViewProps> = ({
const bankAccounts =
user?.accounts.filter(
(acc) =>
acc.type === AccountType.IBAN || acc.type === AccountType.US || acc.type === AccountType.CLABE
acc.type === AccountType.IBAN ||
acc.type === AccountType.US ||
acc.type === AccountType.CLABE ||
acc.type === AccountType.MANTECA
) ?? []

if (bankAccounts.length > 0) {
Expand All @@ -81,6 +105,10 @@ export const AddWithdrawRouterView: FC<AddWithdrawRouterViewProps> = ({
}, [flow, user, setShouldShowAllMethods])

const handleMethodSelected = (method: DepositMethod) => {
if (flow === 'add') {
saveRecentMethod(method)
}

// Handle "From Bank" specially for add flow
if (flow === 'add' && method.id === 'bank-transfer-add') {
setFromBankSelected(true)
Expand Down Expand Up @@ -108,37 +136,6 @@ export const AddWithdrawRouterView: FC<AddWithdrawRouterViewProps> = ({
return
}

// Original add flow logic
const newRecentMethod: RecentMethod = {
id: method.id,
type: method.type as 'crypto' | 'country',
title: method.title,
description: method.description,
iconUrl: method.iconUrl,
currency: method.currency,
path: method.path,
}

const prefs = getUserPreferences() || {}
let currentRecentList: RecentMethod[] = []
if (flow === 'add') {
currentRecentList = prefs.recentAddMethods || []
} else {
currentRecentList = prefs.recentWithdrawMethods || []
}

const filteredList = currentRecentList.filter(
(m) => !(m.id === newRecentMethod.id && m.type === newRecentMethod.type)
)

const updatedRecentList = [newRecentMethod, ...filteredList].slice(0, MAX_RECENT_METHODS)

if (flow === 'add') {
updateUserPreferences({ ...prefs, recentAddMethods: updatedRecentList })
} else {
// for withdraw, we don't save to recents from the 'all methods' list, we show saved accounts
}

if (method.path) {
router.push(method.path)
}
Expand Down Expand Up @@ -190,7 +187,13 @@ export const AddWithdrawRouterView: FC<AddWithdrawRouterViewProps> = ({

// FIXED: For withdraw flow, route to saved account path
if (flow === 'withdraw') {
router.push(path)
if (account.type === AccountType.MANTECA) {
router.push(
`/withdraw/manteca?country=${account.details.countryName}&destination=${account.identifier}`
)
} else {
router.push(path)
}
return
}

Expand Down Expand Up @@ -261,13 +264,13 @@ export const AddWithdrawRouterView: FC<AddWithdrawRouterViewProps> = ({
viewMode="add-withdraw"
onCountryClick={(country) => {
if (flow === 'withdraw') {
// FIXED: Route directly to country page for method selection
const countryPath = `${baseRoute}/${country.path}`
router.push(countryPath)
return
}

// Original add flow
//Add
saveRecentMethod(country)
const countryPath = `${baseRoute}/${country.path}`
router.push(countryPath)
}}
Expand Down
6 changes: 3 additions & 3 deletions src/components/AddWithdraw/DynamicBankAccountForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useAuth } from '@/context/authContext'
import { Button } from '@/components/0_Bruddle/Button'
import { AddBankAccountPayload, BridgeAccountOwnerType, BridgeAccountType } from '@/app/actions/types/users.types'
import BaseInput from '@/components/0_Bruddle/BaseInput'
import { countryCodeMap } from '@/components/AddMoney/consts'
import { BRIDGE_ALPHA3_TO_ALPHA2, ALL_COUNTRIES_ALPHA3_TO_ALPHA2 } from '@/components/AddMoney/consts'
import { useParams, useRouter } from 'next/navigation'
import { validateIban, validateBic, isValidRoutingNumber } from '@/utils/bridge-accounts.utils'
import ErrorAlert from '@/components/Global/ErrorAlert'
Expand All @@ -20,7 +20,7 @@ import { bankFormActions } from '@/redux/slices/bank-form-slice'
import { useDebounce } from '@/hooks/useDebounce'

const isIBANCountry = (country: string) => {
return countryCodeMap[country.toUpperCase()] !== undefined
return BRIDGE_ALPHA3_TO_ALPHA2[country.toUpperCase()] !== undefined
}

export type IBankAccountDetails = {
Expand Down Expand Up @@ -266,7 +266,7 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D
)

const countryCodeForFlag = useMemo(() => {
return countryCodeMap[country.toUpperCase()] ?? country.toUpperCase()
return ALL_COUNTRIES_ALPHA3_TO_ALPHA2[country.toUpperCase()] ?? country.toUpperCase()
}, [country])

return (
Expand Down
4 changes: 2 additions & 2 deletions src/components/Claim/Link/views/Confirm.bank-claim.view.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import { Button } from '@/components/0_Bruddle'
import { countryCodeMap } from '@/components/AddMoney/consts'
import { ALL_COUNTRIES_ALPHA3_TO_ALPHA2 } from '@/components/AddMoney/consts'
import Card from '@/components/Global/Card'
import ErrorAlert from '@/components/Global/ErrorAlert'
import NavHeader from '@/components/Global/NavHeader'
Expand Down Expand Up @@ -50,7 +50,7 @@ export function ConfirmBankClaimView({
}, [bankDetails])

const countryCodeForFlag = useMemo(() => {
return countryCodeMap[bankDetails?.country?.toUpperCase()] ?? bankDetails.country.toUpperCase()
return ALL_COUNTRIES_ALPHA3_TO_ALPHA2[bankDetails?.country?.toUpperCase()] ?? bankDetails.country.toUpperCase()
}, [bankDetails.country])

// amount in USD from claim link data
Expand Down
20 changes: 14 additions & 6 deletions src/components/Common/CountryList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
'use client'
import { countryCodeMap, CountryData, countryData, MantecaSupportedExchanges } from '@/components/AddMoney/consts'
import {
BRIDGE_ALPHA3_TO_ALPHA2,
CountryData,
countryData,
MantecaSupportedExchanges,
ALL_COUNTRIES_ALPHA3_TO_ALPHA2,
} from '@/components/AddMoney/consts'
import EmptyState from '@/components/Global/EmptyStates/EmptyState'
import { SearchInput } from '@/components/SearchUsers/SearchInput'
import { SearchResultCard } from '@/components/SearchUsers/SearchResultCard'
Expand Down Expand Up @@ -49,9 +55,11 @@ export const CountryList = ({
return [...supportedCountries].sort((a, b) => {
if (userGeoLocationCountryCode) {
const aIsUserCountry =
countryCodeMap[a.id] === userGeoLocationCountryCode || a.id === userGeoLocationCountryCode
ALL_COUNTRIES_ALPHA3_TO_ALPHA2[a.id] === userGeoLocationCountryCode ||
a.id === userGeoLocationCountryCode
const bIsUserCountry =
countryCodeMap[b.id] === userGeoLocationCountryCode || b.id === userGeoLocationCountryCode
ALL_COUNTRIES_ALPHA3_TO_ALPHA2[b.id] === userGeoLocationCountryCode ||
b.id === userGeoLocationCountryCode

if (aIsUserCountry && !bIsUserCountry) return -1
if (!aIsUserCountry && bIsUserCountry) return 1
Expand Down Expand Up @@ -107,14 +115,14 @@ export const CountryList = ({
{filteredCountries.length > 0 ? (
filteredCountries.map((country, index) => {
const twoLetterCountryCode =
countryCodeMap[country.id.toUpperCase()] ?? country.id.toLowerCase()
ALL_COUNTRIES_ALPHA3_TO_ALPHA2[country.id.toUpperCase()] ?? country.id.toLowerCase()
const position = getCardPosition(index, filteredCountries.length)
Comment on lines 117 to 119
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use iso2 as fallback for flags instead of id.toLowerCase()

If a country.id is a 3-letter code not present in the map, falling back to id.toLowerCase() yields an invalid flag code (e.g., deu). Prefer the iso2 field.

-                            const twoLetterCountryCode =
-                                ALL_COUNTRIES_ALPHA3_TO_ALPHA2[country.id.toUpperCase()] ?? country.id.toLowerCase()
+                            const twoLetterCountryCode =
+                                ALL_COUNTRIES_ALPHA3_TO_ALPHA2[country.id.toUpperCase()] ??
+                                country.iso2 ??
+                                country.id
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const twoLetterCountryCode =
countryCodeMap[country.id.toUpperCase()] ?? country.id.toLowerCase()
ALL_COUNTRIES_ALPHA3_TO_ALPHA2[country.id.toUpperCase()] ?? country.id.toLowerCase()
const position = getCardPosition(index, filteredCountries.length)
const twoLetterCountryCode =
ALL_COUNTRIES_ALPHA3_TO_ALPHA2[country.id.toUpperCase()] ??
country.iso2 ??
country.id
const position = getCardPosition(index, filteredCountries.length)
🤖 Prompt for AI Agents
In src/components/Common/CountryList.tsx around lines 121 to 123, the code falls
back to country.id.toLowerCase() when the 3-letter code lookup fails, which
produces invalid flag codes; replace that fallback with the country's iso2 value
(e.g., country.iso2?.toLowerCase()) and ensure a safe default if iso2 is missing
(such as an empty string or a placeholder), so the flag code resolution becomes:
try the alpha3→alpha2 map first, then country.iso2 lowercased, otherwise the
safe default.


const isBridgeSupportedCountry = [
'US',
'MX',
...Object.keys(countryCodeMap),
...Object.values(countryCodeMap),
...Object.keys(BRIDGE_ALPHA3_TO_ALPHA2),
...Object.values(BRIDGE_ALPHA3_TO_ALPHA2),
].includes(country.id)
const isMantecaSupportedCountry = Object.keys(MantecaSupportedExchanges).includes(
country.id
Expand Down
5 changes: 3 additions & 2 deletions src/components/Common/SavedAccountsView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use client'
import { countryData as ALL_METHODS_DATA, countryCodeMap } from '@/components/AddMoney/consts'
import { countryData as ALL_METHODS_DATA, ALL_COUNTRIES_ALPHA3_TO_ALPHA2 } from '@/components/AddMoney/consts'
import { shortenStringLong, formatIban } from '@/utils/general.utils'
import { AccountType, Account } from '@/interfaces'
import Image from 'next/image'
Expand Down Expand Up @@ -74,7 +74,8 @@ export function SavedAccountsMapping({
}

const threeLetterCountryCode = (details.countryCode ?? '').toUpperCase()
const twoLetterCountryCode = countryCodeMap[threeLetterCountryCode] ?? threeLetterCountryCode
const twoLetterCountryCode =
ALL_COUNTRIES_ALPHA3_TO_ALPHA2[threeLetterCountryCode] ?? threeLetterCountryCode

const countryCodeForFlag = twoLetterCountryCode.toLowerCase() ?? ''

Expand Down
4 changes: 2 additions & 2 deletions src/components/Kyc/KycStatusDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export const KycStatusDrawer = ({ isOpen, onClose, verification, bridgeKycStatus
case 'processing':
return (
<KycProcessing
bridgeKycStartedAt={user?.user?.bridgeKycStartedAt}
bridgeKycStartedAt={verification?.createdAt ?? user?.user?.bridgeKycStartedAt}
countryCode={countryCode ?? undefined}
isBridge={isBridgeKyc}
/>
Expand All @@ -137,7 +137,7 @@ export const KycStatusDrawer = ({ isOpen, onClose, verification, bridgeKycStatus
return (
<KycFailed
reason={rejectionReason}
bridgeKycRejectedAt={user?.user?.bridgeKycRejectedAt}
bridgeKycRejectedAt={verification?.updatedAt ?? user?.user?.bridgeKycRejectedAt}
countryCode={countryCode ?? undefined}
isBridge={isBridgeKyc}
onRetry={onRetry}
Expand Down
6 changes: 3 additions & 3 deletions src/components/Profile/views/IdentityVerification.view.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'
import { updateUserById } from '@/app/actions/users'
import { Button } from '@/components/0_Bruddle'
import { countryCodeMap, MantecaSupportedExchanges } from '@/components/AddMoney/consts'
import { BRIDGE_ALPHA3_TO_ALPHA2, MantecaSupportedExchanges } from '@/components/AddMoney/consts'
import { UserDetailsForm, UserDetailsFormData } from '@/components/AddMoney/UserDetailsForm'
import { CountryList } from '@/components/Common/CountryList'
import ErrorAlert from '@/components/Global/ErrorAlert'
Expand Down Expand Up @@ -109,8 +109,8 @@ const IdentityVerificationView = () => {
return (
upper === 'US' ||
upper === 'MX' ||
Object.keys(countryCodeMap).includes(upper) ||
Object.values(countryCodeMap).includes(upper)
Object.keys(BRIDGE_ALPHA3_TO_ALPHA2).includes(upper) ||
Object.values(BRIDGE_ALPHA3_TO_ALPHA2).includes(upper)
)
}

Expand Down
1 change: 1 addition & 0 deletions src/interfaces/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export enum AccountType {
EVM_ADDRESS = 'evm-address',
PEANUT_WALLET = 'peanut-wallet',
BRIDGE = 'bridgeBankAccount',
MANTECA = 'manteca',
}

export interface Account {
Expand Down
Loading
Loading