diff --git a/public/game/peanut-game.html b/public/game/peanut-game.html index 2dabff7f5..6399a107a 100644 --- a/public/game/peanut-game.html +++ b/public/game/peanut-game.html @@ -4,7 +4,7 @@ - + diff --git a/src/app/(mobile-ui)/add-money/[country]/bank/page.tsx b/src/app/(mobile-ui)/add-money/[country]/bank/page.tsx index 7792da50f..4915aa8e6 100644 --- a/src/app/(mobile-ui)/add-money/[country]/bank/page.tsx +++ b/src/app/(mobile-ui)/add-money/[country]/bank/page.tsx @@ -10,7 +10,7 @@ import { useWallet } from '@/hooks/wallet/useWallet' import { formatAmount } from '@/utils' import { countryData } from '@/components/AddMoney/consts' import { InitiateKYCModal } from '@/components/Kyc' -import { BridgeKycStatus } from '@/utils/bridge-accounts.utils' +import { KYCStatus } from '@/utils/bridge-accounts.utils' import { useWebSocket } from '@/hooks/useWebSocket' import { useAuth } from '@/context/authContext' import { useCreateOnramp } from '@/hooks/useCreateOnramp' @@ -37,7 +37,7 @@ export default function OnrampBankPage() { const [isRiskAccepted, setIsRiskAccepted] = useState(false) const [isKycModalOpen, setIsKycModalOpen] = useState(false) - const [liveKycStatus, setLiveKycStatus] = useState(undefined) + const [liveKycStatus, setLiveKycStatus] = useState(undefined) const { amountToOnramp: amountFromContext, setAmountToOnramp, setError, error, setOnrampData } = useOnrampFlow() const formRef = useRef<{ handleSubmit: () => void }>(null) const [isUpdatingUser, setIsUpdatingUser] = useState(false) @@ -58,15 +58,15 @@ export default function OnrampBankPage() { username: user?.user.username ?? undefined, autoConnect: !!user?.user.username, onKycStatusUpdate: (newStatus) => { - setLiveKycStatus(newStatus as BridgeKycStatus) + setLiveKycStatus(newStatus as KYCStatus) }, }) useEffect(() => { - if (user?.user.bridgeKycStatus) { - setLiveKycStatus(user.user.bridgeKycStatus as BridgeKycStatus) + if (user?.user.kycStatus) { + setLiveKycStatus(user.user.kycStatus as KYCStatus) } - }, [user?.user.bridgeKycStatus]) + }, [user?.user.kycStatus]) useEffect(() => { fetchUser() @@ -84,7 +84,7 @@ export default function OnrampBankPage() { useEffect(() => { if (user === null) return // wait for user to be fetched if (step === 'loading') { - const currentKycStatus = liveKycStatus || user?.user.bridgeKycStatus + const currentKycStatus = liveKycStatus || user?.user.kycStatus const isUserKycVerified = currentKycStatus === 'approved' if (!isUserKycVerified) { @@ -216,7 +216,7 @@ export default function OnrampBankPage() { if (!user?.user.userId) throw new Error('User not found') const result = await updateUserById({ userId: user.user.userId, - fullName: data.fullName, + fullName: `${data.firstName} ${data.lastName}`, email: data.email, }) if (result.error) { @@ -246,7 +246,8 @@ export default function OnrampBankPage() { const initialUserDetails: Partial = useMemo( () => ({ - fullName: user?.user.fullName ?? '', + firstName: user?.user.fullName ? firstName : '', + lastName: user?.user.fullName ? lastName : '', email: user?.user.email ?? '', }), [user?.user.fullName, user?.user.email, firstName, lastName] diff --git a/src/app/(mobile-ui)/history/page.tsx b/src/app/(mobile-ui)/history/page.tsx index 77441810d..35feb7f5c 100644 --- a/src/app/(mobile-ui)/history/page.tsx +++ b/src/app/(mobile-ui)/history/page.tsx @@ -65,14 +65,10 @@ const HistoryPage = () => { const combinedAndSortedEntries = useMemo(() => { const entries: Array = [...allEntries] - if ( - user?.user?.bridgeKycStatus && - user.user.bridgeKycStatus !== 'not_started' && - user.user.bridgeKycStartedAt - ) { + if (user?.user?.kycStatus && user.user.kycStatus !== 'not_started' && user.user.kycStartedAt) { entries.push({ isKyc: true, - timestamp: user.user.bridgeKycStartedAt, + timestamp: user.user.kycStartedAt, uuid: 'kyc-status-item', }) } @@ -96,7 +92,7 @@ const HistoryPage = () => { return (

Transactions

{' '} - +
) } diff --git a/src/app/(mobile-ui)/home/page.tsx b/src/app/(mobile-ui)/home/page.tsx index da82c0312..295bad12d 100644 --- a/src/app/(mobile-ui)/home/page.tsx +++ b/src/app/(mobile-ui)/home/page.tsx @@ -1,19 +1,21 @@ 'use client' +import { PeanutArmHoldingBeer } from '@/assets' import { Button, ButtonSize, ButtonVariant } from '@/components/0_Bruddle' import PageContainer from '@/components/0_Bruddle/PageContainer' +import Card from '@/components/Global/Card' import { Icon } from '@/components/Global/Icons/Icon' import IOSInstallPWAModal from '@/components/Global/IOSInstallPWAModal' import Loading from '@/components/Global/Loading' import PeanutLoading from '@/components/Global/PeanutLoading' -//import RewardsModal from '@/components/Global/RewardsModal' +import RewardsModal from '@/components/Global/RewardsModal' import HomeHistory from '@/components/Home/HomeHistory' -//import RewardsCardModal from '@/components/Home/RewardsCardModal' +import RewardsCardModal from '@/components/Home/RewardsCardModal' import { SearchUsers } from '@/components/SearchUsers' import { UserHeader } from '@/components/UserHeader' import { useAuth } from '@/context/authContext' import { useWallet } from '@/hooks/wallet/useWallet' -import { useUserStore } from '@/redux/hooks' +import { useUserStore, useWalletStore } from '@/redux/hooks' import { formatExtendedNumber, getUserPreferences, @@ -23,6 +25,7 @@ import { saveToLocalStorage, } from '@/utils' import { useDisconnect } from '@reown/appkit/react' +import Image from 'next/image' import Link from 'next/link' import { useEffect, useMemo, useState } from 'react' import { twMerge } from 'tailwind-merge' @@ -37,16 +40,16 @@ import { PEANUT_WALLET_TOKEN_DECIMALS } from '@/constants' import { PostSignupActionManager } from '@/components/Global/PostSignupActionManager' import { useWithdrawFlow } from '@/context/WithdrawFlowContext' import { useClaimBankFlow } from '@/context/ClaimBankFlowContext' -import { useDeviceType, DeviceType } from '@/hooks/useGetDeviceType' const BALANCE_WARNING_THRESHOLD = parseInt(process.env.NEXT_PUBLIC_BALANCE_WARNING_THRESHOLD ?? '500') const BALANCE_WARNING_EXPIRY = parseInt(process.env.NEXT_PUBLIC_BALANCE_WARNING_EXPIRY ?? '1814400') // 21 days in seconds export default function Home() { - const { balance, address, isFetchingBalance } = useWallet() + const { balance, address, isFetchingBalance, isFetchingRewardBalance } = useWallet() + const { rewardWalletBalance } = useWalletStore() + const [isRewardsModalOpen, setIsRewardsModalOpen] = useState(false) const { resetFlow: resetClaimBankFlow } = useClaimBankFlow() const { resetWithdrawFlow } = useWithdrawFlow() - const { deviceType } = useDeviceType() const [isBalanceHidden, setIsBalanceHidden] = useState(() => { const prefs = getUserPreferences() return prefs?.balanceHidden ?? false @@ -86,7 +89,6 @@ export default function Home() { }, [resetClaimBankFlow, resetWithdrawFlow]) useEffect(() => { - if (isFetchingUser) return // We have some users that didn't have the peanut wallet created // correctly, so we need to create it if (address && user && !user.accounts.some((a) => a.type === AccountType.PEANUT_WALLET)) { @@ -96,7 +98,7 @@ export default function Home() { userId: user.user.userId, }) } - }, [user, address, isFetchingUser]) + }, [user, address, addAccount]) // always reset external wallet connection on home page useEffect(() => { @@ -108,7 +110,9 @@ export default function Home() { // effect for showing iOS PWA Install modal useEffect(() => { if (typeof window !== 'undefined') { - const isIOS = deviceType === DeviceType.IOS + const isIOS = + /iPad|iPhone|iPod/.test(navigator.userAgent) || + (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) const isStandalone = window.matchMedia('(display-mode: standalone)').matches const hasSeenModalThisSession = sessionStorage.getItem('hasSeenIOSPWAPromptThisSession') const redirectUrl = getFromLocalStorage('redirect') @@ -127,7 +131,7 @@ export default function Home() { setShowIOSPWAInstallModal(false) } } - }, [user?.hasPwaInstalled, isPostSignupActionModalVisible, deviceType]) + }, [user?.hasPwaInstalled, isPostSignupActionModalVisible]) // effect for showing balance warning modal useEffect(() => { @@ -212,7 +216,7 @@ export default function Home() { @@ -241,14 +245,19 @@ export default function Home() { + {/* Rewards Card - only shows if balance is non-zero */} +
setIsRewardsModalOpen(true)} className="cursor-pointer"> + +
+ - {/* Render the new Rewards Modal - */} - {/* Render the new Rewards Card Modal + {/* Render the new Rewards Card Modal */} setIsRewardsModalOpen(false)} /> - */} {/* iOS PWA Install Modal */} setShowIOSPWAInstallModal(false)} /> @@ -405,3 +414,41 @@ function ActionButton({ label, action, variant = 'primary-soft', size = 'small' function ActionButtonGroup({ children }: { children: React.ReactNode }) { return
{children}
} + +function RewardsCard({ + balance, + isFetchingRewardBalance, +}: { + balance: string | undefined + isFetchingRewardBalance: boolean +}) { + if (!balance || balance === '0') return null + + return ( +
+

Rewards

+ +
+
+
+ Peanut arm holding beer +
+ + Beers +
+ {isFetchingRewardBalance ? : balance} +
+
+
+ ) +} diff --git a/src/app/(mobile-ui)/layout.tsx b/src/app/(mobile-ui)/layout.tsx index 948fb93ec..f886bb3fd 100644 --- a/src/app/(mobile-ui)/layout.tsx +++ b/src/app/(mobile-ui)/layout.tsx @@ -20,8 +20,6 @@ import PullToRefresh from 'pulltorefreshjs' import { useEffect, useMemo, useState } from 'react' import { twMerge } from 'tailwind-merge' import '../../styles/globals.css' -import SupportDrawer from '@/components/Global/SupportDrawer' -import { useSupportModalContext } from '@/context/SupportModalContext' // Allow access to some public paths without authentication const publicPathRegex = /^\/(request\/pay|claim|pay\/.+$|support)/ @@ -33,7 +31,7 @@ const Layout = ({ children }: { children: React.ReactNode }) => { const [isReady, setIsReady] = useState(false) const [hasToken, setHasToken] = useState(false) const isUserLoggedIn = !!user?.user.userId || false - const { setIsSupportModalOpen } = useSupportModalContext() + const isHome = pathName === '/home' const isHistory = pathName === '/history' const isSupport = pathName === '/support' @@ -111,7 +109,7 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
{/* Only show banner if not on landing page */} {pathName !== '/' && ( -
) } diff --git a/src/app/(mobile-ui)/profile/exchange-rate/page.tsx b/src/app/(mobile-ui)/profile/exchange-rate/page.tsx deleted file mode 100644 index f1ec7be9d..000000000 --- a/src/app/(mobile-ui)/profile/exchange-rate/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client' - -import PageContainer from '@/components/0_Bruddle/PageContainer' -import ExchangeRateWidget from '@/components/Global/ExchangeRateWidget' -import NavHeader from '@/components/Global/NavHeader' -import { useRouter } from 'next/navigation' - -export default function ExchangeRatePage() { - const router = useRouter() - - return ( - - router.replace('/profile')} /> -
- router.push('/add-money')} - /> -
-
- ) -} diff --git a/src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx b/src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx index 0c452f09c..6054a03dd 100644 --- a/src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx +++ b/src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx @@ -12,7 +12,7 @@ import { useWithdrawFlow } from '@/context/WithdrawFlowContext' import { useWallet } from '@/hooks/wallet/useWallet' import { AccountType, Account } from '@/interfaces' import { formatIban, shortenAddressLong, isTxReverted } from '@/utils/general.utils' -import { useParams, useRouter } from 'next/navigation' +import { useRouter } from 'next/navigation' import { useEffect, useState } from 'react' import DirectSuccessView from '@/components/Payment/Views/Status.payment.view' import { ErrorHandler, getBridgeChainName } from '@/utils' @@ -20,7 +20,6 @@ import { getOfframpCurrencyConfig } from '@/utils/bridge.utils' import { createOfframp, confirmOfframp } from '@/app/actions/offramp' import { useAuth } from '@/context/authContext' import ExchangeRate from '@/components/ExchangeRate' -import countryCurrencyMappings from '@/constants/countryCurrencyMapping' type View = 'INITIAL' | 'SUCCESS' @@ -31,14 +30,6 @@ export default function WithdrawBankPage() { const router = useRouter() const [isLoading, setIsLoading] = useState(false) const [view, setView] = useState('INITIAL') - const params = useParams() - const country = params.country as string - - const nonEuroCurrency = countryCurrencyMappings.find( - (currency) => - country.toLowerCase() === currency.country.toLowerCase() || - currency.path?.toLowerCase() === country.toLowerCase() - )?.currencyCode useEffect(() => { if (!bankAccount) { @@ -235,7 +226,7 @@ export default function WithdrawBankPage() { )} - + {error.showError ? ( diff --git a/src/app/(mobile-ui)/withdraw/crypto/page.tsx b/src/app/(mobile-ui)/withdraw/crypto/page.tsx index 0d870c91c..891dbacaa 100644 --- a/src/app/(mobile-ui)/withdraw/crypto/page.tsx +++ b/src/app/(mobile-ui)/withdraw/crypto/page.tsx @@ -281,6 +281,7 @@ export default function WithdrawCryptoPage() { // reset withdraw flow when this component unmounts useEffect(() => { return () => { + resetWithdrawFlow() resetPaymentInitiator() resetTokenContextProvider() // reset token selector context to make sure previously selected token is not cached } @@ -366,9 +367,6 @@ export default function WithdrawCryptoPage() { address={withdrawData.address} /> } - onComplete={() => { - resetWithdrawFlow() - }} /> )} diff --git a/src/app/(mobile-ui)/withdraw/page.tsx b/src/app/(mobile-ui)/withdraw/page.tsx index a59cfd80f..3dd1d4a42 100644 --- a/src/app/(mobile-ui)/withdraw/page.tsx +++ b/src/app/(mobile-ui)/withdraw/page.tsx @@ -27,7 +27,6 @@ export default function WithdrawPage() { error, setUsdAmount, resetWithdrawFlow, - setShowAllWithdrawMethods, } = useWithdrawFlow() // choose the first screen: if an amount already exists we jump straight to the method list @@ -75,7 +74,6 @@ export default function WithdrawPage() { useEffect(() => { if (amountFromContext && parseFloat(amountFromContext) > 0) { setStep('selectMethod') - if (!rawTokenAmount) { setRawTokenAmount(amountFromContext) } @@ -89,13 +87,6 @@ export default function WithdrawPage() { } }, [amountFromContext, step]) - useEffect(() => { - // If amount is available (i.e) user clicked back from select method view, show all methods - if (amountFromContext) { - setShowAllWithdrawMethods(true) - } - }, []) - const validateAmount = useCallback( (amountStr: string): boolean => { if (!amountStr) { diff --git a/src/app/(setup)/setup/page.tsx b/src/app/(setup)/setup/page.tsx index 76f3b43f8..325a62f8a 100644 --- a/src/app/(setup)/setup/page.tsx +++ b/src/app/(setup)/setup/page.tsx @@ -40,7 +40,7 @@ export default function SetupPage() { // check for native passkey support let passkeySupport = true try { - passkeySupport = await PublicKeyCredential.isConditionalMediationAvailable() + passkeySupport = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() } catch (e) { passkeySupport = false console.error('Error checking passkey support:', e) diff --git a/src/app/[...recipient]/client.tsx b/src/app/[...recipient]/client.tsx index 810197c26..eada41455 100644 --- a/src/app/[...recipient]/client.tsx +++ b/src/app/[...recipient]/client.tsx @@ -6,6 +6,7 @@ import ConfirmPaymentView from '@/components/Payment/Views/Confirm.payment.view' import ValidationErrorView, { ValidationErrorViewProps } from '@/components/Payment/Views/Error.validation.view' import InitialPaymentView from '@/components/Payment/Views/Initial.payment.view' import DirectSuccessView from '@/components/Payment/Views/Status.payment.view' +import PintaReqPaySuccessView from '@/components/PintaReqPay/Views/Success.pinta.view' import PublicProfile from '@/components/Profile/components/PublicProfile' import { TransactionDetailsReceipt } from '@/components/TransactionDetails/TransactionDetailsReceipt' import { TransactionDetails } from '@/components/TransactionDetails/transactionTransformer' @@ -26,13 +27,11 @@ import { useEffect, useMemo, useRef, useState } from 'react' import { twMerge } from 'tailwind-merge' import { fetchTokenPrice } from '@/app/actions/tokens' import { GenericBanner } from '@/components/Global/Banner' -import { RequestFulfillmentBankFlowStep, useRequestFulfillmentFlow } from '@/context/RequestFulfillmentFlowContext' +import { useRequestFulfillmentFlow } from '@/context/RequestFulfillmentFlowContext' import ExternalWalletFulfilManager from '@/components/Request/views/ExternalWalletFulfilManager' import ActionList from '@/components/Common/ActionList' import NavHeader from '@/components/Global/NavHeader' import { ReqFulfillBankFlowManager } from '@/components/Request/views/ReqFulfillBankFlowManager' -import SupportCTA from '@/components/Global/SupportCTA' -import { BankRequestType, useDetermineBankRequestType } from '@/hooks/useDetermineBankRequestType' export type PaymentFlow = 'request_pay' | 'external_wallet' | 'direct_pay' | 'withdraw' interface Props { @@ -49,7 +48,7 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props) const [error, setError] = useState(null) const [isUrlParsed, setIsUrlParsed] = useState(false) const [isRequestDetailsFetching, setIsRequestDetailsFetching] = useState(false) - const { user, isFetchingUser } = useAuth() + const { user } = useAuth() const searchParams = useSearchParams() const chargeId = searchParams.get('chargeId') const requestId = searchParams.get('id') @@ -62,13 +61,7 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props) const [currencyAmount, setCurrencyAmount] = useState('') const { isDrawerOpen, selectedTransaction, openTransactionDetails } = useTransactionDetailsDrawer() const [isLinkCancelling, setisLinkCancelling] = useState(false) - const { - showExternalWalletFulfilMethods, - showRequestFulfilmentBankFlowManager, - setShowRequestFulfilmentBankFlowManager, - setFlowStep: setRequestFulfilmentBankFlowStep, - } = useRequestFulfillmentFlow() - const { requestType } = useDetermineBankRequestType(chargeDetails?.requestLink.recipientAccount.userId ?? '') + const { showExternalWalletFulfilMethods, showRequestFulfilmentBankFlowManager } = useRequestFulfillmentFlow() // determine if the current user is the recipient of the transaction const isCurrentUserRecipient = chargeDetails?.requestLink.recipientAccount?.userId === user?.user.userId @@ -346,7 +339,7 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props) amountDisplay: '$ 0.00', }, currency: usdAmount ? { amount: usdAmount, code: 'USD' } : undefined, - isVerified: counterparty?.user?.bridgeKycStatus === 'approved', + isVerified: counterparty?.user?.kycStatus === 'approved', haveSentMoneyToUser: counterparty?.userId ? interactions[counterparty.userId] || false : false, } @@ -391,21 +384,6 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props) } }, [transactionForDrawer, currentView, dispatch, openTransactionDetails, isExternalWalletFlow, chargeId]) - // Send to bank step if its mentioned in the URL and guest KYC is not needed - useEffect(() => { - const stepFromURL = searchParams.get('step') - if ( - parsedPaymentData && - chargeDetails && - requestType !== BankRequestType.GuestKycNeeded && - stepFromURL === 'bank' - ) { - setShowRequestFulfilmentBankFlowManager(true) - - setRequestFulfilmentBankFlowStep(RequestFulfillmentBankFlowStep.BankCountryList) - } - }, [searchParams, parsedPaymentData, chargeDetails, requestType]) - let showActionList = flow !== 'direct_pay' if (flow === 'direct_pay' && !user) { @@ -459,6 +437,19 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props) ) } + // pinta token payment flow + if (parsedPaymentData?.token?.symbol === 'PNT') { + return ( +
+
+ {currentView === 'INITIAL' && } + {currentView === 'CONFIRM' && } + {currentView === 'STATUS' && } +
+
+ ) + } + // default payment flow return (
{!user && parsedPaymentData?.recipient?.recipientType !== 'USERNAME' && ( @@ -504,6 +495,7 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props) {currentView === 'CONFIRM' && ( - {isDrawerOpen && selectedTransaction?.id === transactionForDrawer?.id ? ( + {parsedPaymentData?.token?.symbol === 'PNT' ? ( + + ) : isDrawerOpen && selectedTransaction?.id === transactionForDrawer?.id ? (
)} - - {/* Show only to guest users */} - {!user && !isFetchingUser && }
) } diff --git a/src/app/[...recipient]/error.tsx b/src/app/[...recipient]/error.tsx index 363fdd47d..194db40b7 100644 --- a/src/app/[...recipient]/error.tsx +++ b/src/app/[...recipient]/error.tsx @@ -3,11 +3,9 @@ import { Button, Card } from '@/components/0_Bruddle' import { useEffect } from 'react' import { useRouter } from 'next/navigation' -import { useSupportModalContext } from '@/context/SupportModalContext' export default function PaymentError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) { const router = useRouter() - const { setIsSupportModalOpen } = useSupportModalContext() useEffect(() => { console.error(error) @@ -25,7 +23,7 @@ export default function PaymentError({ error, reset }: { error: Error & { digest - diff --git a/src/app/actions/types/users.types.ts b/src/app/actions/types/users.types.ts index 79811164a..922384d86 100644 --- a/src/app/actions/types/users.types.ts +++ b/src/app/actions/types/users.types.ts @@ -9,7 +9,7 @@ export enum BridgeEndorsementType { export interface InitiateKycResponse { kycLink: string tosLink?: string - bridgeKycStatus: string + kycStatus: string tosStatus?: string error?: string // will be present on rejections reasons?: Array<{ diff --git a/src/app/api/auto-claim/route.ts b/src/app/api/auto-claim/route.ts deleted file mode 100644 index 7c00ad546..000000000 --- a/src/app/api/auto-claim/route.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server' -import { fetchWithSentry } from '@/utils' -import { PEANUT_API_URL } from '@/constants' - -/** - * API route for automated link claiming without requiring user interaction. - * - * This route serves as a workaround for Next.js server action limitations: - * Server actions cannot be directly called within useEffect hooks, which is - * necessary for our automatic claim flow. By exposing this as an API route - * instead, we can make the claim request safely from client-side effects. - */ -export async function POST(request: NextRequest) { - try { - const body = await request.json() - const { pubKey, recipient, password } = body - - if (!pubKey || !recipient || !password) { - return NextResponse.json( - { error: 'Missing required parameters: pubKey, recipient, or password' }, - { status: 400 } - ) - } - - const response = await fetchWithSentry(`${PEANUT_API_URL}/send-links/${pubKey}/claim`, { - method: 'POST', - headers: { - 'api-key': process.env.PEANUT_API_KEY!, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - recipient, - password, - }), - }) - - if (!response.ok) { - return NextResponse.json( - { error: `Failed to claim link: ${response.statusText}` }, - { status: response.status } - ) - } - - const responseText = await response.text() - console.log('response', responseText) - return new NextResponse(responseText, { - headers: { - 'Content-Type': 'application/json', - }, - }) - } catch (error) { - console.error('Error claiming send link:', error) - return NextResponse.json({ error: 'Failed to claim send link' }, { status: 500 }) - } -} diff --git a/src/app/api/health/backend/route.ts b/src/app/api/health/backend/route.ts index d6918afbc..3d1333455 100644 --- a/src/app/api/health/backend/route.ts +++ b/src/app/api/health/backend/route.ts @@ -2,6 +2,10 @@ import { NextResponse } from 'next/server' import { PEANUT_API_URL } from '@/constants' import { fetchWithSentry } from '@/utils' +export const dynamic = 'force-dynamic' +export const revalidate = 0 +export const fetchCache = 'force-no-store' + /** * Health check for Peanut API backend * Tests connectivity to the main peanut-api-ts backend service @@ -30,6 +34,8 @@ export async function GET() { headers: { 'Content-Type': 'application/json', }, + cache: 'no-store', + next: { revalidate: 0 }, }) const backendResponseTime = Date.now() - backendTestStart @@ -41,26 +47,37 @@ export async function GET() { const totalResponseTime = Date.now() - startTime - return NextResponse.json({ - status: 'healthy', - service: 'backend', - timestamp: new Date().toISOString(), - responseTime: totalResponseTime, - details: { - apiConnectivity: { - status: 'healthy', - responseTime: backendResponseTime, - httpStatus: backendResponse.status, - apiUrl: PEANUT_API_URL, - testEndpoint: '/users/username/hugo', - message: backendResponse.ok - ? 'Backend responding normally' - : backendResponse.status === 404 - ? 'Backend accessible (user not found as expected)' - : 'Backend accessible', + return NextResponse.json( + { + status: 'healthy', + service: 'backend', + timestamp: new Date().toISOString(), + responseTime: totalResponseTime, + details: { + apiConnectivity: { + status: 'healthy', + responseTime: backendResponseTime, + httpStatus: backendResponse.status, + apiUrl: PEANUT_API_URL, + testEndpoint: '/users/username/hugo', + message: backendResponse.ok + ? 'Backend responding normally' + : backendResponse.status === 404 + ? 'Backend accessible (user not found as expected)' + : 'Backend accessible', + }, }, }, - }) + { + status: 200, + headers: { + 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate', + Pragma: 'no-cache', + Expires: '0', + 'Surrogate-Control': 'no-store', + }, + } + ) } catch (error) { const totalResponseTime = Date.now() - startTime @@ -72,7 +89,15 @@ export async function GET() { error: error instanceof Error ? error.message : 'Unknown error', responseTime: totalResponseTime, }, - { status: 500 } + { + status: 500, + headers: { + 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate', + Pragma: 'no-cache', + Expires: '0', + 'Surrogate-Control': 'no-store', + }, + } ) } } diff --git a/src/app/api/health/route.ts b/src/app/api/health/route.ts index f26de8529..58309883a 100644 --- a/src/app/api/health/route.ts +++ b/src/app/api/health/route.ts @@ -1,6 +1,10 @@ import { NextResponse } from 'next/server' import { fetchWithSentry } from '@/utils' +export const dynamic = 'force-dynamic' +export const revalidate = 0 +export const fetchCache = 'force-no-store' + /** * Overall health check endpoint * Aggregates health status from all individual service health checks @@ -84,6 +88,8 @@ export async function GET() { headers: { 'Content-Type': 'application/json', }, + cache: 'no-store', + next: { revalidate: 0 }, }) if (!response.ok) { @@ -189,23 +195,42 @@ export async function GET() { // Send Discord notification asynchronously (don't await to avoid delaying the response) sendDiscordNotification(responseData).catch(console.error) - return NextResponse.json(responseData, { status: 500 }) + return NextResponse.json(responseData, { + status: 500, + headers: { + 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate', + Pragma: 'no-cache', + Expires: '0', + 'Surrogate-Control': 'no-store', + }, + }) } - return NextResponse.json({ - status: overallStatus, - service: 'peanut-protocol', - timestamp: new Date().toISOString(), - responseTime: totalResponseTime, - healthScore, - summary: results.summary, - services: results.services, - systemInfo: { - environment: process.env.NODE_ENV, - version: process.env.npm_package_version || 'unknown', - region: process.env.VERCEL_REGION || 'unknown', + return NextResponse.json( + { + status: overallStatus, + service: 'peanut-protocol', + timestamp: new Date().toISOString(), + responseTime: totalResponseTime, + healthScore, + summary: results.summary, + services: results.services, + systemInfo: { + environment: process.env.NODE_ENV, + version: process.env.npm_package_version || 'unknown', + region: process.env.VERCEL_REGION || 'unknown', + }, }, - }) + { + status: 200, + headers: { + 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate', + Pragma: 'no-cache', + Expires: '0', + 'Surrogate-Control': 'no-store', + }, + } + ) } catch (error) { const totalResponseTime = Date.now() - startTime @@ -218,7 +243,15 @@ export async function GET() { responseTime: totalResponseTime, healthScore: 0, }, - { status: 500 } + { + status: 500, + headers: { + 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate', + Pragma: 'no-cache', + Expires: '0', + 'Surrogate-Control': 'no-store', + }, + } ) } } diff --git a/src/app/api/peanut/user/update-user/route.ts b/src/app/api/peanut/user/update-user/route.ts index 99abbd366..3cfcd3cd3 100644 --- a/src/app/api/peanut/user/update-user/route.ts +++ b/src/app/api/peanut/user/update-user/route.ts @@ -1,5 +1,5 @@ import * as consts from '@/constants' -import { fetchWithSentry, BridgeKycStatus } from '@/utils' +import { fetchWithSentry, KYCStatus } from '@/utils' import { cookies } from 'next/headers' import { NextRequest, NextResponse } from 'next/server' @@ -7,7 +7,7 @@ type UserPayload = { userId: string username?: string bridge_customer_id?: string - bridgeKycStatus?: BridgeKycStatus + kycStatus?: KYCStatus telegramUsername?: string email?: string pushSubscriptionId?: string @@ -15,7 +15,7 @@ type UserPayload = { } export async function POST(request: NextRequest) { - const { userId, username, bridge_customer_id, bridgeKycStatus, telegram, email, pushSubscriptionId, fullName } = + const { userId, username, bridge_customer_id, kycStatus, telegram, email, pushSubscriptionId, fullName } = await request.json() const apiKey = process.env.PEANUT_API_KEY @@ -31,7 +31,7 @@ export async function POST(request: NextRequest) { userId, username, bridge_customer_id, - bridgeKycStatus: bridgeKycStatus, + kycStatus, } if (telegram) { diff --git a/src/assets/illustrations/index.ts b/src/assets/illustrations/index.ts index 88002e1ce..e04ba355b 100644 --- a/src/assets/illustrations/index.ts +++ b/src/assets/illustrations/index.ts @@ -6,7 +6,7 @@ export { default as Eyes } from './eyes.svg' export { default as HandThumbsUp } from './hand-thumbs-up.svg' export { default as HandToken } from './new-hand-token.svg' export { default as AboutPeanut } from './new-hero-description.svg' -//export { default as PeanutArmHoldingBeer } from './peanut-arm-holding-beer.svg' +export { default as PeanutArmHoldingBeer } from './peanut-arm-holding-beer.svg' export { default as PEANUT_LOGO_BLACK } from './peanut-logo-dark.svg' export { default as PeanutsBG } from './peanuts-bg.svg' export { default as Sparkle } from './sparkle.svg' diff --git a/src/assets/peanut/index.ts b/src/assets/peanut/index.ts index b447c6d76..67030828a 100644 --- a/src/assets/peanut/index.ts +++ b/src/assets/peanut/index.ts @@ -1,3 +1,4 @@ +export { default as PEANUTMAN_BEER } from './peanut-holding-beer.svg' export { default as PEANUTMAN_MOBILE } from './peanut-holding-mobile.svg' export { default as PEANUTMAN_PFP } from './peanut-pfp.svg' export { default as PEANUTMAN_RAISING_HANDS } from './peanut-raising-hands.svg' diff --git a/src/components/AddMoney/UserDetailsForm.tsx b/src/components/AddMoney/UserDetailsForm.tsx index 041d89e64..a1ace78f3 100644 --- a/src/components/AddMoney/UserDetailsForm.tsx +++ b/src/components/AddMoney/UserDetailsForm.tsx @@ -5,7 +5,8 @@ import BaseInput from '@/components/0_Bruddle/BaseInput' import ErrorAlert from '@/components/Global/ErrorAlert' export type UserDetailsFormData = { - fullName: string + firstName: string + lastName: string email: string } @@ -26,7 +27,8 @@ export const UserDetailsForm = forwardRef<{ handleSubmit: () => void }, UserDeta formState: { errors, isValid, isValidating }, } = useForm({ defaultValues: { - fullName: initialData?.fullName ?? '', + firstName: initialData?.firstName ?? '', + lastName: initialData?.lastName ?? '', email: initialData?.email ?? '', }, mode: 'onBlur', @@ -92,7 +94,8 @@ export const UserDetailsForm = forwardRef<{ handleSubmit: () => void }, UserDeta className="space-y-4" >
- {renderInput('fullName', 'Full Name', { required: 'Full name is required' })} + {renderInput('firstName', 'First Name', { required: 'First name is required' })} + {renderInput('lastName', 'Last Name', { required: 'Last name is required' })} {renderInput('email', 'E-mail', { required: 'Email is required', pattern: { diff --git a/src/components/AddMoney/consts/index.ts b/src/components/AddMoney/consts/index.ts index c4100d0d4..114b6fa45 100644 --- a/src/components/AddMoney/consts/index.ts +++ b/src/components/AddMoney/consts/index.ts @@ -144,7 +144,6 @@ export interface CountryData { description?: string path: string iso2?: string - iso3?: string } export interface DepositMethods extends CountryData { @@ -268,8 +267,6 @@ export const countryData: CountryData[] = [ title: 'Andorra', currency: 'EUR', path: 'andorra', - iso2: 'AD', - iso3: 'AND', }, { id: 'AE', @@ -277,8 +274,6 @@ export const countryData: CountryData[] = [ title: 'United Arab Emirates', currency: 'AED', path: 'united-arab-emirates', - iso2: 'AE', - iso3: 'ARE', }, { id: 'AG', @@ -286,8 +281,6 @@ export const countryData: CountryData[] = [ title: 'Antigua and Barbuda', currency: 'XCD', path: 'antigua-and-barbuda', - iso2: 'AG', - iso3: 'ATG', }, { id: 'AI', @@ -295,8 +288,6 @@ export const countryData: CountryData[] = [ title: 'Anguilla', currency: 'XCD', path: 'anguilla', - iso2: 'AI', - iso3: 'AIA', }, { id: 'AL', @@ -304,8 +295,6 @@ export const countryData: CountryData[] = [ title: 'Albania', currency: 'ALL', path: 'albania', - iso2: 'AL', - iso3: 'ALB', }, { id: 'AM', @@ -313,8 +302,6 @@ export const countryData: CountryData[] = [ title: 'Armenia', currency: 'AMD', path: 'armenia', - iso2: 'AM', - iso3: 'ARM', }, { id: 'AO', @@ -322,8 +309,6 @@ export const countryData: CountryData[] = [ title: 'Angola', currency: 'AOA', path: 'angola', - iso2: 'AO', - iso3: 'AGO', }, { id: 'AQ', @@ -331,8 +316,6 @@ export const countryData: CountryData[] = [ title: 'Antarctica', currency: '', path: 'antarctica', - iso2: 'AQ', - iso3: 'ATA', }, { id: 'AR', @@ -340,8 +323,6 @@ export const countryData: CountryData[] = [ title: 'Argentina', currency: 'ARS', path: 'argentina', - iso2: 'AR', - iso3: 'ARG', }, { id: 'AS', @@ -349,8 +330,6 @@ export const countryData: CountryData[] = [ title: 'American Samoa', currency: 'USD', path: 'american-samoa', - iso2: 'AS', - iso3: 'ASM', }, { id: 'AUT', @@ -358,8 +337,6 @@ export const countryData: CountryData[] = [ title: 'Austria', currency: 'EUR', path: 'austria', - iso2: 'AT', - iso3: 'AUT', }, { id: 'AU', @@ -367,8 +344,6 @@ export const countryData: CountryData[] = [ title: 'Australia', currency: 'AUD', path: 'australia', - iso2: 'AU', - iso3: 'AUS', }, { id: 'AW', @@ -376,8 +351,6 @@ export const countryData: CountryData[] = [ title: 'Aruba', currency: 'AWG', path: 'aruba', - iso2: 'AW', - iso3: 'ABW', }, { id: 'ALA', @@ -385,8 +358,6 @@ export const countryData: CountryData[] = [ title: 'Åland', currency: 'EUR', path: 'aland', - iso2: 'AX', - iso3: 'ALA', }, { id: 'AZ', @@ -394,8 +365,6 @@ export const countryData: CountryData[] = [ title: 'Azerbaijan', currency: 'AZN', path: 'azerbaijan', - iso2: 'AZ', - iso3: 'AZE', }, { id: 'BA', @@ -403,8 +372,6 @@ export const countryData: CountryData[] = [ title: 'Bosnia and Herzegovina', currency: 'BAM', path: 'bosnia-and-herzegovina', - iso2: 'BA', - iso3: 'BIH', }, { id: 'BB', @@ -412,8 +379,6 @@ export const countryData: CountryData[] = [ title: 'Barbados', currency: 'BBD', path: 'barbados', - iso2: 'BB', - iso3: 'BRB', }, { id: 'BD', @@ -421,8 +386,6 @@ export const countryData: CountryData[] = [ title: 'Bangladesh', currency: 'BDT', path: 'bangladesh', - iso2: 'BD', - iso3: 'BGD', }, { id: 'BEL', @@ -430,8 +393,6 @@ export const countryData: CountryData[] = [ title: 'Belgium', currency: 'EUR', path: 'belgium', - iso2: 'BE', - iso3: 'BEL', }, { id: 'BF', @@ -439,8 +400,6 @@ export const countryData: CountryData[] = [ title: 'Burkina Faso', currency: 'XOF', path: 'burkina-faso', - iso2: 'BF', - iso3: 'BFA', }, { id: 'BGR', @@ -448,8 +407,6 @@ export const countryData: CountryData[] = [ title: 'Bulgaria', currency: 'BGN', path: 'bulgaria', - iso2: 'BG', - iso3: 'BGR', }, { id: 'BH', @@ -457,8 +414,6 @@ export const countryData: CountryData[] = [ title: 'Bahrain', currency: 'BHD', path: 'bahrain', - iso2: 'BH', - iso3: 'BHR', }, { id: 'BI', @@ -466,8 +421,6 @@ export const countryData: CountryData[] = [ title: 'Burundi', currency: 'BIF', path: 'burundi', - iso2: 'BI', - iso3: 'BDI', }, { id: 'BJ', @@ -475,8 +428,6 @@ export const countryData: CountryData[] = [ title: 'Benin', currency: 'XOF', path: 'benin', - iso2: 'BJ', - iso3: 'BEN', }, { id: 'BL', @@ -484,8 +435,6 @@ export const countryData: CountryData[] = [ title: 'Saint Barthélemy', currency: 'EUR', path: 'saint-barthélemy', - iso2: 'BL', - iso3: 'BLM', }, { id: 'BM', @@ -493,8 +442,6 @@ export const countryData: CountryData[] = [ title: 'Bermuda', currency: 'BMD', path: 'bermuda', - iso2: 'BM', - iso3: 'BMU', }, { id: 'BN', @@ -502,8 +449,6 @@ export const countryData: CountryData[] = [ title: 'Brunei', currency: 'BND', path: 'brunei', - iso2: 'BN', - iso3: 'BRN', }, { id: 'BO', @@ -511,8 +456,6 @@ export const countryData: CountryData[] = [ title: 'Bolivia', currency: 'BOB', path: 'bolivia', - iso2: 'BO', - iso3: 'BOL', }, { id: 'BQ', @@ -520,8 +463,6 @@ export const countryData: CountryData[] = [ title: 'Bonaire', currency: 'USD', path: 'bonaire', - iso2: 'BQ', - iso3: 'BES', }, { id: 'BR', @@ -529,8 +470,6 @@ export const countryData: CountryData[] = [ title: 'Brazil', currency: 'BRL', path: 'brazil', - iso2: 'BR', - iso3: 'BRA', }, { id: 'BS', @@ -538,8 +477,6 @@ export const countryData: CountryData[] = [ title: 'Bahamas', currency: 'BSD', path: 'bahamas', - iso2: 'BS', - iso3: 'BHS', }, { id: 'BT', @@ -547,8 +484,6 @@ export const countryData: CountryData[] = [ title: 'Bhutan', currency: 'BTN', path: 'bhutan', - iso2: 'BT', - iso3: 'BTN', }, { id: 'BV', @@ -556,8 +491,6 @@ export const countryData: CountryData[] = [ title: 'Bouvet Island', currency: 'NOK', path: 'bouvet-island', - iso2: 'BV', - iso3: 'BVT', }, { id: 'BW', @@ -565,8 +498,6 @@ export const countryData: CountryData[] = [ title: 'Botswana', currency: 'BWP', path: 'botswana', - iso2: 'BW', - iso3: 'BWA', }, { id: 'BZ', @@ -574,8 +505,6 @@ export const countryData: CountryData[] = [ title: 'Belize', currency: 'BZD', path: 'belize', - iso2: 'BZ', - iso3: 'BLZ', }, { id: 'CA', @@ -583,8 +512,6 @@ export const countryData: CountryData[] = [ title: 'Canada', currency: 'CAD', path: 'canada', - iso2: 'CA', - iso3: 'CAN', }, { id: 'CC', @@ -592,8 +519,6 @@ export const countryData: CountryData[] = [ title: 'Cocos (Keeling) Islands', currency: 'AUD', path: 'cocos-keeling-islands', - iso2: 'CC', - iso3: 'CCK', }, { id: 'CD', @@ -601,8 +526,6 @@ export const countryData: CountryData[] = [ title: 'Democratic Republic of the Congo', currency: 'CDF', path: 'democratic-republic-of-the-congo', - iso2: 'CD', - iso3: 'COD', }, { id: 'CF', @@ -610,8 +533,6 @@ export const countryData: CountryData[] = [ title: 'Central African Republic', currency: 'XAF', path: 'central-african-republic', - iso2: 'CF', - iso3: 'CAF', }, { id: 'CG', @@ -619,8 +540,6 @@ export const countryData: CountryData[] = [ title: 'Republic of the Congo', currency: 'XAF', path: 'republic-of-the-congo', - iso2: 'CG', - iso3: 'COG', }, { id: 'CHE', @@ -628,8 +547,6 @@ export const countryData: CountryData[] = [ title: 'Switzerland', currency: 'CHF', path: 'switzerland', - iso2: 'CH', - iso3: 'CHE', }, { id: 'CI', @@ -637,8 +554,6 @@ export const countryData: CountryData[] = [ title: 'Ivory Coast', currency: 'XOF', path: 'ivory-coast', - iso2: 'CI', - iso3: 'CIV', }, { id: 'CK', @@ -646,8 +561,6 @@ export const countryData: CountryData[] = [ title: 'Cook Islands', currency: 'NZD', path: 'cook-islands', - iso2: 'CK', - iso3: 'COK', }, { id: 'CL', @@ -655,8 +568,6 @@ export const countryData: CountryData[] = [ title: 'Chile', currency: 'CLP', path: 'chile', - iso2: 'CL', - iso3: 'CHL', }, { id: 'CM', @@ -664,8 +575,6 @@ export const countryData: CountryData[] = [ title: 'Cameroon', currency: 'XAF', path: 'cameroon', - iso2: 'CM', - iso3: 'CMR', }, { id: 'CN', @@ -673,8 +582,6 @@ export const countryData: CountryData[] = [ title: 'China', currency: 'CNY', path: 'china', - iso2: 'CN', - iso3: 'CHN', }, { id: 'CO', @@ -682,8 +589,6 @@ export const countryData: CountryData[] = [ title: 'Colombia', currency: 'COP', path: 'colombia', - iso2: 'CO', - iso3: 'COL', }, { id: 'CR', @@ -691,8 +596,6 @@ export const countryData: CountryData[] = [ title: 'Costa Rica', currency: 'CRC', path: 'costa-rica', - iso2: 'CR', - iso3: 'CRI', }, { id: 'CV', @@ -700,8 +603,6 @@ export const countryData: CountryData[] = [ title: 'Cape Verde', currency: 'CVE', path: 'cape-verde', - iso2: 'CV', - iso3: 'CPV', }, { id: 'CW', @@ -709,8 +610,6 @@ export const countryData: CountryData[] = [ title: 'Curacao', currency: 'ANG', path: 'curacao', - iso2: 'CW', - iso3: 'CUW', }, { id: 'CX', @@ -718,8 +617,6 @@ export const countryData: CountryData[] = [ title: 'Christmas Island', currency: 'AUD', path: 'christmas-island', - iso2: 'CX', - iso3: 'CXR', }, { id: 'CYP', @@ -727,8 +624,6 @@ export const countryData: CountryData[] = [ title: 'Cyprus', currency: 'EUR', path: 'cyprus', - iso2: 'CY', - iso3: 'CYP', }, { id: 'CZE', @@ -736,8 +631,6 @@ export const countryData: CountryData[] = [ title: 'Czechia', currency: 'CZK', path: 'czechia', - iso2: 'CZ', - iso3: 'CZE', }, { id: 'DEU', @@ -745,8 +638,6 @@ export const countryData: CountryData[] = [ title: 'Germany', currency: 'EUR', path: 'germany', - iso2: 'DE', - iso3: 'DEU', }, { id: 'DJ', @@ -754,8 +645,6 @@ export const countryData: CountryData[] = [ title: 'Djibouti', currency: 'DJF', path: 'djibouti', - iso2: 'DJ', - iso3: 'DJI', }, { id: 'DNK', @@ -763,8 +652,6 @@ export const countryData: CountryData[] = [ title: 'Denmark', currency: 'DKK', path: 'denmark', - iso2: 'DK', - iso3: 'DNK', }, { id: 'DM', @@ -772,8 +659,6 @@ export const countryData: CountryData[] = [ title: 'Dominica', currency: 'XCD', path: 'dominica', - iso2: 'DM', - iso3: 'DMA', }, { id: 'DO', @@ -781,8 +666,6 @@ export const countryData: CountryData[] = [ title: 'Dominican Republic', currency: 'DOP', path: 'dominican-republic', - iso2: 'DO', - iso3: 'DOM', }, { id: 'DZ', @@ -790,8 +673,6 @@ export const countryData: CountryData[] = [ title: 'Algeria', currency: 'DZD', path: 'algeria', - iso2: 'DZ', - iso3: 'DZA', }, { id: 'EC', @@ -799,8 +680,6 @@ export const countryData: CountryData[] = [ title: 'Ecuador', currency: 'USD', path: 'ecuador', - iso2: 'EC', - iso3: 'ECU', }, { id: 'EST', @@ -808,8 +687,6 @@ export const countryData: CountryData[] = [ title: 'Estonia', currency: 'EUR', path: 'estonia', - iso2: 'EE', - iso3: 'EST', }, { id: 'EG', @@ -817,8 +694,6 @@ export const countryData: CountryData[] = [ title: 'Egypt', currency: 'EGP', path: 'egypt', - iso2: 'EG', - iso3: 'EGY', }, { id: 'EH', @@ -826,8 +701,6 @@ export const countryData: CountryData[] = [ title: 'Western Sahara', currency: 'MAD', path: 'western-sahara', - iso2: 'EH', - iso3: 'ESH', }, { id: 'ER', @@ -835,8 +708,6 @@ export const countryData: CountryData[] = [ title: 'Eritrea', currency: 'ERN', path: 'eritrea', - iso2: 'ER', - iso3: 'ERI', }, { id: 'ESP', @@ -844,8 +715,6 @@ export const countryData: CountryData[] = [ title: 'Spain', currency: 'EUR', path: 'spain', - iso2: 'ES', - iso3: 'ESP', }, { id: 'ET', @@ -853,8 +722,6 @@ export const countryData: CountryData[] = [ title: 'Ethiopia', currency: 'ETB', path: 'ethiopia', - iso2: 'ET', - iso3: 'ETH', }, { id: 'FIN', @@ -862,8 +729,6 @@ export const countryData: CountryData[] = [ title: 'Finland', currency: 'EUR', path: 'finland', - iso2: 'FI', - iso3: 'FIN', }, { id: 'FJ', @@ -871,8 +736,6 @@ export const countryData: CountryData[] = [ title: 'Fiji', currency: 'FJD', path: 'fiji', - iso2: 'FJ', - iso3: 'FJI', }, { id: 'FK', @@ -880,8 +743,6 @@ export const countryData: CountryData[] = [ title: 'Falkland Islands', currency: 'FKP', path: 'falkland-islands', - iso2: 'FK', - iso3: 'FLK', }, { id: 'FM', @@ -889,8 +750,6 @@ export const countryData: CountryData[] = [ title: 'Micronesia', currency: 'USD', path: 'micronesia', - iso2: 'FM', - iso3: 'FSM', }, { id: 'FO', @@ -898,8 +757,6 @@ export const countryData: CountryData[] = [ title: 'Faroe Islands', currency: 'DKK', path: 'faroe-islands', - iso2: 'FO', - iso3: 'FRO', }, { id: 'FRA', @@ -907,8 +764,6 @@ export const countryData: CountryData[] = [ title: 'France', currency: 'EUR', path: 'france', - iso2: 'FR', - iso3: 'FRA', }, { id: 'GA', @@ -916,8 +771,6 @@ export const countryData: CountryData[] = [ title: 'Gabon', currency: 'XAF', path: 'gabon', - iso2: 'GA', - iso3: 'GAB', }, { id: 'GBR', @@ -926,7 +779,6 @@ export const countryData: CountryData[] = [ currency: 'GBP', path: 'united-kingdom', iso2: 'GB', - iso3: 'GBR', }, { id: 'GD', @@ -934,8 +786,6 @@ export const countryData: CountryData[] = [ title: 'Grenada', currency: 'XCD', path: 'grenada', - iso2: 'GD', - iso3: 'GRD', }, { id: 'GE', @@ -943,8 +793,6 @@ export const countryData: CountryData[] = [ title: 'Georgia', currency: 'GEL', path: 'georgia', - iso2: 'GE', - iso3: 'GEO', }, { id: 'GUF', @@ -952,8 +800,6 @@ export const countryData: CountryData[] = [ title: 'French Guiana', currency: 'EUR', path: 'french-guiana', - iso2: 'GF', - iso3: 'GUF', }, { id: 'GG', @@ -961,8 +807,6 @@ export const countryData: CountryData[] = [ title: 'Guernsey', currency: 'GBP', path: 'guernsey', - iso2: 'GG', - iso3: 'GGY', }, { id: 'GH', @@ -970,8 +814,6 @@ export const countryData: CountryData[] = [ title: 'Ghana', currency: 'GHS', path: 'ghana', - iso2: 'GH', - iso3: 'GHA', }, { id: 'GI', @@ -979,8 +821,6 @@ export const countryData: CountryData[] = [ title: 'Gibraltar', currency: 'GIP', path: 'gibraltar', - iso2: 'GI', - iso3: 'GIB', }, { id: 'GL', @@ -988,8 +828,6 @@ export const countryData: CountryData[] = [ title: 'Greenland', currency: 'DKK', path: 'greenland', - iso2: 'GL', - iso3: 'GRL', }, { id: 'GM', @@ -997,8 +835,6 @@ export const countryData: CountryData[] = [ title: 'Gambia', currency: 'GMD', path: 'gambia', - iso2: 'GM', - iso3: 'GMB', }, { id: 'GN', @@ -1006,8 +842,6 @@ export const countryData: CountryData[] = [ title: 'Guinea', currency: 'GNF', path: 'guinea', - iso2: 'GN', - iso3: 'GIN', }, { id: 'GP', @@ -1015,8 +849,6 @@ export const countryData: CountryData[] = [ title: 'Guadeloupe', currency: 'EUR', path: 'guadeloupe', - iso2: 'GP', - iso3: 'GLP', }, { id: 'GQ', @@ -1024,8 +856,6 @@ export const countryData: CountryData[] = [ title: 'Equatorial Guinea', currency: 'XAF', path: 'equatorial-guinea', - iso2: 'GQ', - iso3: 'GNQ', }, { id: 'GR', @@ -1033,8 +863,6 @@ export const countryData: CountryData[] = [ title: 'Greece', currency: 'EUR', path: 'greece', - iso2: 'GR', - iso3: 'GRC', }, { id: 'GS', @@ -1042,8 +870,6 @@ export const countryData: CountryData[] = [ title: 'South Georgia and the South Sandwich Islands', currency: 'GBP', path: 'south-georgia-and-the-south-sandwich-islands', - iso2: 'GS', - iso3: 'SGS', }, { id: 'GT', @@ -1051,8 +877,6 @@ export const countryData: CountryData[] = [ title: 'Guatemala', currency: 'GTQ', path: 'guatemala', - iso2: 'GT', - iso3: 'GTM', }, { id: 'GU', @@ -1060,8 +884,6 @@ export const countryData: CountryData[] = [ title: 'Guam', currency: 'USD', path: 'guam', - iso2: 'GU', - iso3: 'GUM', }, { id: 'GW', @@ -1069,8 +891,6 @@ export const countryData: CountryData[] = [ title: 'Guinea-Bissau', currency: 'XOF', path: 'guinea-bissau', - iso2: 'GW', - iso3: 'GNB', }, { id: 'GY', @@ -1078,8 +898,6 @@ export const countryData: CountryData[] = [ title: 'Guyana', currency: 'GYD', path: 'guyana', - iso2: 'GY', - iso3: 'GUY', }, { id: 'HK', @@ -1087,8 +905,6 @@ export const countryData: CountryData[] = [ title: 'Hong Kong', currency: 'HKD', path: 'hong-kong', - iso2: 'HK', - iso3: 'HKG', }, { id: 'HM', @@ -1096,8 +912,6 @@ export const countryData: CountryData[] = [ title: 'Heard Island and McDonald Islands', currency: 'AUD', path: 'heard-island-and-mcdonald-islands', - iso2: 'HM', - iso3: 'HMD', }, { id: 'HN', @@ -1105,8 +919,6 @@ export const countryData: CountryData[] = [ title: 'Honduras', currency: 'HNL', path: 'honduras', - iso2: 'HN', - iso3: 'HND', }, { id: 'HRV', @@ -1114,8 +926,6 @@ export const countryData: CountryData[] = [ title: 'Croatia', currency: 'EUR', path: 'croatia', - iso2: 'HR', - iso3: 'HRV', }, { id: 'HT', @@ -1123,8 +933,6 @@ export const countryData: CountryData[] = [ title: 'Haiti', currency: 'HTG', path: 'haiti', - iso2: 'HT', - iso3: 'HTI', }, { id: 'HUN', @@ -1132,8 +940,6 @@ export const countryData: CountryData[] = [ title: 'Hungary', currency: 'HUF', path: 'hungary', - iso2: 'HU', - iso3: 'HUN', }, { id: 'ID', @@ -1141,8 +947,6 @@ export const countryData: CountryData[] = [ title: 'Indonesia', currency: 'IDR', path: 'indonesia', - iso2: 'ID', - iso3: 'IDN', }, { id: 'IRL', @@ -1150,8 +954,6 @@ export const countryData: CountryData[] = [ title: 'Ireland', currency: 'EUR', path: 'ireland', - iso2: 'IE', - iso3: 'IRL', }, { id: 'IL', @@ -1159,8 +961,6 @@ export const countryData: CountryData[] = [ title: 'Israel', currency: 'ILS', path: 'israel', - iso2: 'IL', - iso3: 'ISR', }, { id: 'IM', @@ -1168,8 +968,6 @@ export const countryData: CountryData[] = [ title: 'Isle of Man', currency: 'GBP', path: 'isle-of-man', - iso2: 'IM', - iso3: 'IMN', }, { id: 'IN', @@ -1177,8 +975,6 @@ export const countryData: CountryData[] = [ title: 'India', currency: 'INR', path: 'india', - iso2: 'IN', - iso3: 'IND', }, { id: 'IO', @@ -1186,8 +982,6 @@ export const countryData: CountryData[] = [ title: 'British Indian Ocean Territory', currency: 'USD', path: 'british-indian-ocean-territory', - iso2: 'IO', - iso3: 'IOT', }, { id: 'ISL', @@ -1195,8 +989,6 @@ export const countryData: CountryData[] = [ title: 'Iceland', currency: 'ISK', path: 'iceland', - iso2: 'IS', - iso3: 'ISL', }, { id: 'ITA', @@ -1204,8 +996,6 @@ export const countryData: CountryData[] = [ title: 'Italy', currency: 'EUR', path: 'italy', - iso2: 'IT', - iso3: 'ITA', }, { id: 'JE', @@ -1213,8 +1003,6 @@ export const countryData: CountryData[] = [ title: 'Jersey', currency: 'GBP', path: 'jersey', - iso2: 'JE', - iso3: 'JEY', }, { id: 'JM', @@ -1222,8 +1010,6 @@ export const countryData: CountryData[] = [ title: 'Jamaica', currency: 'JMD', path: 'jamaica', - iso2: 'JM', - iso3: 'JAM', }, { id: 'JO', @@ -1231,8 +1017,6 @@ export const countryData: CountryData[] = [ title: 'Jordan', currency: 'JOD', path: 'jordan', - iso2: 'JO', - iso3: 'JOR', }, { id: 'JP', @@ -1240,8 +1024,6 @@ export const countryData: CountryData[] = [ title: 'Japan', currency: 'JPY', path: 'japan', - iso2: 'JP', - iso3: 'JPN', }, { id: 'KE', @@ -1249,8 +1031,6 @@ export const countryData: CountryData[] = [ title: 'Kenya', currency: 'KES', path: 'kenya', - iso2: 'KE', - iso3: 'KEN', }, { id: 'KG', @@ -1258,8 +1038,6 @@ export const countryData: CountryData[] = [ title: 'Kyrgyzstan', currency: 'KGS', path: 'kyrgyzstan', - iso2: 'KG', - iso3: 'KGZ', }, { id: 'KH', @@ -1267,8 +1045,6 @@ export const countryData: CountryData[] = [ title: 'Cambodia', currency: 'KHR', path: 'cambodia', - iso2: 'KH', - iso3: 'KHM', }, { id: 'KI', @@ -1276,8 +1052,6 @@ export const countryData: CountryData[] = [ title: 'Kiribati', currency: 'AUD', path: 'kiribati', - iso2: 'KI', - iso3: 'KIR', }, { id: 'KM', @@ -1285,8 +1059,6 @@ export const countryData: CountryData[] = [ title: 'Comoros', currency: 'KMF', path: 'comoros', - iso2: 'KM', - iso3: 'COM', }, { id: 'KN', @@ -1294,8 +1066,6 @@ export const countryData: CountryData[] = [ title: 'Saint Kitts and Nevis', currency: 'XCD', path: 'saint-kitts-and-nevis', - iso2: 'KN', - iso3: 'KNA', }, { id: 'KR', @@ -1303,8 +1073,6 @@ export const countryData: CountryData[] = [ title: 'South Korea', currency: 'KRW', path: 'south-korea', - iso2: 'KR', - iso3: 'KOR', }, { id: 'KW', @@ -1312,8 +1080,6 @@ export const countryData: CountryData[] = [ title: 'Kuwait', currency: 'KWD', path: 'kuwait', - iso2: 'KW', - iso3: 'KWT', }, { id: 'KY', @@ -1321,8 +1087,6 @@ export const countryData: CountryData[] = [ title: 'Cayman Islands', currency: 'KYD', path: 'cayman-islands', - iso2: 'KY', - iso3: 'CYM', }, { id: 'KZ', @@ -1330,8 +1094,6 @@ export const countryData: CountryData[] = [ title: 'Kazakhstan', currency: 'KZT', path: 'kazakhstan', - iso2: 'KZ', - iso3: 'KAZ', }, { id: 'LA', @@ -1339,8 +1101,6 @@ export const countryData: CountryData[] = [ title: 'Laos', currency: 'LAK', path: 'laos', - iso2: 'LA', - iso3: 'LAO', }, { id: 'LB', @@ -1348,8 +1108,6 @@ export const countryData: CountryData[] = [ title: 'Lebanon', currency: 'LBP', path: 'lebanon', - iso2: 'LB', - iso3: 'LBN', }, { id: 'LC', @@ -1357,8 +1115,6 @@ export const countryData: CountryData[] = [ title: 'Saint Lucia', currency: 'XCD', path: 'saint-lucia', - iso2: 'LC', - iso3: 'LCA', }, { id: 'LI', @@ -1366,8 +1122,6 @@ export const countryData: CountryData[] = [ title: 'Liechtenstein', currency: 'CHF', path: 'liechtenstein', - iso2: 'LI', - iso3: 'LIE', }, { id: 'LK', @@ -1375,8 +1129,6 @@ export const countryData: CountryData[] = [ title: 'Sri Lanka', currency: 'LKR', path: 'sri-lanka', - iso2: 'LK', - iso3: 'LKA', }, { id: 'LR', @@ -1384,8 +1136,6 @@ export const countryData: CountryData[] = [ title: 'Liberia', currency: 'LRD', path: 'liberia', - iso2: 'LR', - iso3: 'LBR', }, { id: 'LS', @@ -1393,8 +1143,6 @@ export const countryData: CountryData[] = [ title: 'Lesotho', currency: 'LSL', path: 'lesotho', - iso2: 'LS', - iso3: 'LSO', }, { id: 'LTU', @@ -1402,8 +1150,6 @@ export const countryData: CountryData[] = [ title: 'Lithuania', currency: 'EUR', path: 'lithuania', - iso2: 'LT', - iso3: 'LTU', }, { id: 'LUX', @@ -1411,8 +1157,6 @@ export const countryData: CountryData[] = [ title: 'Luxembourg', currency: 'EUR', path: 'luxembourg', - iso2: 'LU', - iso3: 'LUX', }, { id: 'LVA', @@ -1420,8 +1164,6 @@ export const countryData: CountryData[] = [ title: 'Latvia', currency: 'EUR', path: 'latvia', - iso2: 'LV', - iso3: 'LVA', }, { id: 'LY', @@ -1429,8 +1171,6 @@ export const countryData: CountryData[] = [ title: 'Libya', currency: 'LYD', path: 'libya', - iso2: 'LY', - iso3: 'LBY', }, { id: 'MA', @@ -1438,8 +1178,6 @@ export const countryData: CountryData[] = [ title: 'Morocco', currency: 'MAD', path: 'morocco', - iso2: 'MA', - iso3: 'MAR', }, { id: 'MC', @@ -1447,8 +1185,6 @@ export const countryData: CountryData[] = [ title: 'Monaco', currency: 'EUR', path: 'monaco', - iso2: 'MC', - iso3: 'MCO', }, { id: 'MD', @@ -1456,8 +1192,6 @@ export const countryData: CountryData[] = [ title: 'Moldova', currency: 'MDL', path: 'moldova', - iso2: 'MD', - iso3: 'MDA', }, { id: 'ME', @@ -1465,8 +1199,6 @@ export const countryData: CountryData[] = [ title: 'Montenegro', currency: 'EUR', path: 'montenegro', - iso2: 'ME', - iso3: 'MNE', }, { id: 'MAF', @@ -1474,8 +1206,6 @@ export const countryData: CountryData[] = [ title: 'Saint Martin', currency: 'EUR', path: 'saint-martin', - iso2: 'MF', - iso3: 'MAF', }, { id: 'MG', @@ -1483,8 +1213,6 @@ export const countryData: CountryData[] = [ title: 'Madagascar', currency: 'MGA', path: 'madagascar', - iso2: 'MG', - iso3: 'MDG', }, { id: 'MH', @@ -1492,8 +1220,6 @@ export const countryData: CountryData[] = [ title: 'Marshall Islands', currency: 'USD', path: 'marshall-islands', - iso2: 'MH', - iso3: 'MHL', }, { id: 'MK', @@ -1501,8 +1227,6 @@ export const countryData: CountryData[] = [ title: 'Macedonia', currency: 'MKD', path: 'macedonia', - iso2: 'MK', - iso3: 'MKD', }, { id: 'ML', @@ -1510,8 +1234,6 @@ export const countryData: CountryData[] = [ title: 'Mali', currency: 'XOF', path: 'mali', - iso2: 'ML', - iso3: 'MLI', }, { id: 'MN', @@ -1519,8 +1241,6 @@ export const countryData: CountryData[] = [ title: 'Mongolia', currency: 'MNT', path: 'mongolia', - iso2: 'MN', - iso3: 'MNG', }, { id: 'MO', @@ -1528,8 +1248,6 @@ export const countryData: CountryData[] = [ title: 'Macao', currency: 'MOP', path: 'macao', - iso2: 'MO', - iso3: 'MAC', }, { id: 'MP', @@ -1537,8 +1255,6 @@ export const countryData: CountryData[] = [ title: 'Northern Mariana Islands', currency: 'USD', path: 'northern-mariana-islands', - iso2: 'MP', - iso3: 'MNP', }, { id: 'MTQ', @@ -1546,8 +1262,6 @@ export const countryData: CountryData[] = [ title: 'Martinique', currency: 'EUR', path: 'martinique', - iso2: 'MQ', - iso3: 'MTQ', }, { id: 'MR', @@ -1555,8 +1269,6 @@ export const countryData: CountryData[] = [ title: 'Mauritania', currency: 'MRU', path: 'mauritania', - iso2: 'MR', - iso3: 'MRT', }, { id: 'MS', @@ -1564,8 +1276,6 @@ export const countryData: CountryData[] = [ title: 'Montserrat', currency: 'XCD', path: 'montserrat', - iso2: 'MS', - iso3: 'MSR', }, { id: 'MLT', @@ -1573,8 +1283,6 @@ export const countryData: CountryData[] = [ title: 'Malta', currency: 'EUR', path: 'malta', - iso2: 'MT', - iso3: 'MLT', }, { id: 'MU', @@ -1582,8 +1290,6 @@ export const countryData: CountryData[] = [ title: 'Mauritius', currency: 'MUR', path: 'mauritius', - iso2: 'MU', - iso3: 'MUS', }, { id: 'MV', @@ -1591,8 +1297,6 @@ export const countryData: CountryData[] = [ title: 'Maldives', currency: 'MVR', path: 'maldives', - iso2: 'MV', - iso3: 'MDV', }, { id: 'MW', @@ -1600,8 +1304,6 @@ export const countryData: CountryData[] = [ title: 'Malawi', currency: 'MWK', path: 'malawi', - iso2: 'MW', - iso3: 'MWI', }, { id: 'MX', @@ -1609,8 +1311,6 @@ export const countryData: CountryData[] = [ title: 'Mexico', currency: 'MXN', path: 'mexico', - iso2: 'MX', - iso3: 'MEX', }, { id: 'MY', @@ -1618,8 +1318,6 @@ export const countryData: CountryData[] = [ title: 'Malaysia', currency: 'MYR', path: 'malaysia', - iso2: 'MY', - iso3: 'MYS', }, { id: 'MZ', @@ -1627,8 +1325,6 @@ export const countryData: CountryData[] = [ title: 'Mozambique', currency: 'MZN', path: 'mozambique', - iso2: 'MZ', - iso3: 'MOZ', }, { id: 'NA', @@ -1636,8 +1332,6 @@ export const countryData: CountryData[] = [ title: 'Namibia', currency: 'NAD', path: 'namibia', - iso2: 'NA', - iso3: 'NAM', }, { id: 'NC', @@ -1645,8 +1339,6 @@ export const countryData: CountryData[] = [ title: 'New Caledonia', currency: 'XPF', path: 'new-caledonia', - iso2: 'NC', - iso3: 'NCL', }, { id: 'NE', @@ -1654,8 +1346,6 @@ export const countryData: CountryData[] = [ title: 'Niger', currency: 'XOF', path: 'niger', - iso2: 'NE', - iso3: 'NER', }, { id: 'NF', @@ -1663,8 +1353,6 @@ export const countryData: CountryData[] = [ title: 'Norfolk Island', currency: 'AUD', path: 'norfolk-island', - iso2: 'NF', - iso3: 'NFK', }, { id: 'NG', @@ -1672,8 +1360,6 @@ export const countryData: CountryData[] = [ title: 'Nigeria', currency: 'NGN', path: 'nigeria', - iso2: 'NG', - iso3: 'NGA', }, { id: 'NI', @@ -1681,8 +1367,6 @@ export const countryData: CountryData[] = [ title: 'Nicaragua', currency: 'NIO', path: 'nicaragua', - iso2: 'NI', - iso3: 'NIC', }, { id: 'NLD', @@ -1690,8 +1374,6 @@ export const countryData: CountryData[] = [ title: 'Netherlands', currency: 'EUR', path: 'netherlands', - iso2: 'NL', - iso3: 'NLD', }, { id: 'NOR', @@ -1699,8 +1381,6 @@ export const countryData: CountryData[] = [ title: 'Norway', currency: 'NOK', path: 'norway', - iso2: 'NO', - iso3: 'NOR', }, { id: 'NP', @@ -1708,8 +1388,6 @@ export const countryData: CountryData[] = [ title: 'Nepal', currency: 'NPR', path: 'nepal', - iso2: 'NP', - iso3: 'NPL', }, { id: 'NR', @@ -1717,8 +1395,6 @@ export const countryData: CountryData[] = [ title: 'Nauru', currency: 'AUD', path: 'nauru', - iso2: 'NR', - iso3: 'NRU', }, { id: 'NU', @@ -1726,8 +1402,6 @@ export const countryData: CountryData[] = [ title: 'Niue', currency: 'NZD', path: 'niue', - iso2: 'NU', - iso3: 'NIU', }, { id: 'NZ', @@ -1735,8 +1409,6 @@ export const countryData: CountryData[] = [ title: 'New Zealand', currency: 'NZD', path: 'new-zealand', - iso2: 'NZ', - iso3: 'NZL', }, { id: 'OM', @@ -1744,8 +1416,6 @@ export const countryData: CountryData[] = [ title: 'Oman', currency: 'OMR', path: 'oman', - iso2: 'OM', - iso3: 'OMN', }, { id: 'PA', @@ -1753,8 +1423,6 @@ export const countryData: CountryData[] = [ title: 'Panama', currency: 'PAB', path: 'panama', - iso2: 'PA', - iso3: 'PAN', }, { id: 'PE', @@ -1762,8 +1430,6 @@ export const countryData: CountryData[] = [ title: 'Peru', currency: 'PEN', path: 'peru', - iso2: 'PE', - iso3: 'PER', }, { id: 'PF', @@ -1771,8 +1437,6 @@ export const countryData: CountryData[] = [ title: 'French Polynesia', currency: 'XPF', path: 'french-polynesia', - iso2: 'PF', - iso3: 'PYF', }, { id: 'PG', @@ -1780,8 +1444,6 @@ export const countryData: CountryData[] = [ title: 'Papua New Guinea', currency: 'PGK', path: 'papua-new-guinea', - iso2: 'PG', - iso3: 'PNG', }, { id: 'PH', @@ -1789,8 +1451,6 @@ export const countryData: CountryData[] = [ title: 'Philippines', currency: 'PHP', path: 'philippines', - iso2: 'PH', - iso3: 'PHL', }, { id: 'PK', @@ -1798,8 +1458,6 @@ export const countryData: CountryData[] = [ title: 'Pakistan', currency: 'PKR', path: 'pakistan', - iso2: 'PK', - iso3: 'PAK', }, { id: 'PL', @@ -1807,8 +1465,6 @@ export const countryData: CountryData[] = [ title: 'Poland', currency: 'PLN', path: 'poland', - iso2: 'PL', - iso3: 'POL', }, { id: 'PM', @@ -1816,8 +1472,6 @@ export const countryData: CountryData[] = [ title: 'Saint Pierre and Miquelon', currency: 'EUR', path: 'saint-pierre-and-miquelon', - iso2: 'PM', - iso3: 'SPM', }, { id: 'PN', @@ -1825,8 +1479,6 @@ export const countryData: CountryData[] = [ title: 'Pitcairn Islands', currency: 'NZD', path: 'pitcairn-islands', - iso2: 'PN', - iso3: 'PCN', }, { id: 'PR', @@ -1834,8 +1486,6 @@ export const countryData: CountryData[] = [ title: 'Puerto Rico', currency: 'USD', path: 'puerto-rico', - iso2: 'PR', - iso3: 'PRI', }, { id: 'PS', @@ -1843,8 +1493,6 @@ export const countryData: CountryData[] = [ title: 'Palestine', currency: 'ILS', path: 'palestine', - iso2: 'PS', - iso3: 'PSE', }, { id: 'PRT', @@ -1852,8 +1500,6 @@ export const countryData: CountryData[] = [ title: 'Portugal', currency: 'EUR', path: 'portugal', - iso2: 'PT', - iso3: 'PRT', }, { id: 'PW', @@ -1861,8 +1507,6 @@ export const countryData: CountryData[] = [ title: 'Palau', currency: 'USD', path: 'palau', - iso2: 'PW', - iso3: 'PLW', }, { id: 'PY', @@ -1870,8 +1514,6 @@ export const countryData: CountryData[] = [ title: 'Paraguay', currency: 'PYG', path: 'paraguay', - iso2: 'PY', - iso3: 'PRY', }, { id: 'QA', @@ -1879,8 +1521,6 @@ export const countryData: CountryData[] = [ title: 'Qatar', currency: 'QAR', path: 'qatar', - iso2: 'QA', - iso3: 'QAT', }, { id: 'REU', @@ -1888,8 +1528,6 @@ export const countryData: CountryData[] = [ title: 'Réunion', currency: 'EUR', path: 'reunion', - iso2: 'RE', - iso3: 'REU', }, { id: 'ROU', @@ -1897,8 +1535,6 @@ export const countryData: CountryData[] = [ title: 'Romania', currency: 'RON', path: 'romania', - iso2: 'RO', - iso3: 'ROU', }, { id: 'RS', @@ -1906,8 +1542,6 @@ export const countryData: CountryData[] = [ title: 'Serbia', currency: 'RSD', path: 'serbia', - iso2: 'RS', - iso3: 'SRB', }, { id: 'RW', @@ -1915,8 +1549,6 @@ export const countryData: CountryData[] = [ title: 'Rwanda', currency: 'RWF', path: 'rwanda', - iso2: 'RW', - iso3: 'RWA', }, { id: 'SA', @@ -1924,8 +1556,6 @@ export const countryData: CountryData[] = [ title: 'Saudi Arabia', currency: 'SAR', path: 'saudi-arabia', - iso2: 'SA', - iso3: 'SAU', }, { id: 'SB', @@ -1933,8 +1563,6 @@ export const countryData: CountryData[] = [ title: 'Solomon Islands', currency: 'SBD', path: 'solomon-islands', - iso2: 'SB', - iso3: 'SLB', }, { id: 'SC', @@ -1942,8 +1570,6 @@ export const countryData: CountryData[] = [ title: 'Seychelles', currency: 'SCR', path: 'seychelles', - iso2: 'SC', - iso3: 'SYC', }, { id: 'SD', @@ -1951,8 +1577,6 @@ export const countryData: CountryData[] = [ title: 'Sudan', currency: 'SDG', path: 'sudan', - iso2: 'SD', - iso3: 'SDN', }, { id: 'SE', @@ -1960,8 +1584,6 @@ export const countryData: CountryData[] = [ title: 'Sweden', currency: 'SEK', path: 'sweden', - iso2: 'SE', - iso3: 'SWE', }, { id: 'SG', @@ -1969,8 +1591,6 @@ export const countryData: CountryData[] = [ title: 'Singapore', currency: 'SGD', path: 'singapore', - iso2: 'SG', - iso3: 'SGP', }, { id: 'SH', @@ -1978,8 +1598,6 @@ export const countryData: CountryData[] = [ title: 'Saint Helena', currency: 'SHP', path: 'saint-helena', - iso2: 'SH', - iso3: 'SHN', }, { id: 'SVN', @@ -1987,8 +1605,6 @@ export const countryData: CountryData[] = [ title: 'Slovenia', currency: 'EUR', path: 'slovenia', - iso2: 'SI', - iso3: 'SVN', }, { id: 'SJ', @@ -1996,8 +1612,6 @@ export const countryData: CountryData[] = [ title: 'Svalbard and Jan Mayen', currency: 'NOK', path: 'svalbard-and-jan-mayen', - iso2: 'SJ', - iso3: 'SJM', }, { id: 'SVK', @@ -2005,8 +1619,6 @@ export const countryData: CountryData[] = [ title: 'Slovakia', currency: 'EUR', path: 'slovakia', - iso2: 'SK', - iso3: 'SVK', }, { id: 'SL', @@ -2014,8 +1626,6 @@ export const countryData: CountryData[] = [ title: 'Sierra Leone', currency: 'SLL', path: 'sierra-leone', - iso2: 'SL', - iso3: 'SLE', }, { id: 'SM', @@ -2023,8 +1633,6 @@ export const countryData: CountryData[] = [ title: 'San Marino', currency: 'EUR', path: 'san-marino', - iso2: 'SM', - iso3: 'SMR', }, { id: 'SN', @@ -2032,8 +1640,6 @@ export const countryData: CountryData[] = [ title: 'Senegal', currency: 'XOF', path: 'senegal', - iso2: 'SN', - iso3: 'SEN', }, { id: 'SO', @@ -2041,8 +1647,6 @@ export const countryData: CountryData[] = [ title: 'Somalia', currency: 'SOS', path: 'somalia', - iso2: 'SO', - iso3: 'SOM', }, { id: 'SR', @@ -2050,8 +1654,6 @@ export const countryData: CountryData[] = [ title: 'Suriname', currency: 'SRD', path: 'suriname', - iso2: 'SR', - iso3: 'SUR', }, { id: 'SS', @@ -2059,8 +1661,6 @@ export const countryData: CountryData[] = [ title: 'South Sudan', currency: 'SSP', path: 'south-sudan', - iso2: 'SS', - iso3: 'SSD', }, { id: 'ST', @@ -2068,8 +1668,6 @@ export const countryData: CountryData[] = [ title: 'São Tomé and Príncipe', currency: 'STD', path: 'sao-tome-and-principe', - iso2: 'ST', - iso3: 'STP', }, { id: 'SV', @@ -2077,8 +1675,6 @@ export const countryData: CountryData[] = [ title: 'El Salvador', currency: 'USD', path: 'el-salvador', - iso2: 'SV', - iso3: 'SLV', }, { id: 'SX', @@ -2086,8 +1682,6 @@ export const countryData: CountryData[] = [ title: 'Sint Maarten', currency: 'ANG', path: 'sint-maarten', - iso2: 'SX', - iso3: 'SXM', }, { id: 'SZ', @@ -2095,8 +1689,6 @@ export const countryData: CountryData[] = [ title: 'Swaziland', currency: 'SZL', path: 'swaziland', - iso2: 'SZ', - iso3: 'SWZ', }, { id: 'TC', @@ -2104,8 +1696,6 @@ export const countryData: CountryData[] = [ title: 'Turks and Caicos Islands', currency: 'USD', path: 'turks-and-caicos-islands', - iso2: 'TC', - iso3: 'TCA', }, { id: 'TD', @@ -2113,8 +1703,6 @@ export const countryData: CountryData[] = [ title: 'Chad', currency: 'XAF', path: 'chad', - iso2: 'TD', - iso3: 'TCD', }, { id: 'TF', @@ -2122,8 +1710,6 @@ export const countryData: CountryData[] = [ title: 'French Southern Territories', currency: 'EUR', path: 'french-southern-territories', - iso2: 'TF', - iso3: 'ATF', }, { id: 'TG', @@ -2131,8 +1717,6 @@ export const countryData: CountryData[] = [ title: 'Togo', currency: 'XOF', path: 'togo', - iso2: 'TG', - iso3: 'TGO', }, { id: 'TH', @@ -2140,8 +1724,6 @@ export const countryData: CountryData[] = [ title: 'Thailand', currency: 'THB', path: 'thailand', - iso2: 'TH', - iso3: 'THA', }, { id: 'TJ', @@ -2149,8 +1731,6 @@ export const countryData: CountryData[] = [ title: 'Tajikistan', currency: 'TJS', path: 'tajikistan', - iso2: 'TJ', - iso3: 'TJK', }, { id: 'TK', @@ -2158,8 +1738,6 @@ export const countryData: CountryData[] = [ title: 'Tokelau', currency: 'NZD', path: 'tokelau', - iso2: 'TK', - iso3: 'TKL', }, { id: 'TL', @@ -2167,8 +1745,6 @@ export const countryData: CountryData[] = [ title: 'East Timor', currency: 'USD', path: 'east-timor', - iso2: 'TL', - iso3: 'TLS', }, { id: 'TM', @@ -2176,8 +1752,6 @@ export const countryData: CountryData[] = [ title: 'Turkmenistan', currency: 'TMT', path: 'turkmenistan', - iso2: 'TM', - iso3: 'TKM', }, { id: 'TN', @@ -2185,8 +1759,6 @@ export const countryData: CountryData[] = [ title: 'Tunisia', currency: 'TND', path: 'tunisia', - iso2: 'TN', - iso3: 'TUN', }, { id: 'TO', @@ -2194,8 +1766,6 @@ export const countryData: CountryData[] = [ title: 'Tonga', currency: 'TOP', path: 'tonga', - iso2: 'TO', - iso3: 'TON', }, { id: 'TR', @@ -2203,8 +1773,6 @@ export const countryData: CountryData[] = [ title: 'Turkey', currency: 'TRY', path: 'turkey', - iso2: 'TR', - iso3: 'TUR', }, { id: 'TT', @@ -2212,8 +1780,6 @@ export const countryData: CountryData[] = [ title: 'Trinidad and Tobago', currency: 'TTD', path: 'trinidad-and-tobago', - iso2: 'TT', - iso3: 'TTO', }, { id: 'TV', @@ -2221,8 +1787,6 @@ export const countryData: CountryData[] = [ title: 'Tuvalu', currency: 'AUD', path: 'tuvalu', - iso2: 'TV', - iso3: 'TUV', }, { id: 'TW', @@ -2230,8 +1794,6 @@ export const countryData: CountryData[] = [ title: 'Taiwan', currency: 'TWD', path: 'taiwan', - iso2: 'TW', - iso3: 'TWN', }, { id: 'TZ', @@ -2239,8 +1801,6 @@ export const countryData: CountryData[] = [ title: 'Tanzania', currency: 'TZS', path: 'tanzania', - iso2: 'TZ', - iso3: 'TZA', }, { id: 'UA', @@ -2248,8 +1808,6 @@ export const countryData: CountryData[] = [ title: 'Ukraine', currency: 'UAH', path: 'ukraine', - iso2: 'UA', - iso3: 'UKR', }, { id: 'UG', @@ -2257,8 +1815,6 @@ export const countryData: CountryData[] = [ title: 'Uganda', currency: 'UGX', path: 'uganda', - iso2: 'UG', - iso3: 'UGA', }, { id: 'UM', @@ -2266,8 +1822,6 @@ export const countryData: CountryData[] = [ title: 'U.S. Minor Outlying Islands', currency: 'USD', path: 'u.s.-minor-outlying-islands', - iso2: 'UM', - iso3: 'UMI', }, { id: 'US', @@ -2275,8 +1829,6 @@ export const countryData: CountryData[] = [ title: 'United States', currency: 'USD', path: 'usa', - iso2: 'US', - iso3: 'USA', }, { id: 'UY', @@ -2284,8 +1836,6 @@ export const countryData: CountryData[] = [ title: 'Uruguay', currency: 'UYU', path: 'uruguay', - iso2: 'UY', - iso3: 'URY', }, { id: 'UZ', @@ -2293,8 +1843,6 @@ export const countryData: CountryData[] = [ title: 'Uzbekistan', currency: 'UZS', path: 'uzbekistan', - iso2: 'UZ', - iso3: 'UZB', }, { id: 'VA', @@ -2302,8 +1850,6 @@ export const countryData: CountryData[] = [ title: 'Vatican City', currency: 'EUR', path: 'vatican-city', - iso2: 'VA', - iso3: 'VAT', }, { id: 'VC', @@ -2311,8 +1857,6 @@ export const countryData: CountryData[] = [ title: 'Saint Vincent and the Grenadines', currency: 'XCD', path: 'saint-vincent-and-the-grenadines', - iso2: 'VC', - iso3: 'VCT', }, { id: 'VG', @@ -2320,8 +1864,6 @@ export const countryData: CountryData[] = [ title: 'British Virgin Islands', currency: 'USD', path: 'british-virgin-islands', - iso2: 'VG', - iso3: 'VGB', }, { id: 'VI', @@ -2329,8 +1871,6 @@ export const countryData: CountryData[] = [ title: 'U.S. Virgin Islands', currency: 'USD', path: 'us-virgin-islands', - iso2: 'VI', - iso3: 'VIR', }, { id: 'VN', @@ -2338,8 +1878,6 @@ export const countryData: CountryData[] = [ title: 'Vietnam', currency: 'VND', path: 'vietnam', - iso2: 'VN', - iso3: 'VNM', }, { id: 'VU', @@ -2347,8 +1885,6 @@ export const countryData: CountryData[] = [ title: 'Vanuatu', currency: 'VUV', path: 'vanuatu', - iso2: 'VU', - iso3: 'VUT', }, { id: 'WF', @@ -2356,8 +1892,6 @@ export const countryData: CountryData[] = [ title: 'Wallis and Futuna', currency: 'XPF', path: 'wallis-and-futuna', - iso2: 'WF', - iso3: 'WLF', }, { id: 'WS', @@ -2365,8 +1899,6 @@ export const countryData: CountryData[] = [ title: 'Samoa', currency: 'WST', path: 'samoa', - iso2: 'WS', - iso3: 'WSM', }, { id: 'XK', @@ -2374,8 +1906,6 @@ export const countryData: CountryData[] = [ title: 'Kosovo', currency: 'EUR', path: 'kosovo', - iso2: 'XK', - iso3: 'XKX', }, { id: 'YE', @@ -2383,8 +1913,6 @@ export const countryData: CountryData[] = [ title: 'Yemen', currency: 'YER', path: 'yemen', - iso2: 'YE', - iso3: 'YEM', }, { id: 'YT', @@ -2392,8 +1920,6 @@ export const countryData: CountryData[] = [ title: 'Mayotte', currency: 'EUR', path: 'mayotte', - iso2: 'YT', - iso3: 'MYT', }, { id: 'ZA', @@ -2401,8 +1927,6 @@ export const countryData: CountryData[] = [ title: 'South Africa', currency: 'ZAR', path: 'south-africa', - iso2: 'ZA', - iso3: 'ZAF', }, { id: 'ZM', @@ -2410,8 +1934,6 @@ export const countryData: CountryData[] = [ title: 'Zambia', currency: 'ZMW', path: 'zambia', - iso2: 'ZM', - iso3: 'ZMB', }, { id: 'ZW', @@ -2419,8 +1941,6 @@ export const countryData: CountryData[] = [ title: 'Zimbabwe', currency: 'ZWL', path: 'zimbabwe', - iso2: 'ZW', - iso3: 'ZWE', }, ] diff --git a/src/components/AddWithdraw/AddWithdrawCountriesList.tsx b/src/components/AddWithdraw/AddWithdrawCountriesList.tsx index 4b2a0ec55..70c6ab5fb 100644 --- a/src/components/AddWithdraw/AddWithdrawCountriesList.tsx +++ b/src/components/AddWithdraw/AddWithdrawCountriesList.tsx @@ -15,7 +15,7 @@ import { useEffect, useMemo, useRef, useState } from 'react' import { InitiateKYCModal } from '@/components/Kyc' import { DynamicBankAccountForm, IBankAccountDetails } from './DynamicBankAccountForm' import { addBankAccount, updateUserById } from '@/app/actions/users' -import { BridgeKycStatus } from '@/utils/bridge-accounts.utils' +import { KYCStatus } from '@/utils/bridge-accounts.utils' import { AddBankAccountPayload } from '@/app/actions/types/users.types' import { useWebSocket } from '@/hooks/useWebSocket' import { useWithdrawFlow } from '@/context/WithdrawFlowContext' @@ -24,8 +24,6 @@ import PeanutLoading from '../Global/PeanutLoading' import { getCountryCodeForWithdraw } from '@/utils/withdraw.utils' import { DeviceType, useDeviceType } from '@/hooks/useGetDeviceType' import CryptoMethodDrawer from '../AddMoney/components/CryptoMethodDrawer' -import { useAppDispatch } from '@/redux/hooks' -import { bankFormActions } from '@/redux/slices/bank-form-slice' interface AddWithdrawCountriesListProps { flow: 'add' | 'withdraw' @@ -39,30 +37,27 @@ const AddWithdrawCountriesList = ({ flow }: AddWithdrawCountriesListProps) => { const { deviceType } = useDeviceType() const { user, fetchUser } = useAuth() const { setSelectedBankAccount, amountToWithdraw } = useWithdrawFlow() - const dispatch = useAppDispatch() // component level states const [view, setView] = useState<'list' | 'form'>('list') const [isKycModalOpen, setIsKycModalOpen] = useState(false) const formRef = useRef<{ handleSubmit: () => void }>(null) - const [liveKycStatus, setLiveKycStatus] = useState( - user?.user?.bridgeKycStatus as BridgeKycStatus - ) + const [liveKycStatus, setLiveKycStatus] = useState(user?.user?.kycStatus as KYCStatus) const [isDrawerOpen, setIsDrawerOpen] = useState(false) useWebSocket({ username: user?.user.username ?? undefined, autoConnect: !!user?.user.username, onKycStatusUpdate: (newStatus) => { - setLiveKycStatus(newStatus as BridgeKycStatus) + setLiveKycStatus(newStatus as KYCStatus) }, }) useEffect(() => { - if (user?.user.bridgeKycStatus) { - setLiveKycStatus(user.user.bridgeKycStatus as BridgeKycStatus) + if (user?.user.kycStatus) { + setLiveKycStatus(user.user.kycStatus as KYCStatus) } - }, [user?.user.bridgeKycStatus]) + }, [user?.user.kycStatus]) useEffect(() => { fetchUser() @@ -80,7 +75,7 @@ const AddWithdrawCountriesList = ({ flow }: AddWithdrawCountriesListProps) => { payload: AddBankAccountPayload, rawData: IBankAccountDetails ): Promise<{ error?: string }> => { - const currentKycStatus = liveKycStatus || user?.user.bridgeKycStatus + const currentKycStatus = liveKycStatus || user?.user.kycStatus const isUserKycVerified = currentKycStatus === 'approved' const hasNameOnLoad = !!user?.user.fullName @@ -96,7 +91,7 @@ const AddWithdrawCountriesList = ({ flow }: AddWithdrawCountriesListProps) => { return { error: result.error } } if (!result.data) { - return { error: 'Failed to process bank account. Please try again or contact support.' } + return { error: 'Failed to process bank account. Please try again.' } } // after successfully adding, we refetch user data to get the new account @@ -230,8 +225,6 @@ const AddWithdrawCountriesList = ({ flow }: AddWithdrawCountriesListProps) => { { - // clear DynamicBankAccountForm data - dispatch(bankFormActions.clearFormData()) // ensure kyc modal isn't open so late success events don't flip view setIsKycModalOpen(false) setView('list') diff --git a/src/components/AddWithdraw/DynamicBankAccountForm.tsx b/src/components/AddWithdraw/DynamicBankAccountForm.tsx index 89936dcd6..eb44236b7 100644 --- a/src/components/AddWithdraw/DynamicBankAccountForm.tsx +++ b/src/components/AddWithdraw/DynamicBankAccountForm.tsx @@ -1,12 +1,12 @@ 'use client' -import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from 'react' +import { forwardRef, useImperativeHandle, useMemo, useState } from 'react' import { useForm, Controller } from 'react-hook-form' 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 { useParams, useRouter } from 'next/navigation' +import { useParams } from 'next/navigation' import { validateIban, validateBic, isValidRoutingNumber } from '@/utils/bridge-accounts.utils' import ErrorAlert from '@/components/Global/ErrorAlert' import { getBicFromIban } from '@/app/actions/ibanToBic' @@ -14,10 +14,6 @@ import PeanutActionDetailsCard, { PeanutActionDetailsCardProps } from '../Global import { PEANUT_WALLET_TOKEN_SYMBOL } from '@/constants' import { useWithdrawFlow } from '@/context/WithdrawFlowContext' import { getCountryFromIban, validateMXCLabeAccount, validateUSBankAccount } from '@/utils/withdraw.utils' -import useSavedAccounts from '@/hooks/useSavedAccounts' -import { useAppDispatch, useAppSelector } from '@/redux/hooks' -import { bankFormActions } from '@/redux/slices/bank-form-slice' -import { useDebounce } from '@/hooks/useDebounce' const isIBANCountry = (country: string) => { return countryCodeMap[country.toUpperCase()] !== undefined @@ -48,7 +44,6 @@ interface DynamicBankAccountFormProps { flow?: 'claim' | 'withdraw' actionDetailsProps?: Partial error: string | null - hideEmailInput?: boolean } export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, DynamicBankAccountFormProps>( @@ -61,36 +56,25 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D actionDetailsProps, countryName: countryNameFromProps, error, - hideEmailInput = false, }, ref ) => { - const isMx = country.toUpperCase() === 'MX' - const isUs = country.toUpperCase() === 'USA' - const isIban = isUs || isMx ? false : isIBANCountry(country) const { user } = useAuth() - const dispatch = useAppDispatch() const [isSubmitting, setIsSubmitting] = useState(false) const [submissionError, setSubmissionError] = useState(null) + const [showBicField, setShowBicField] = useState(false) const { country: countryNameParams } = useParams() - const { amountToWithdraw, setSelectedBankAccount } = useWithdrawFlow() + const { amountToWithdraw } = useWithdrawFlow() const [firstName, ...lastNameParts] = (user?.user.fullName ?? '').split(' ') const lastName = lastNameParts.join(' ') - const router = useRouter() - const savedAccounts = useSavedAccounts() - const [isCheckingBICValid, setisCheckingBICValid] = useState(false) let selectedCountry = (countryNameFromProps ?? (countryNameParams as string)).toLowerCase() - // Get persisted form data from Redux - const persistedFormData = useAppSelector((state) => state.bankForm.formData) - const { control, handleSubmit, setValue, getValues, - watch, formState: { errors, isValid, isValidating, touchedFields }, } = useForm({ defaultValues: { @@ -106,28 +90,15 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D state: '', postalCode: '', ...initialData, - ...persistedFormData, // Redux persisted data takes precedence }, mode: 'onBlur', reValidateMode: 'onSubmit', }) - // Watch BIC field value for debouncing - const bicValue = watch('bic') - const debouncedBicValue = useDebounce(bicValue, 500) // 500ms delay - useImperativeHandle(ref, () => ({ handleSubmit: handleSubmit(onSubmit), })) - // Trigger BIC validation when debounced value changes - useEffect(() => { - if (isIban && debouncedBicValue && debouncedBicValue.trim().length > 0) { - // Trigger validation for the BIC field - setValue('bic', debouncedBicValue, { shouldValidate: true }) - } - }, [debouncedBicValue, isIban, setValue]) - const onSubmit = async (data: IBankAccountDetails) => { // If validation is still running, don't proceed if (isValidating) { @@ -142,17 +113,6 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D setIsSubmitting(true) try { - const existingAccount = savedAccounts.find( - (account) => account.identifier === (data.accountNumber.toLowerCase() || data.clabe.toLowerCase()) - ) - - // Skip adding account if the account already exists for the logged in user - if (existingAccount) { - setSelectedBankAccount(existingAccount) - router.push(`/withdraw/${country}/bank`) - return - } - const isUs = country.toUpperCase() === 'USA' const isMx = country.toUpperCase() === 'MX' const isIban = isUs || isMx ? false : isIBANCountry(country) @@ -169,6 +129,35 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D let bic = data.bic || getValues('bic') const iban = data.iban || getValues('iban') + // for IBAN countries, ensure BIC is available + if (isIban) { + // if BIC field is shown but empty, don't proceed + if (showBicField && !bic) { + setSubmissionError('BIC is required') + return + } + + // if BIC field is not shown and no BIC available, try to get it automatically + if (!showBicField && !bic) { + try { + const autoBic = await getBicFromIban(accountNumber) + if (autoBic) { + bic = autoBic + // set the BIC value in the form without showing the field + setValue('bic', autoBic, { shouldValidate: false }) + } else { + setShowBicField(true) + setSubmissionError('BIC is required') + return + } + } catch (error) { + setShowBicField(true) + setSubmissionError('BIC is required') + return + } + } + } + const payload: Partial = { accountType, accountNumber: accountNumber.replace(/\s/g, ''), @@ -205,17 +194,6 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D }) if (result.error) { setSubmissionError(result.error) - setIsSubmitting(false) - } else { - // Save form data to Redux after successful submission - const formDataToSave = { - ...data, - country, - firstName: data.firstName.trim(), - lastName: data.lastName.trim(), - } - dispatch(bankFormActions.setFormData(formDataToSave)) - setIsSubmitting(false) } } catch (error: any) { setSubmissionError(error.message) @@ -224,6 +202,10 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D } } + const isMx = country.toUpperCase() === 'MX' + const isUs = country.toUpperCase() === 'USA' + const isIban = isUs || isMx ? false : isIBANCountry(country) + const renderInput = ( name: keyof IBankAccountDetails, placeholder: string, @@ -306,7 +288,6 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D {flow === 'claim' && user?.user.userId && !user.user.email && - !hideEmailInput && renderInput('email', 'E-mail', { required: 'Email is required', })} @@ -317,7 +298,6 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D
)} {flow !== 'claim' && - !hideEmailInput && !user?.user?.email && renderInput('email', 'E-mail', { required: 'Email is required', @@ -352,17 +332,6 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D undefined, async (field) => { if (!field.value || field.value.trim().length === 0) return - const isValidIban = await validateIban(field.value) - if (isValidIban) { - try { - const autoBic = await getBicFromIban(field.value) - if (autoBic && !getValues('bic')) { - setValue('bic', autoBic, { shouldValidate: true }) - } - } catch { - console.log('Could not fetch BIC automatically.') - } - } } ) : renderInput( @@ -377,6 +346,7 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D )} {isIban && + showBicField && renderInput( 'bic', 'BIC', @@ -384,15 +354,7 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D required: 'BIC is required', validate: async (value: string) => { if (!value || value.trim().length === 0) return 'BIC is required' - - // Only validate if the value matches the debounced value (to prevent API calls on every keystroke) - if (value.trim() !== debouncedBicValue?.trim()) { - return true // Skip validation until debounced value is ready - } - - setisCheckingBICValid(true) const isValid = await validateBic(value.trim()) - setisCheckingBICValid(false) return isValid || 'Invalid BIC code' }, }, @@ -433,8 +395,8 @@ export const DynamicBankAccountForm = forwardRef<{ handleSubmit: () => void }, D variant="purple" shadowSize="4" className="!mt-4 w-full" - loading={isSubmitting || isCheckingBICValid} - disabled={isSubmitting || !isValid || isCheckingBICValid} + loading={isSubmitting} + disabled={isSubmitting || !isValid} > Review diff --git a/src/components/Claim/Claim.tsx b/src/components/Claim/Claim.tsx index 1e4bbb46a..99bf282ca 100644 --- a/src/components/Claim/Claim.tsx +++ b/src/components/Claim/Claim.tsx @@ -25,10 +25,6 @@ import * as _consts from './Claim.consts' import FlowManager from './Link/FlowManager' import { type PeanutCrossChainRoute } from '@/services/swap' import { NotFoundClaimLink, WrongPasswordClaimLink, ClaimedView } from './Generic' -import SupportCTA from '../Global/SupportCTA' -import { twMerge } from 'tailwind-merge' -import { ClaimBankFlowStep, useClaimBankFlow } from '@/context/ClaimBankFlowContext' -import { useSearchParams } from 'next/navigation' export const Claim = ({}) => { const [step, setStep] = useState<_consts.IClaimScreenState>(_consts.INIT_VIEW_STATE) @@ -70,9 +66,6 @@ export const Claim = ({}) => { const senderId = claimLinkData?.sender.userId const { interactions } = useUserInteractions(senderId ? [senderId] : []) - const { setFlowStep: setClaimBankFlowStep } = useClaimBankFlow() - const searchParams = useSearchParams() - const transactionForDrawer: TransactionDetails | null = useMemo(() => { if (!claimLinkData) return null @@ -129,7 +122,7 @@ export const Claim = ({}) => { peanutFeeDetails: { amountDisplay: '$ 0.00', }, - isVerified: claimLinkData.sender?.bridgeKycStatus === 'approved', + isVerified: claimLinkData.sender?.kycStatus === 'approved', haveSentMoneyToUser: claimLinkData.sender?.userId ? interactions[claimLinkData.sender.userId] || false : false, @@ -261,19 +254,8 @@ export const Claim = ({}) => { } }, [linkState, transactionForDrawer]) - // redirect to bank flow if user is KYC approved and step is bank - useEffect(() => { - const stepFromURL = searchParams.get('step') - if (user?.user.bridgeKycStatus === 'approved' && stepFromURL === 'bank') { - setClaimBankFlowStep(ClaimBankFlowStep.BankCountryList) - } - }, [user]) - return ( - + {linkState === _consts.claimLinkStateType.LOADING && } {linkState === _consts.claimLinkStateType.CLAIM && ( { onClose={() => checkLink(window.location.href)} /> )} - - {/* Show only to guest users */} - {linkState !== _consts.claimLinkStateType.LOADING && !user && !isFetchingUser && } ) } diff --git a/src/components/Claim/Link/Initial.view.tsx b/src/components/Claim/Link/Initial.view.tsx index b3a5543b7..782352be4 100644 --- a/src/components/Claim/Link/Initial.view.tsx +++ b/src/components/Claim/Link/Initial.view.tsx @@ -11,7 +11,13 @@ import { usdcAddressOptimism, } from '@/components/Offramp/Offramp.consts' import { ActionType, estimatePoints } from '@/components/utils/utils' -import { PEANUT_WALLET_CHAIN, PEANUT_WALLET_TOKEN, ROUTE_NOT_FOUND_ERROR } from '@/constants' +import { + PEANUT_WALLET_CHAIN, + PEANUT_WALLET_TOKEN, + PINTA_WALLET_CHAIN, + PINTA_WALLET_TOKEN, + ROUTE_NOT_FOUND_ERROR, +} from '@/constants' import { TRANSACTIONS } from '@/constants/query.consts' import { loadingStateContext, tokenSelectorContext } from '@/context' import { useAuth } from '@/context/authContext' @@ -97,7 +103,7 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { isXChain, setIsXChain, } = useContext(tokenSelectorContext) - const { claimLink, claimLinkXchain, removeParamStep } = useClaimLink() + const { claimLink, claimLinkXchain } = useClaimLink() const { isConnected: isPeanutWallet, address, fetchBalance } = useWallet() const router = useRouter() const { user } = useAuth() @@ -120,8 +126,16 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { } }, [claimLinkData, isPeanutWallet]) + const isPeanutClaimOnlyMode = useMemo(() => { + return searchParams.get('t') === 'pnt' + }, [searchParams]) + const isPeanutChain = useMemo(() => { - return claimLinkData.chainId === PEANUT_WALLET_CHAIN.id.toString() + return ( + claimLinkData.chainId === PEANUT_WALLET_CHAIN.id.toString() || + (areEvmAddressesEqual(claimLinkData.tokenAddress, PINTA_WALLET_TOKEN) && + claimLinkData.chainId === PINTA_WALLET_CHAIN.id.toString()) + ) }, [claimLinkData]) // set token selector chain/token to peanut wallet chain/token if recipient type is username @@ -143,7 +157,7 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { }, [recipientType, claimLinkData.chainId, isPeanutChain, claimLinkData.tokenAddress]) const handleClaimLink = useCallback( - async (bypassModal = false, autoClaim = false) => { + async (bypassModal = false) => { if (!isPeanutWallet && !bypassModal) { setShowConfirmationModal(true) return @@ -161,11 +175,8 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { try { setLoadingState('Executing transaction') if (isPeanutWallet) { - if (autoClaim) { - await sendLinksApi.autoClaimLink(user?.user.username ?? address, claimLinkData.link) - } else { - await sendLinksApi.claim(user?.user.username ?? address, claimLinkData.link) - } + await sendLinksApi.claim(user?.user.username ?? address, claimLinkData.link) + setClaimType('claim') onCustom('SUCCESS') fetchBalance() @@ -318,7 +329,7 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { recipient: recipient.name ?? recipient.address, password: '', }) - if (user?.user.bridgeKycStatus === 'approved') { + if (user?.user.kycStatus === 'approved') { const account = user.accounts.find( (account) => account.identifier.replaceAll(/\s/g, '').toLowerCase() === @@ -388,11 +399,10 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { } }, [selectedChainID, selectedTokenAddress, claimLinkData.chainId, claimLinkData.tokenAddress]) - // We may need this when we re add rewards via specific tokens - // If not, feel free to remove const isReward = useMemo(() => { - return false - }, []) + if (!claimLinkData.tokenAddress) return false + return areEvmAddressesEqual(claimLinkData.tokenAddress, PINTA_WALLET_TOKEN) + }, [claimLinkData.tokenAddress]) const fetchRoute = useCallback( async (toToken?: string, toChain?: string) => { @@ -613,14 +623,6 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { } } - useEffect(() => { - const stepFromURL = searchParams.get('step') - if (user && claimLinkData.status !== 'CLAIMED' && stepFromURL === 'claim' && isPeanutWallet) { - removeParamStep() - handleClaimLink(false, true) - } - }, [user, searchParams, isPeanutWallet]) - if (claimBankFlowStep) { return } @@ -668,6 +670,7 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { */} {recipientType !== 'iban' && recipientType !== 'us' && + !isPeanutClaimOnlyMode && claimBankFlowStep !== ClaimBankFlowStep.BankCountryList && !!claimToExternalWallet && ( @@ -675,29 +678,33 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => {
{/* Alternative options section with divider */} - {/* Manual Input Section - Always visible in non-peanut-only mode */} - {!!claimToExternalWallet && ( - { - setRecipient(update.recipient) - if (!update.recipient.address) { - setRecipientType('address') - // Reset loading state when input is cleared - setLoadingState('Idle') - } else { - setRecipientType(update.type) - } - setIsValidRecipient(update.isValid) - setErrorState({ - showError: !update.isValid, - errorMessage: update.errorMessage, - }) - setInputChanging(update.isChanging) - }} - showInfoText={false} - /> + {!isPeanutClaimOnlyMode && ( + <> + {/* Manual Input Section - Always visible in non-peanut-only mode */} + {!!claimToExternalWallet && ( + { + setRecipient(update.recipient) + if (!update.recipient.address) { + setRecipientType('address') + // Reset loading state when input is cleared + setLoadingState('Idle') + } else { + setRecipientType(update.type) + } + setIsValidRecipient(update.isValid) + setErrorState({ + showError: !update.isValid, + errorMessage: update.errorMessage, + }) + setInputChanging(update.isChanging) + }} + showInfoText={false} + /> + )} + )} {recipientType === 'username' && !!claimToExternalWallet && (
@@ -725,7 +732,7 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { {getButtonText()} )} - {!claimToExternalWallet && ( + {!isPeanutClaimOnlyMode && !claimToExternalWallet && ( )}
@@ -773,13 +780,9 @@ export const InitialClaimLinkView = (props: IClaimScreenProps) => { modalPanelClassName="max-w-md mx-8" /> { - removeParamStep() - setShowVerificationModal(false) - }} + isOpen={showVerificationModal && !user} + onClose={() => setShowVerificationModal(false)} description="The sender isn't verified, so please create an account and verify your identity to have the funds deposited to your bank." />
diff --git a/src/components/Claim/Link/Onchain/Confirm.view.tsx b/src/components/Claim/Link/Onchain/Confirm.view.tsx index 60bb0c161..7a572f307 100644 --- a/src/components/Claim/Link/Onchain/Confirm.view.tsx +++ b/src/components/Claim/Link/Onchain/Confirm.view.tsx @@ -23,6 +23,7 @@ import { useContext, useState, useMemo } from 'react' import { formatUnits } from 'viem' import * as _consts from '../../Claim.consts' import useClaimLink from '../../useClaimLink' +import { PINTA_WALLET_TOKEN } from '@/constants' import { useAuth } from '@/context/authContext' import { sendLinksApi } from '@/services/sendLinks' @@ -48,11 +49,10 @@ export const ConfirmClaimLinkView = ({ errorMessage: string }>({ showError: false, errorMessage: '' }) - // We may need this when we re add rewards via specific tokens - // If not, feel free to remove const isReward = useMemo(() => { - return false - }, []) + if (!claimLinkData.tokenAddress) return false + return areEvmAddressesEqual(claimLinkData.tokenAddress, PINTA_WALLET_TOKEN) + }, [claimLinkData.tokenAddress]) // Determine which chain/token details to show – prefer the selectedRoute details if present, // otherwise fall back to what the user picked in the token selector. diff --git a/src/components/Claim/Link/Onchain/Success.view.tsx b/src/components/Claim/Link/Onchain/Success.view.tsx index 63cfa3e51..19447b4fd 100644 --- a/src/components/Claim/Link/Onchain/Success.view.tsx +++ b/src/components/Claim/Link/Onchain/Success.view.tsx @@ -14,9 +14,6 @@ import { useEffect, useMemo } from 'react' import type { Hash } from 'viem' import { formatUnits } from 'viem' import * as _consts from '../../Claim.consts' -import Image from 'next/image' -import { PEANUT_LOGO_BLACK, PEANUTMAN_LOGO } from '@/assets' -import CreateAccountButton from '@/components/Global/CreateAccountButton' export const SuccessClaimLinkView = ({ transactionHash, @@ -132,7 +129,11 @@ export const SuccessClaimLinkView = ({ ) } - return router.push('/setup')} /> + return ( + + ) } return ( diff --git a/src/components/Claim/Link/views/BankFlowManager.view.tsx b/src/components/Claim/Link/views/BankFlowManager.view.tsx index a7adde123..52458af8c 100644 --- a/src/components/Claim/Link/views/BankFlowManager.view.tsx +++ b/src/components/Claim/Link/views/BankFlowManager.view.tsx @@ -26,10 +26,8 @@ import { CountryListRouter } from '@/components/Common/CountryListRouter' import NavHeader from '@/components/Global/NavHeader' import { InitiateKYCModal } from '@/components/Kyc' import { useWebSocket } from '@/hooks/useWebSocket' -import { BridgeKycStatus } from '@/utils/bridge-accounts.utils' +import { KYCStatus } from '@/utils/bridge-accounts.utils' import { getCountryCodeForWithdraw } from '@/utils/withdraw.utils' -import { useAppDispatch } from '@/redux/hooks' -import { bankFormActions } from '@/redux/slices/bank-form-slice' import { sendLinksApi } from '@/services/sendLinks' type BankAccountWithId = IBankAccountDetails & @@ -68,16 +66,13 @@ export const BankFlowManager = (props: IClaimScreenProps) => { const savedAccounts = useSavedAccounts() const { isLoading, setLoadingState } = useContext(loadingStateContext) const { claimLink } = useClaimLink() - const dispatch = useAppDispatch() // local states for this component const [localBankDetails, setLocalBankDetails] = useState(null) const [receiverFullName, setReceiverFullName] = useState('') const [error, setError] = useState(null) const formRef = useRef<{ handleSubmit: () => void }>(null) - const [liveKycStatus, setLiveKycStatus] = useState( - user?.user?.bridgeKycStatus as BridgeKycStatus - ) + const [liveKycStatus, setLiveKycStatus] = useState(user?.user?.kycStatus as KYCStatus) const [isProcessingKycSuccess, setIsProcessingKycSuccess] = useState(false) const [offrampData, setOfframpData] = useState(null) @@ -86,16 +81,16 @@ export const BankFlowManager = (props: IClaimScreenProps) => { username: user?.user.username ?? undefined, autoConnect: !!user?.user.username, onKycStatusUpdate: (newStatus) => { - setLiveKycStatus(newStatus as BridgeKycStatus) + setLiveKycStatus(newStatus as KYCStatus) }, }) // effect to update live KYC status from user object useEffect(() => { - if (user?.user.bridgeKycStatus) { - setLiveKycStatus(user.user.bridgeKycStatus as BridgeKycStatus) + if (user?.user.kycStatus) { + setLiveKycStatus(user.user.kycStatus as KYCStatus) } - }, [user?.user.bridgeKycStatus]) + }, [user?.user.kycStatus]) /** * @name handleConfirmClaim @@ -156,7 +151,7 @@ export const BankFlowManager = (props: IClaimScreenProps) => { } // handle error if user is not KYC approved - if (userForOfframp.bridgeKycStatus !== 'approved') throw new Error('User not KYC approved') + if (userForOfframp.kycStatus !== 'approved') throw new Error('User not KYC approved') if (!userForOfframp?.bridgeCustomerId) throw new Error('User bridge customer ID not found') // get payment rail and currency for the offramp @@ -457,12 +452,11 @@ export const BankFlowManager = (props: IClaimScreenProps) => {
{ - dispatch(bankFormActions.clearFormData()) // clear DynamicBankAccountForm data + onPrev={() => savedAccounts.length > 0 ? setClaimBankFlowStep(ClaimBankFlowStep.SavedAccountsList) : setClaimBankFlowStep(ClaimBankFlowStep.BankCountryList) - }} + } />
{ countryName={selectedCountry?.title ?? ''} onSuccess={handleSuccess} flow={'claim'} - hideEmailInput={bankClaimType === BankClaimType.GuestBankClaim} actionDetailsProps={{ transactionType: 'CLAIM_LINK_BANK_ACCOUNT', recipientType: 'BANK_ACCOUNT', diff --git a/src/components/Claim/Link/views/Confirm.bank-claim.view.tsx b/src/components/Claim/Link/views/Confirm.bank-claim.view.tsx index e0df2d795..9c7fddeac 100644 --- a/src/components/Claim/Link/views/Confirm.bank-claim.view.tsx +++ b/src/components/Claim/Link/views/Confirm.bank-claim.view.tsx @@ -13,7 +13,8 @@ import { ClaimLinkData } from '@/services/sendLinks' import { formatUnits } from 'viem' import ExchangeRate from '@/components/ExchangeRate' import { AccountType } from '@/interfaces' -import countryCurrencyMappings from '@/constants/countryCurrencyMapping' +import { useCurrency } from '@/hooks/useCurrency' +import { getCurrencySymbol } from '@/utils/bridge.utils' interface ConfirmBankClaimViewProps { onConfirm: () => void @@ -59,9 +60,36 @@ export function ConfirmBankClaimView({ [claimLinkData] ) - const nonEuroCurrency = countryCurrencyMappings.find( - (currency) => countryCodeForFlag.toLowerCase() === currency.flagCode.toLowerCase() - )?.currencyCode + // determine display currency based on account type + const currencyCode = useMemo(() => { + if (accountType === AccountType.CLABE) return 'MXN' + if (accountType === AccountType.US) return 'USD' + return 'EUR' + }, [accountType]) + + // fetch exchange rate and symbol (USD -> local currency) + const { symbol: resolvedSymbol, price, isLoading: isLoadingCurrency } = useCurrency(currencyCode) + + // fallback if conversion fails + const failedConversion = useMemo(() => { + return currencyCode !== 'USD' && !isLoadingCurrency && (!price || isNaN(price)) + }, [currencyCode, isLoadingCurrency, price]) + + // display amount in local currency + const displayAmount = useMemo(() => { + if (currencyCode === 'USD') return usdAmount + if (isLoadingCurrency) return '-' + if (!price || isNaN(price)) return usdAmount + const converted = (Number(usdAmount) * price).toFixed(2) + return converted + }, [price, usdAmount, currencyCode, isLoadingCurrency]) + + const displaySymbol = useMemo(() => { + if (currencyCode === 'USD') return '$' + // fallback to $ if conversion fails + if (failedConversion) return '$' + return resolvedSymbol ?? getCurrencySymbol(currencyCode) + }, [currencyCode, resolvedSymbol, failedConversion]) return (
@@ -75,8 +103,10 @@ export function ConfirmBankClaimView({ transactionType="CLAIM_LINK_BANK_ACCOUNT" recipientType="BANK_ACCOUNT" recipientName={bankDetails.country} - amount={usdAmount} + amount={displayAmount} tokenSymbol={claimLinkData.tokenSymbol} + currencySymbol={displaySymbol} + isLoading={isLoadingCurrency} /> @@ -91,7 +121,7 @@ export function ConfirmBankClaimView({ {bankDetails.routingNumber && ( )} - + diff --git a/src/components/Claim/useClaimLink.tsx b/src/components/Claim/useClaimLink.tsx index 4aeaf9b6c..d1d0197ce 100644 --- a/src/components/Claim/useClaimLink.tsx +++ b/src/components/Claim/useClaimLink.tsx @@ -11,14 +11,11 @@ import { useWallet } from '@/hooks/wallet/useWallet' import { isTestnetChain } from '@/utils' import * as Sentry from '@sentry/nextjs' import { useAccount } from 'wagmi' -import { usePathname, useSearchParams } from 'next/navigation' const useClaimLink = () => { const { fetchBalance } = useWallet() const { chain: currentChain } = useAccount() const { switchChainAsync } = useSwitchChain() - const pathname = usePathname() - const searchParams = useSearchParams() const { setLoadingState } = useContext(loadingStateContext) @@ -96,29 +93,10 @@ const useClaimLink = () => { } } - const addParamStep = (step: 'bank' | 'claim') => { - const params = new URLSearchParams(searchParams) - params.set('step', step) - - const hash = window.location.hash - const newUrl = `${pathname}?${params.toString()}${hash}` - window.history.replaceState(null, '', newUrl) - } - - const removeParamStep = () => { - const params = new URLSearchParams(searchParams) - params.delete('step') - const queryString = params.toString() - const newUrl = `${pathname}${queryString ? `?${queryString}` : ''}${window.location.hash}` - window.history.replaceState(null, '', newUrl) - } - return { claimLink, claimLinkXchain, switchNetwork, - addParamStep, - removeParamStep, } } diff --git a/src/components/Common/ActionList.tsx b/src/components/Common/ActionList.tsx index 0233f0bf0..da6cf66a1 100644 --- a/src/components/Common/ActionList.tsx +++ b/src/components/Common/ActionList.tsx @@ -12,6 +12,7 @@ import Divider from '../0_Bruddle/Divider' import { Button } from '../0_Bruddle' import { PEANUT_LOGO_BLACK } from '@/assets/illustrations' import Image from 'next/image' +import { saveRedirectUrl } from '@/utils' import { useRouter } from 'next/navigation' import { PEANUTMAN_LOGO } from '@/assets/peanut' import { BankClaimType, useDetermineBankClaimType } from '@/hooks/useDetermineBankClaimType' @@ -23,7 +24,6 @@ import { BankRequestType, useDetermineBankRequestType } from '@/hooks/useDetermi import { GuestVerificationModal } from '../Global/GuestVerificationModal' import ActionListDaimoPayButton from './ActionListDaimoPayButton' import { ACTION_METHODS, PaymentMethod } from '@/constants/actionlist.consts' -import useClaimLink from '../Claim/useClaimLink' interface IActionListProps { flow: 'claim' | 'request' @@ -50,7 +50,6 @@ export default function ActionList({ claimLinkData, isLoggedIn, flow, requestLin const { requestType } = useDetermineBankRequestType(requesterUserId) const savedAccounts = useSavedAccounts() const { usdAmount } = usePaymentStore() - const { addParamStep } = useClaimLink() const { setShowRequestFulfilmentBankFlowManager, setShowExternalWalletFulfilMethods, @@ -61,7 +60,7 @@ export default function ActionList({ claimLinkData, isLoggedIn, flow, requestLin const handleMethodClick = async (method: PaymentMethod) => { if (flow === 'claim' && claimLinkData) { const amountInUsd = parseFloat(formatUnits(claimLinkData.amount, claimLinkData.tokenDecimals)) - if (method.id === 'bank' && amountInUsd < 5) { + if (method.id === 'bank' && amountInUsd < 2) { setShowMinAmountError(true) return } @@ -69,7 +68,6 @@ export default function ActionList({ claimLinkData, isLoggedIn, flow, requestLin case 'bank': { if (claimType === BankClaimType.GuestKycNeeded) { - addParamStep('bank') setShowVerificationModal(true) } else { if (savedAccounts.length) { @@ -95,7 +93,6 @@ export default function ActionList({ claimLinkData, isLoggedIn, flow, requestLin switch (method.id) { case 'bank': if (requestType === BankRequestType.GuestKycNeeded) { - addParamStep('bank') setIsGuestVerificationModalOpen(true) } else { setShowRequestFulfilmentBankFlowManager(true) @@ -139,7 +136,7 @@ export default function ActionList({ claimLinkData, isLoggedIn, flow, requestLin
) diff --git a/src/components/Common/ActionListDaimoPayButton.tsx b/src/components/Common/ActionListDaimoPayButton.tsx index 0b0b7d9a4..aec0a7ea2 100644 --- a/src/components/Common/ActionListDaimoPayButton.tsx +++ b/src/components/Common/ActionListDaimoPayButton.tsx @@ -34,7 +34,7 @@ const ActionListDaimoPayButton = () => { if (!parsedPaymentData) { console.error('Invalid payment data') - dispatch(paymentActions.setError('Something went wrong. Please try again or contact support.')) + dispatch(paymentActions.setError('Something went wrong. Please try again.')) return false } @@ -45,6 +45,7 @@ const ActionListDaimoPayButton = () => { const payload: InitiatePaymentPayload = { recipient: parsedPaymentData?.recipient, tokenAmount, + isPintaReq: false, // explicitly set to false for non-PINTA requests requestId: requestId ?? undefined, chargeId: chargeDetails?.uuid, currency: currencyCode @@ -68,12 +69,12 @@ const ActionListDaimoPayButton = () => { console.log('Charge created!!') return true } else if (result.status === 'Error') { - dispatch(paymentActions.setError('Something went wrong. Please try again or contact support.')) + dispatch(paymentActions.setError('Something went wrong. Please try again.')) console.error('Payment initiation failed:', result) return false } else { console.warn('Unexpected status from usePaymentInitiator:', result.status) - dispatch(paymentActions.setError('Something went wrong. Please try again or contact support.')) + dispatch(paymentActions.setError('Something went wrong. Please try again.')) return false } }, [ diff --git a/src/components/Common/SavedAccountsView.tsx b/src/components/Common/SavedAccountsView.tsx index 876172ada..fca18a728 100644 --- a/src/components/Common/SavedAccountsView.tsx +++ b/src/components/Common/SavedAccountsView.tsx @@ -83,7 +83,7 @@ export function SavedAccountsMapping({ countryInfo = ALL_METHODS_DATA.find((c) => c.id === 'US') } else { countryInfo = details.countryName - ? ALL_METHODS_DATA.find((c) => c.path.toLowerCase() === details.countryName?.toLowerCase()) + ? ALL_METHODS_DATA.find((c) => c.title.toLowerCase() === details.countryName?.toLowerCase()) : ALL_METHODS_DATA.find((c) => c.id === threeLetterCountryCode) } diff --git a/src/components/CrispChat.tsx b/src/components/CrispChat.tsx index 529de6c59..05f55d660 100644 --- a/src/components/CrispChat.tsx +++ b/src/components/CrispChat.tsx @@ -1,13 +1,13 @@ 'use client' import Script from 'next/script' -import { useSupportModalContext } from '@/context/SupportModalContext' +import { useRouter } from 'next/navigation' export const CrispButton = ({ children, ...rest }: React.HTMLAttributes) => { - const { setIsSupportModalOpen } = useSupportModalContext() + const router = useRouter() const handleClick = () => { - setIsSupportModalOpen(true) + router.push('/support') } return ( diff --git a/src/components/ExchangeRate/index.tsx b/src/components/ExchangeRate/index.tsx index 761cc5c6a..6dc578008 100644 --- a/src/components/ExchangeRate/index.tsx +++ b/src/components/ExchangeRate/index.tsx @@ -1,21 +1,9 @@ import { AccountType } from '@/interfaces' import { PaymentInfoRow } from '@/components/Payment/PaymentInfoRow' import useGetExchangeRate, { IExchangeRate } from '@/hooks/useGetExchangeRate' -import { useExchangeRate } from '@/hooks/useExchangeRate' -interface IExchangeRateProps extends Omit { - nonEuroCurrency?: string - sourceCurrency?: string -} - -const ExchangeRate = ({ accountType, nonEuroCurrency, sourceCurrency = 'USD' }: IExchangeRateProps) => { - const { exchangeRate, isFetchingRate } = useGetExchangeRate({ accountType, enabled: !nonEuroCurrency }) - const { exchangeRate: nonEruoExchangeRate, isLoading } = useExchangeRate({ - sourceCurrency, - destinationCurrency: nonEuroCurrency || 'EUR', - initialSourceAmount: 1, - enabled: !!nonEuroCurrency, - }) +const ExchangeRate = ({ accountType }: IExchangeRate) => { + const { exchangeRate, isFetchingRate } = useGetExchangeRate({ accountType }) const toCurrency = accountType === AccountType.IBAN ? 'EUR' : accountType === AccountType.CLABE ? 'MXN' : 'USD' @@ -23,28 +11,13 @@ const ExchangeRate = ({ accountType, nonEuroCurrency, sourceCurrency = 'USD' }: return } - let displayValue = '-' - let isLoadingRate = false - let moreInfoText = '' - - if (nonEuroCurrency) { - displayValue = nonEruoExchangeRate - ? `1 ${sourceCurrency} = ${parseFloat(nonEruoExchangeRate.toString()).toFixed(4)} ${nonEuroCurrency}` - : '-' - isLoadingRate = isLoading - moreInfoText = - "This is an approximate value. The actual amount received may vary based on your bank's exchange rate" - } else { - displayValue = exchangeRate ? `1 USD = ${parseFloat(exchangeRate).toFixed(4)} ${toCurrency}` : '-' - isLoadingRate = isFetchingRate - moreInfoText = `Exchange rates apply when converting to ${toCurrency}` - } + const displayValue = exchangeRate ? `1 USD = ${parseFloat(exchangeRate).toFixed(4)} ${toCurrency}` : '-' return ( ) diff --git a/src/components/Global/Banner/index.tsx b/src/components/Global/Banner/index.tsx index 4e2a3ac31..cbb990377 100644 --- a/src/components/Global/Banner/index.tsx +++ b/src/components/Global/Banner/index.tsx @@ -1,12 +1,9 @@ -'use client' - -import { usePathname } from 'next/navigation' +import { usePathname, useRouter } from 'next/navigation' import { MaintenanceBanner } from './MaintenanceBanner' import { MarqueeWrapper } from '../MarqueeWrapper' import config from '@/config/routesUnderMaintenance' import { HandThumbsUp } from '@/assets' import Image from 'next/image' -import { useSupportModalContext } from '@/context/SupportModalContext' export function Banner() { const pathname = usePathname() @@ -26,10 +23,10 @@ export function Banner() { } function FeedbackBanner() { - const { setIsSupportModalOpen } = useSupportModalContext() + const router = useRouter() const handleClick = () => { - setIsSupportModalOpen(true) + router.push('/support') } return ( diff --git a/src/components/Global/CreateAccountButton/index.tsx b/src/components/Global/CreateAccountButton/index.tsx deleted file mode 100644 index f367ad66d..000000000 --- a/src/components/Global/CreateAccountButton/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' - -import { PEANUT_LOGO_BLACK, PEANUTMAN_LOGO } from '@/assets' -import { Button } from '@/components/0_Bruddle' -import Image from 'next/image' -import React from 'react' - -interface CreateAccountButtonProps { - onClick: () => void -} - -const CreateAccountButton = ({ onClick }: CreateAccountButtonProps) => { - return ( - - ) -} - -export default CreateAccountButton diff --git a/src/components/Global/DirectSendQR/__tests__/recognizeQr.test.ts b/src/components/Global/DirectSendQR/__tests__/recognizeQr.test.ts index cd33061c3..faba20312 100644 --- a/src/components/Global/DirectSendQR/__tests__/recognizeQr.test.ts +++ b/src/components/Global/DirectSendQR/__tests__/recognizeQr.test.ts @@ -6,6 +6,7 @@ describe('recognizeQr', () => { ['https://peanut.example.org/link/abc', EQrType.PEANUT_URL], ['https://peanut.example.org/something-else', EQrType.PEANUT_URL], ['0x1234567890123456789012345678901234567890', EQrType.EVM_ADDRESS], + ['0x0ff60f43e8c04d57c7374537d8432da8fedbb41d', EQrType.PINTA_MERCHANT], ['vitalik.eth', EQrType.ENS_NAME], ['jota.peanut.me', EQrType.ENS_NAME], ['ethereum:0x1234567890123456789012345678901234567890?value=1e18', EQrType.EIP_681], diff --git a/src/components/Global/DirectSendQR/index.tsx b/src/components/Global/DirectSendQR/index.tsx index e92f242b6..0098213f0 100644 --- a/src/components/Global/DirectSendQR/index.tsx +++ b/src/components/Global/DirectSendQR/index.tsx @@ -254,6 +254,11 @@ export default function DirectSendQr({ redirectUrl = path } break + case EQrType.PINTA_MERCHANT: + { + redirectUrl = `/${data}@polygon/PNT` + } + break case EQrType.EVM_ADDRESS: { toConfirmUrl = `/${data}` diff --git a/src/components/Global/DirectSendQR/utils.ts b/src/components/Global/DirectSendQR/utils.ts index 313b162ea..302a00071 100644 --- a/src/components/Global/DirectSendQR/utils.ts +++ b/src/components/Global/DirectSendQR/utils.ts @@ -1,9 +1,15 @@ import { getTokenSymbol, validateEnsName, getTokenDecimals } from '@/utils' import { isAddress, formatUnits } from 'viem' +// Constants +const PINTA_MERCHANTS: Record = { + '0x0ff60f43e8c04d57c7374537d8432da8fedbb41d': 'Casa Temple', +} + export enum EQrType { PEANUT_URL = 'PEANUT_URL', ENS_NAME = 'ENS_NAME', + PINTA_MERCHANT = 'PINTA_MERCHANT', EVM_ADDRESS = 'EVM_ADDRESS', URL = 'URL', EIP_681 = 'EIP_681', @@ -68,7 +74,7 @@ export function recognizeQr(data: string): QrType | null { return EQrType.PEANUT_URL } if (isAddress(data)) { - return EQrType.EVM_ADDRESS + return PINTA_MERCHANTS[data] ? EQrType.PINTA_MERCHANT : EQrType.EVM_ADDRESS } if (validateEnsName(data)) { return EQrType.ENS_NAME diff --git a/src/components/Global/ExchangeRateWidget/index.tsx b/src/components/Global/ExchangeRateWidget/index.tsx deleted file mode 100644 index 1115d0061..000000000 --- a/src/components/Global/ExchangeRateWidget/index.tsx +++ /dev/null @@ -1,234 +0,0 @@ -import CurrencySelect from '@/components/LandingPage/CurrencySelect' -import { countryCurrencyMappings } from '@/constants/countryCurrencyMapping' -import { useDebounce } from '@/hooks/useDebounce' -import { useExchangeRate } from '@/hooks/useExchangeRate' -import Image from 'next/image' -import { useRouter, useSearchParams } from 'next/navigation' -import { FC, useCallback, useEffect, useMemo } from 'react' -import { Icon, IconName } from '../Icons/Icon' -import { Button } from '@/components/0_Bruddle' - -interface IExchangeRateWidgetProps { - ctaLabel: string - ctaIcon: IconName - ctaAction: () => void -} - -const ExchangeRateWidget: FC = ({ ctaLabel, ctaIcon, ctaAction }) => { - const searchParams = useSearchParams() - const router = useRouter() - - // Get values from URL or use defaults - const sourceCurrency = searchParams.get('from') || 'USD' - const destinationCurrency = searchParams.get('to') || 'EUR' - const rawAmount = searchParams.get('amount') - const parsedAmount = rawAmount !== null ? Number(rawAmount) : 10 - const urlSourceAmount = Number.isFinite(parsedAmount) && parsedAmount > 0 ? parsedAmount : 10 - - // Exchange rate hook handles all the conversion logic - const { - sourceAmount, - destinationAmount, - exchangeRate, - isLoading, - isError, - handleSourceAmountChange, - handleDestinationAmountChange, - getDestinationDisplayValue, - } = useExchangeRate({ - sourceCurrency, - destinationCurrency, - initialSourceAmount: urlSourceAmount, - }) - - const debouncedSourceAmount = useDebounce(sourceAmount, 500) - - // Function to update URL parameters - const updateUrlParams = useCallback( - (params: { from?: string; to?: string; amount?: number }) => { - const newSearchParams = new URLSearchParams(searchParams.toString()) - - if (params.from) newSearchParams.set('from', params.from) - if (params.to) newSearchParams.set('to', params.to) - if (params.amount !== undefined) newSearchParams.set('amount', params.amount.toString()) - - router.replace(`?${newSearchParams.toString()}`, { scroll: false }) - }, - [searchParams, router] - ) - - // Setter functions that update URL - const setSourceCurrency = useCallback( - (currency: string) => { - updateUrlParams({ from: currency }) - }, - [updateUrlParams] - ) - - const setDestinationCurrency = useCallback( - (currency: string) => { - updateUrlParams({ to: currency }) - }, - [updateUrlParams] - ) - - // Update URL when source amount changes (only for valid numbers) - useEffect(() => { - if (typeof debouncedSourceAmount === 'number' && debouncedSourceAmount !== urlSourceAmount) { - updateUrlParams({ amount: debouncedSourceAmount }) - } - }, [debouncedSourceAmount, urlSourceAmount, updateUrlParams]) - - const sourceCurrencyFlag = useMemo( - () => countryCurrencyMappings.find((currency) => currency.currencyCode === sourceCurrency)?.flagCode, - [sourceCurrency] - ) - - const destinationCurrencyFlag = useMemo( - () => countryCurrencyMappings.find((currency) => currency.currencyCode === destinationCurrency)?.flagCode, - [destinationCurrency] - ) - - // Determine delivery time text based on destination currency - const deliveryTimeText = useMemo(() => { - return destinationCurrency === 'USD' ? 'Should arrive in hours.' : 'Should arrive in minutes.' - }, [destinationCurrency]) - - return ( -
-
-

You Send

-
- {isLoading ? ( -
-
-
- ) : ( - { - const inputValue = e.target.value - if (inputValue === '') { - handleSourceAmountChange('') - } else { - const value = parseFloat(inputValue) - handleSourceAmountChange(isNaN(value) ? '' : value) - } - }} - type="number" - className="w-full bg-transparent outline-none" - /> - )} - - {`${sourceCurrencyFlag} - {sourceCurrency} - - } - /> -
-
- -
-

Recipient Gets

-
- {isLoading ? ( -
-
-
- ) : ( - { - const inputValue = e.target.value - if (inputValue === '') { - handleDestinationAmountChange('', '') - } else { - const value = parseFloat(inputValue) - handleDestinationAmountChange(inputValue, isNaN(value) ? '' : value) - } - }} - type="number" - className="w-full bg-transparent outline-none" - /> - )} - - {`${destinationCurrencyFlag} - {destinationCurrency} - - } - /> -
-
- -
- {isLoading ? ( -
- ) : isError ? ( - Rate currently unavailable - ) : ( - <> - 1 {sourceCurrency} = {exchangeRate.toFixed(4)} {destinationCurrency} - - )} -
- - {typeof destinationAmount === 'number' && destinationAmount > 0 && ( -
-
-

Bank fee

-

Free!

-
- -
-

Peanut fee

-

Free!

-
-
- )} - - - - {typeof destinationAmount === 'number' && destinationAmount > 0 && ( -
- -

{deliveryTimeText}

-
- )} -
- ) -} - -export default ExchangeRateWidget diff --git a/src/components/Global/GuestLoginCta/index.tsx b/src/components/Global/GuestLoginCta/index.tsx index 121be04e7..bc51ca6bf 100644 --- a/src/components/Global/GuestLoginCta/index.tsx +++ b/src/components/Global/GuestLoginCta/index.tsx @@ -2,10 +2,10 @@ import { Button } from '@/components/0_Bruddle' import Divider from '@/components/0_Bruddle/Divider' import { useToast } from '@/components/0_Bruddle/Toast' import { useZeroDev } from '@/hooks/useZeroDev' -import { sanitizeRedirectURL, saveRedirectUrl } from '@/utils' +import { saveRedirectUrl } from '@/utils' import { useAppKit } from '@reown/appkit/react' import * as Sentry from '@sentry/nextjs' -import { useRouter, useSearchParams } from 'next/navigation' +import { useRouter } from 'next/navigation' import { useEffect } from 'react' interface GuestLoginCtaProps { @@ -18,7 +18,6 @@ const GuestLoginCta = ({ hideConnectWallet = false, view }: GuestLoginCtaProps) const toast = useToast() const router = useRouter() const { open: openReownModal } = useAppKit() - const searchParams = useSearchParams() // If user already has a passkey address, auto-redirect to avoid double prompting useEffect(() => { @@ -40,11 +39,6 @@ const GuestLoginCta = ({ hideConnectWallet = false, view }: GuestLoginCtaProps) try { await handleLogin() - const redirect_uri = searchParams.get('redirect_uri') - if (redirect_uri) { - const sanitizedRedirectUrl = sanitizeRedirectURL(redirect_uri) - router.push(sanitizedRedirectUrl) - } } catch (e) { toast.error('Error logging in') Sentry.captureException(e) diff --git a/src/components/Global/GuestVerificationModal/index.tsx b/src/components/Global/GuestVerificationModal/index.tsx index 279c45c32..54bd2dab3 100644 --- a/src/components/Global/GuestVerificationModal/index.tsx +++ b/src/components/Global/GuestVerificationModal/index.tsx @@ -9,7 +9,6 @@ interface GuestVerificationModalProps { isOpen: boolean onClose: () => void secondaryCtaLabel: string - redirectToVerification?: boolean } export const GuestVerificationModal = ({ @@ -17,7 +16,6 @@ export const GuestVerificationModal = ({ onClose, description, secondaryCtaLabel, - redirectToVerification, }: GuestVerificationModalProps) => { const router = useRouter() return ( @@ -36,10 +34,6 @@ export const GuestVerificationModal = ({ className: 'md:py-2.5', onClick: () => { saveRedirectUrl() - if (redirectToVerification) { - router.push('/setup?redirect_uri=/profile/identity-verification') - return - } router.push('/setup') }, }, diff --git a/src/components/Global/Icons/Icon.tsx b/src/components/Global/Icons/Icon.tsx index f132a4387..1d240cc46 100644 --- a/src/components/Global/Icons/Icon.tsx +++ b/src/components/Global/Icons/Icon.tsx @@ -120,7 +120,6 @@ export type IconName = | 'processing' | 'failed' | 'chevron-down' - | 'shield' | 'question-mark' | 'shield' diff --git a/src/components/Global/IframeWrapper/index.tsx b/src/components/Global/IframeWrapper/index.tsx index 2aa206a66..113f74020 100644 --- a/src/components/Global/IframeWrapper/index.tsx +++ b/src/components/Global/IframeWrapper/index.tsx @@ -5,7 +5,6 @@ import { Icon, IconName } from '../Icons/Icon' import ActionModal from '../ActionModal' import { useRouter } from 'next/navigation' import StartVerificationView from './StartVerificationView' -import { useSupportModalContext } from '@/context/SupportModalContext' export type IFrameWrapperProps = { src: string @@ -21,7 +20,6 @@ const IframeWrapper = ({ src, visible, onClose, closeConfirmMessage }: IFrameWra const [copied, setCopied] = useState(false) const [isVerificationStarted, setIsVerificationStarted] = useState(false) const router = useRouter() - const { setIsSupportModalOpen } = useSupportModalContext() const handleCopy = (textToCopy: string) => { navigator.clipboard.writeText(textToCopy).then(() => { @@ -56,7 +54,7 @@ const IframeWrapper = ({ src, visible, onClose, closeConfirmMessage }: IFrameWra { text: 'Chat with support', icon: 'peanut-support' as IconName, - onClick: () => setIsSupportModalOpen(true), + onClick: () => router.push('/support'), variant: 'transparent' as ButtonVariant, className: 'underline text-sm font-medium w-full fill-none h-fit mt-3', }, @@ -140,11 +138,11 @@ const IframeWrapper = ({ src, visible, onClose, closeConfirmMessage }: IFrameWra key={src} src={src} allow="camera;" - style={{ width: '100%', height: '85%', border: 'none' }} + style={{ width: '100%', height: '80%', border: 'none' }} className="rounded-md" sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation-by-user-activation" /> -
+