From 4a7c6006fe5c8bb4a041331ce8b333c9dc03b0a7 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Wed, 5 Nov 2025 23:01:09 +0530 Subject: [PATCH 01/14] feat: Add merchant map cta design --- .../Home/HomeCarouselCTA/CarouselCTA.tsx | 19 ++++++++++++++++--- src/components/Home/HomeCarouselCTA/index.tsx | 1 + src/hooks/useHomeCarouselCTAs.tsx | 13 +++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/components/Home/HomeCarouselCTA/CarouselCTA.tsx b/src/components/Home/HomeCarouselCTA/CarouselCTA.tsx index 060cc51a0..a87202950 100644 --- a/src/components/Home/HomeCarouselCTA/CarouselCTA.tsx +++ b/src/components/Home/HomeCarouselCTA/CarouselCTA.tsx @@ -19,6 +19,7 @@ interface CarouselCTAProps { iconContainerClassName?: string // Notification-specific props isPermissionDenied?: boolean + secondaryIcon?: StaticImageData | string } const CarouselCTA = ({ @@ -30,6 +31,7 @@ const CarouselCTA = ({ logo, iconContainerClassName, isPermissionDenied, + secondaryIcon, }: CarouselCTAProps) => { const [showPermissionDeniedModal, setShowPermissionDeniedModal] = useState(false) @@ -87,15 +89,26 @@ const CarouselCTA = ({ {/* Icon container */}
{/* Show icon only if logo isn't provided. Logo takes precedence over icon. */} - {!logo && } + {!logo && } {logo && ( - {typeof + {typeof + )} + + {secondaryIcon && ( + secondary icon )}
diff --git a/src/components/Home/HomeCarouselCTA/index.tsx b/src/components/Home/HomeCarouselCTA/index.tsx index e7ad1bf00..779b4ccff 100644 --- a/src/components/Home/HomeCarouselCTA/index.tsx +++ b/src/components/Home/HomeCarouselCTA/index.tsx @@ -31,6 +31,7 @@ const HomeCarouselCTA = () => { logo={cta.logo} iconContainerClassName={cta.iconContainerClassName} isPermissionDenied={cta.isPermissionDenied} + secondaryIcon={cta.secondaryIcon} /> ))} diff --git a/src/hooks/useHomeCarouselCTAs.tsx b/src/hooks/useHomeCarouselCTAs.tsx index 325212874..a3141c719 100644 --- a/src/hooks/useHomeCarouselCTAs.tsx +++ b/src/hooks/useHomeCarouselCTAs.tsx @@ -7,6 +7,7 @@ import { useNotifications } from './useNotifications' import { useRouter } from 'next/navigation' import useKycStatus from './useKycStatus' import type { StaticImageData } from 'next/image' +import { PIX } from '@/assets' export type CarouselCTA = { id: string @@ -19,6 +20,7 @@ export type CarouselCTA = { onClose?: () => void isPermissionDenied?: boolean iconContainerClassName?: string + secondaryIcon?: StaticImageData | string } export const useHomeCarouselCTAs = () => { @@ -32,6 +34,17 @@ export const useHomeCarouselCTAs = () => { const generateCarouselCTAs = useCallback(() => { const _carouselCTAs: CarouselCTA[] = [] + _carouselCTAs.push({ + id: 'merchant-map-pix', + title: '20% Off with PIX Payments', + description: 'Click to explore participating merchants. Pay with PIX QR, save instantly, earn points.', + iconContainerClassName: 'bg-secondary-1', + icon: 'shield', + onClick: () => {}, + logo: PIX, + secondaryIcon: 'https://flagcdn.com/w320/br.png', + }) + // add notification prompt as first item if it should be shown if (showReminderBanner) { _carouselCTAs.push({ From 27f6e52db691fce049b9eb2013c8d968f1b8a73d Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Thu, 6 Nov 2025 19:04:04 +0530 Subject: [PATCH 02/14] feat: Add link --- src/hooks/useHomeCarouselCTAs.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hooks/useHomeCarouselCTAs.tsx b/src/hooks/useHomeCarouselCTAs.tsx index a3141c719..22db2da83 100644 --- a/src/hooks/useHomeCarouselCTAs.tsx +++ b/src/hooks/useHomeCarouselCTAs.tsx @@ -40,7 +40,9 @@ export const useHomeCarouselCTAs = () => { description: 'Click to explore participating merchants. Pay with PIX QR, save instantly, earn points.', iconContainerClassName: 'bg-secondary-1', icon: 'shield', - onClick: () => {}, + onClick: () => { + router.push('https://www.notion.so/peanutprotocol/Peanut-Foodie-Guide-29a83811757980e79896f2a610d6591a') + }, logo: PIX, secondaryIcon: 'https://flagcdn.com/w320/br.png', }) From 0d4a7facb2d6776a9c24ea937f46b65afea14570 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Thu, 6 Nov 2025 19:09:50 +0530 Subject: [PATCH 03/14] update merhcant map link --- src/hooks/useHomeCarouselCTAs.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hooks/useHomeCarouselCTAs.tsx b/src/hooks/useHomeCarouselCTAs.tsx index 22db2da83..3db53951d 100644 --- a/src/hooks/useHomeCarouselCTAs.tsx +++ b/src/hooks/useHomeCarouselCTAs.tsx @@ -41,7 +41,9 @@ export const useHomeCarouselCTAs = () => { iconContainerClassName: 'bg-secondary-1', icon: 'shield', onClick: () => { - router.push('https://www.notion.so/peanutprotocol/Peanut-Foodie-Guide-29a83811757980e79896f2a610d6591a') + router.push( + 'https://peanutprotocol.notion.site/297838117579804da61dc45760a2599f?v=29783811757980a1b23a000cce31c330' + ) }, logo: PIX, secondaryIcon: 'https://flagcdn.com/w320/br.png', From 5630a3819b14f97eedee92555cd97f1b15180aa8 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Thu, 6 Nov 2025 22:13:01 +0530 Subject: [PATCH 04/14] update CTA Link --- src/hooks/useHomeCarouselCTAs.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hooks/useHomeCarouselCTAs.tsx b/src/hooks/useHomeCarouselCTAs.tsx index 3db53951d..b388afad2 100644 --- a/src/hooks/useHomeCarouselCTAs.tsx +++ b/src/hooks/useHomeCarouselCTAs.tsx @@ -41,9 +41,7 @@ export const useHomeCarouselCTAs = () => { iconContainerClassName: 'bg-secondary-1', icon: 'shield', onClick: () => { - router.push( - 'https://peanutprotocol.notion.site/297838117579804da61dc45760a2599f?v=29783811757980a1b23a000cce31c330' - ) + router.push('https://peanutprotocol.notion.site/Peanut-Foodie-Guide-29a83811757980e79896f2a610d6591a') }, logo: PIX, secondaryIcon: 'https://flagcdn.com/w320/br.png', From 08d82aff5e9837b9c69e569583b53007a769a397 Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Wed, 5 Nov 2025 17:02:49 -0300 Subject: [PATCH 05/14] simplefi did breaking changes --- .../__tests__/recognizeQr.test.ts | 71 ++++++++++++++++--- src/components/Global/DirectSendQR/utils.ts | 9 ++- 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/components/Global/DirectSendQR/__tests__/recognizeQr.test.ts b/src/components/Global/DirectSendQR/__tests__/recognizeQr.test.ts index 9aba5276a..70c4406da 100644 --- a/src/components/Global/DirectSendQR/__tests__/recognizeQr.test.ts +++ b/src/components/Global/DirectSendQR/__tests__/recognizeQr.test.ts @@ -321,6 +321,15 @@ describe('recognizeQr', () => { ['www.pagar.simplefi.tech/peanut-test?static=true', 'without protocol'], ['pagar.simplefi.tech/peanut-test?static=true', 'without www and protocol'], ['https://pagar.simplefi.tech/merchant-123/static', 'with numeric merchant slug'], + // New pay.simplefi.tech URLs + ['https://pay.simplefi.tech/peanut-test/static', 'pay subdomain with /static path'], + ['https://www.pay.simplefi.tech/peanut-test/static', 'pay subdomain with www'], + ['http://www.pay.simplefi.tech/peanut-test/static', 'pay subdomain http protocol'], + ['http://www.pay.simplefi.tech/peanut-test/static?stupid=params', 'pay subdomain with query params'], + ['https://pay.simplefi.tech/peanut-test?static=true', 'pay subdomain with static=true param'], + ['www.pay.simplefi.tech/peanut-test?static=true', 'pay subdomain without protocol'], + ['pay.simplefi.tech/peanut-test?static=true', 'pay subdomain without www and protocol'], + ['https://pay.simplefi.tech/merchant-123/static', 'pay subdomain with numeric merchant slug'], ])('should recognize %s (%s)', (data, _description) => { expect(recognizeQr(data)).toBe(EQrType.SIMPLEFI_STATIC) }) @@ -337,18 +346,31 @@ describe('recognizeQr', () => { describe('SIMPLEFI_DYNAMIC', () => { it.each([ - ['https://pagar.simplefi.tech/1234/payment/5678', 'standard dynamic payment'], - ['https://www.pagar.simplefi.tech/merchant-slug/payment/pay-id-123', 'with www'], - ['http://pagar.simplefi.tech/abc/payment/def', 'http protocol'], - ['pagar.simplefi.tech/merchant/payment/payment-id', 'without protocol'], + // Old format with /payment/ (backward compatibility) + ['https://pagar.simplefi.tech/1234/payment/5678', 'old format: standard dynamic payment'], + ['https://www.pagar.simplefi.tech/merchant-slug/payment/pay-id-123', 'old format: with www'], + ['http://pagar.simplefi.tech/abc/payment/def', 'old format: http protocol'], + ['pagar.simplefi.tech/merchant/payment/payment-id', 'old format: without protocol'], + ['https://pay.simplefi.tech/1234/payment/5678', 'old format: pay subdomain'], + ['https://www.pay.simplefi.tech/merchant-slug/payment/pay-id-123', 'old format: pay subdomain with www'], + ['http://pay.simplefi.tech/abc/payment/def', 'old format: pay subdomain http protocol'], + ['pay.simplefi.tech/merchant/payment/payment-id', 'old format: pay subdomain without protocol'], + // New format without /payment/ (current) + ['https://pagar.simplefi.tech/1234/5678', 'new format: pagar subdomain'], + ['https://www.pagar.simplefi.tech/merchant-slug/pay-id-123', 'new format: pagar with www'], + ['http://pagar.simplefi.tech/abc/def', 'new format: pagar http protocol'], + ['pagar.simplefi.tech/merchant/payment-id', 'new format: pagar without protocol'], + ['https://pay.simplefi.tech/1234/5678', 'new format: pay subdomain'], + ['https://www.pay.simplefi.tech/merchant-slug/pay-id-123', 'new format: pay with www'], + ['http://pay.simplefi.tech/abc/def', 'new format: pay http protocol'], + ['pay.simplefi.tech/merchant/payment-id', 'new format: pay without protocol'], ])('should recognize %s (%s)', (data, _description) => { expect(recognizeQr(data)).toBe(EQrType.SIMPLEFI_DYNAMIC) }) it.each([ - ['https://pagar.simplefi.tech/1234/payment', 'missing payment ID'], - ['https://pagar.simplefi.tech/payment/5678', 'missing merchant ID'], - ['https://pagar.simplefi.tech/1234/pay/5678', 'wrong path segment (pay vs payment)'], + ['https://pagar.simplefi.tech/1234/pay/5678/extra', 'too many path segments'], + ['https://pagar.simplefi.tech/merchant', 'only one path segment (should be USER_SPECIFIED)'], ])('should NOT recognize %s as SIMPLEFI_DYNAMIC (%s)', (data, _description) => { expect(recognizeQr(data)).not.toBe(EQrType.SIMPLEFI_DYNAMIC) }) @@ -361,13 +383,21 @@ describe('recognizeQr', () => { ['http://pagar.simplefi.tech/shop-name', 'http protocol'], ['pagar.simplefi.tech/store', 'without protocol'], ['https://pagar.simplefi.tech/merchant-with-dashes', 'merchant with dashes'], + // New pay.simplefi.tech URLs + ['https://pay.simplefi.tech/peanut-test', 'pay subdomain basic merchant slug'], + ['https://www.pay.simplefi.tech/merchant', 'pay subdomain with www'], + ['http://pay.simplefi.tech/shop-name', 'pay subdomain http protocol'], + ['pay.simplefi.tech/store', 'pay subdomain without protocol'], + ['https://pay.simplefi.tech/merchant-with-dashes', 'pay subdomain merchant with dashes'], ])('should recognize %s (%s)', (data, _description) => { expect(recognizeQr(data)).toBe(EQrType.SIMPLEFI_USER_SPECIFIED) }) it.each([ ['https://other-domain.com/merchant', 'wrong domain'], - ['https://simplefi.tech/merchant', 'missing pagar subdomain'], + ['https://simplefi.tech/merchant', 'missing pagar/pay subdomain'], + ['https://pagar.simplefi.tech/merchant/123', 'two path segments (should be DYNAMIC)'], + ['https://pay.simplefi.tech/merchant/456', 'two path segments on pay subdomain (should be DYNAMIC)'], ])('should NOT recognize %s as SIMPLEFI_USER_SPECIFIED (%s)', (data, _description) => { expect(recognizeQr(data)).not.toBe(EQrType.SIMPLEFI_USER_SPECIFIED) }) @@ -376,6 +406,11 @@ describe('recognizeQr', () => { // The regex captures an empty merchant slug with trailing slash expect(recognizeQr('https://pagar.simplefi.tech/')).toBe(EQrType.SIMPLEFI_USER_SPECIFIED) }) + + it('should recognize https://pay.simplefi.tech/ as SIMPLEFI_USER_SPECIFIED (regex matches trailing slash)', () => { + // The regex captures an empty merchant slug with trailing slash + expect(recognizeQr('https://pay.simplefi.tech/')).toBe(EQrType.SIMPLEFI_USER_SPECIFIED) + }) }) describe('URL (generic)', () => { @@ -457,6 +492,26 @@ describe('recognizeQr', () => { expect(recognizeQr(dynamicUrl)).toBe(EQrType.SIMPLEFI_DYNAMIC) }) + it('should prioritize SIMPLEFI_STATIC over SIMPLEFI_USER_SPECIFIED for pay.simplefi.tech', () => { + const staticUrl = 'https://pay.simplefi.tech/merchant/static' + expect(recognizeQr(staticUrl)).toBe(EQrType.SIMPLEFI_STATIC) + }) + + it('should prioritize SIMPLEFI_DYNAMIC over SIMPLEFI_USER_SPECIFIED for pay.simplefi.tech', () => { + const dynamicUrl = 'https://pay.simplefi.tech/merchant/payment/123' + expect(recognizeQr(dynamicUrl)).toBe(EQrType.SIMPLEFI_DYNAMIC) + }) + + it('should prioritize SIMPLEFI_DYNAMIC (new format) over SIMPLEFI_USER_SPECIFIED for pagar.simplefi.tech', () => { + const dynamicUrlNewFormat = 'https://pagar.simplefi.tech/merchant/123' + expect(recognizeQr(dynamicUrlNewFormat)).toBe(EQrType.SIMPLEFI_DYNAMIC) + }) + + it('should prioritize SIMPLEFI_DYNAMIC (new format) over SIMPLEFI_USER_SPECIFIED for pay.simplefi.tech', () => { + const dynamicUrlNewFormat = 'https://pay.simplefi.tech/merchant/456' + expect(recognizeQr(dynamicUrlNewFormat)).toBe(EQrType.SIMPLEFI_DYNAMIC) + }) + it('should prioritize ENS_NAME over URL for valid ENS domains', () => { const ensName = 'vitalik.eth' expect(recognizeQr(ensName)).toBe(EQrType.ENS_NAME) diff --git a/src/components/Global/DirectSendQR/utils.ts b/src/components/Global/DirectSendQR/utils.ts index 1c37a990d..b811c58f7 100644 --- a/src/components/Global/DirectSendQR/utils.ts +++ b/src/components/Global/DirectSendQR/utils.ts @@ -68,12 +68,15 @@ const PIX_REGEX = /^.*000201.*0014br\.gov\.bcb\.pix.*5303986.*5802BR.*$/i * infer the flow type and merchant slug. * * The flow type is static, dynamic or user_specified. + * Supports both pagar.simplefi.tech (legacy) and pay.simplefi.tech (new) URLs. + * Dynamic URLs support both old format (/merchant/payment/123) and new format (/merchant/123). */ export const SIMPLEFI_STATIC_REGEX = - /^(?:https?:\/\/)?(?:www\.)?pagar\.simplefi\.tech\/(?[^\/]*)(\/static|\/?\?.*static\=true.*)/ -export const SIMPLEFI_USER_SPECIFIED_REGEX = /^(?:https?:\/\/)?(?:www\.)?pagar\.simplefi\.tech\/(?[^\/]*)/ + /^(?:https?:\/\/)?(?:www\.)?(?:pagar|pay)\.simplefi\.tech\/(?[^\/]*)(\/static|\/?\?.*static\=true.*)/ +export const SIMPLEFI_USER_SPECIFIED_REGEX = + /^(?:https?:\/\/)?(?:www\.)?(?:pagar|pay)\.simplefi\.tech\/(?[^\/\?]*)(?:\/)?(?:\?.*)?$/ export const SIMPLEFI_DYNAMIC_REGEX = - /^(?:https?:\/\/)?(?:www\.)?pagar\.simplefi\.tech\/(?[^\/]*)\/payment\/(?[^\/]*)/ + /^(?:https?:\/\/)?(?:www\.)?(?:pagar|pay)\.simplefi\.tech\/(?[^\/]*)\/(?:payment\/)?(?[^\/\?]+)(?:\/)?(?:\?.*)?$/ export const PAYMENT_PROCESSOR_REGEXES: { [key in QrType]?: RegExp } = { [EQrType.MERCADO_PAGO]: MP_AR_REGEX, From 204d4b6d7db98febf2700ed6e0c09cf55517c272 Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Wed, 5 Nov 2025 17:12:24 -0300 Subject: [PATCH 06/14] fix --- src/app/(mobile-ui)/qr-pay/page.tsx | 33 +++++++++++++++-------------- src/hooks/useQrKycGate.ts | 13 ++++++++++-- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/app/(mobile-ui)/qr-pay/page.tsx b/src/app/(mobile-ui)/qr-pay/page.tsx index e94e288ba..e6d38421e 100644 --- a/src/app/(mobile-ui)/qr-pay/page.tsx +++ b/src/app/(mobile-ui)/qr-pay/page.tsx @@ -78,7 +78,23 @@ export default function QRPayPage() { const { openTransactionDetails, selectedTransaction, isDrawerOpen, closeTransactionDetails } = useTransactionDetailsDrawer() const { isLoading, loadingState, setLoadingState } = useContext(loadingStateContext) - const { shouldBlockPay, kycGateState } = useQrKycGate() + + const paymentProcessor: PaymentProcessor | null = useMemo(() => { + switch (qrType) { + case EQrType.SIMPLEFI_STATIC: + case EQrType.SIMPLEFI_DYNAMIC: + case EQrType.SIMPLEFI_USER_SPECIFIED: + return 'SIMPLEFI' + case EQrType.MERCADO_PAGO: + case EQrType.ARGENTINA_QR3: + case EQrType.PIX: + return 'MANTECA' + default: + return null + } + }, [qrType]) + + const { shouldBlockPay, kycGateState } = useQrKycGate(paymentProcessor) const queryClient = useQueryClient() const { hasPendingTransactions } = usePendingTransactions() const [isShaking, setIsShaking] = useState(false) @@ -97,21 +113,6 @@ export default function QRPayPage() { const [waitingForMerchantAmount, setWaitingForMerchantAmount] = useState(false) const retryCount = useRef(0) - const paymentProcessor: PaymentProcessor | null = useMemo(() => { - switch (qrType) { - case EQrType.SIMPLEFI_STATIC: - case EQrType.SIMPLEFI_DYNAMIC: - case EQrType.SIMPLEFI_USER_SPECIFIED: - return 'SIMPLEFI' - case EQrType.MERCADO_PAGO: - case EQrType.ARGENTINA_QR3: - case EQrType.PIX: - return 'MANTECA' - default: - return null - } - }, [qrType]) - const resetState = () => { setIsSuccess(false) setErrorMessage(null) diff --git a/src/hooks/useQrKycGate.ts b/src/hooks/useQrKycGate.ts index 26a8a63e8..c90fb7f78 100644 --- a/src/hooks/useQrKycGate.ts +++ b/src/hooks/useQrKycGate.ts @@ -21,13 +21,22 @@ export interface QrKycGateResult { /** * This hook determines the KYC gate state for the QR pay page. * It checks the user's KYC status and the country of the QR code to determine the appropriate action. + * @param paymentProcessor - The payment processor type ('MANTECA' | 'SIMPLEFI' | null) * @returns {QrKycGateResult} An object with the KYC gate state and a boolean indicating if the user should be blocked from paying. + * + * Note: KYC is only required for MANTECA payments. SimpleFi payments do not require KYC. */ -export function useQrKycGate(): QrKycGateResult { +export function useQrKycGate(paymentProcessor?: 'MANTECA' | 'SIMPLEFI' | null): QrKycGateResult { const { user } = useAuth() const [kycGateState, setKycGateState] = useState(QrKycState.LOADING) const determineKycGateState = useCallback(async () => { + // SimpleFi payments do not require KYC - allow payment immediately + if (paymentProcessor === 'SIMPLEFI') { + setKycGateState(QrKycState.PROCEED_TO_PAY) + return + } + const currentUser = user?.user if (!currentUser) { setKycGateState(QrKycState.REQUIRES_IDENTITY_VERIFICATION) @@ -68,7 +77,7 @@ export function useQrKycGate(): QrKycGateResult { } setKycGateState(QrKycState.REQUIRES_IDENTITY_VERIFICATION) - }, [user?.user]) + }, [user?.user, paymentProcessor]) useEffect(() => { determineKycGateState() From 4d27b23602605300f8572fd731bc5a1d4fa265fc Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Wed, 5 Nov 2025 17:19:02 -0300 Subject: [PATCH 07/14] format --- src/hooks/useQrKycGate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useQrKycGate.ts b/src/hooks/useQrKycGate.ts index c90fb7f78..e4d175f8b 100644 --- a/src/hooks/useQrKycGate.ts +++ b/src/hooks/useQrKycGate.ts @@ -23,7 +23,7 @@ export interface QrKycGateResult { * It checks the user's KYC status and the country of the QR code to determine the appropriate action. * @param paymentProcessor - The payment processor type ('MANTECA' | 'SIMPLEFI' | null) * @returns {QrKycGateResult} An object with the KYC gate state and a boolean indicating if the user should be blocked from paying. - * + * * Note: KYC is only required for MANTECA payments. SimpleFi payments do not require KYC. */ export function useQrKycGate(paymentProcessor?: 'MANTECA' | 'SIMPLEFI' | null): QrKycGateResult { From dc7a9b2e90a9828466b918ba7a75a4c18fab173c Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Wed, 5 Nov 2025 17:45:20 -0300 Subject: [PATCH 08/14] fix: amount --- src/app/(mobile-ui)/qr-pay/page.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/app/(mobile-ui)/qr-pay/page.tsx b/src/app/(mobile-ui)/qr-pay/page.tsx index e6d38421e..1209d64fc 100644 --- a/src/app/(mobile-ui)/qr-pay/page.tsx +++ b/src/app/(mobile-ui)/qr-pay/page.tsx @@ -302,6 +302,22 @@ export default function QRPayPage() { getCurrencyObject().then(setCurrency) }, [paymentLock?.code, paymentProcessor]) + // Set default currency for SimpleFi USER_SPECIFIED (user will enter amount) + useEffect(() => { + if (paymentProcessor !== 'SIMPLEFI') return + if (simpleFiQrData?.type !== 'SIMPLEFI_USER_SPECIFIED') return + if (currency) return // Already set + + // Default to ARS for SimpleFi payments + getCurrencyPrice('ARS').then((priceData) => { + setCurrency({ + code: 'ARS', + symbol: 'ARS', + price: priceData.sell, + }) + }) + }, [paymentProcessor, simpleFiQrData?.type, currency]) + const isBlockingError = useMemo(() => { return !!errorMessage && errorMessage !== 'Please confirm the transaction.' }, [errorMessage]) From 9648771df9e0687144800986b69e91d77df32f71 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Tue, 4 Nov 2025 20:37:21 +0530 Subject: [PATCH 09/14] feat: update kyc history card design --- src/components/Kyc/KycStatusItem.tsx | 33 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/components/Kyc/KycStatusItem.tsx b/src/components/Kyc/KycStatusItem.tsx index 9d7181d2e..480ae71be 100644 --- a/src/components/Kyc/KycStatusItem.tsx +++ b/src/components/Kyc/KycStatusItem.tsx @@ -10,6 +10,7 @@ import { type HTMLAttributes } from 'react' import { twMerge } from 'tailwind-merge' import { type IUserKycVerification } from '@/interfaces' import { Icon } from '@/components/Global/Icons/Icon' +import StatusPill from '../Global/StatusPill' // this component shows the current kyc status and opens a drawer with more details on click export const KycStatusItem = ({ @@ -45,23 +46,21 @@ export const KycStatusItem = ({ const finalBridgeKycStatus = wsBridgeKycStatus || bridgeKycStatus || user?.user?.bridgeKycStatus const kycStatus = verification ? verification.status : finalBridgeKycStatus + // Check if KYC is approved to show points earned + const isApproved = kycStatus === 'approved' || kycStatus === 'ACTIVE' + + const isPending = kycStatus === 'under_review' || kycStatus === 'ONBOARDING' + const isRejected = kycStatus === 'rejected' || kycStatus === 'INACTIVE' + const subtitle = useMemo(() => { - const date = verification - ? (verification.approvedAt ?? verification.updatedAt ?? verification.createdAt) - : bridgeKycStartedAt - if (!date) { - return 'Verification in progress' + if (isPending) { + return 'Under review' } - try { - return `Submitted on ${formatDate(new Date(date)).split(' - ')[0]}` - } catch (error) { - console.error('Failed to parse date:', error) - return 'Verification in progress' + if (isApproved) { + return 'Approved' } - }, [bridgeKycStartedAt, verification]) - - // Check if KYC is approved to show points earned - const isApproved = kycStatus === 'approved' || kycStatus === 'ACTIVE' + return 'Rejected' + }, [isPending, isApproved, isRejected]) if (!kycStatus || kycStatus === 'not_started') { return null @@ -81,10 +80,12 @@ export const KycStatusItem = ({

Identity verification

-

{subtitle}

+
+

{subtitle}

+ +
- {isApproved && } From 5cd4aba1522a4ad6a7b385d7f378efb4415520b4 Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Thu, 6 Nov 2025 20:06:45 +0530 Subject: [PATCH 10/14] hotfix: Add blur to QR code till request is created --- src/components/Global/QRCodeWrapper/index.tsx | 5 ++- .../link/views/Create.request.link.view.tsx | 40 +++++++++++++------ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/components/Global/QRCodeWrapper/index.tsx b/src/components/Global/QRCodeWrapper/index.tsx index 37fad75bf..b0ae65b99 100644 --- a/src/components/Global/QRCodeWrapper/index.tsx +++ b/src/components/Global/QRCodeWrapper/index.tsx @@ -8,9 +8,10 @@ interface QRCodeWrapperProps { url: string isLoading?: boolean disabled?: boolean + isBlurred?: boolean } -const QRCodeWrapper = ({ url, isLoading = false, disabled = false }: QRCodeWrapperProps) => { +const QRCodeWrapper = ({ url, isLoading = false, disabled = false, isBlurred = false }: QRCodeWrapperProps) => { return (
{/* Container with black border and rounded corners */} @@ -21,7 +22,7 @@ const QRCodeWrapper = ({ url, isLoading = false, disabled = false }: QRCodeWrapp )} > {/* QR Code with white buffer */} -
+
{
- + { setAttachmentOptions={handleAttachmentOptionsChange} /> - {isCreatingLink || isUpdatingRequest ? ( - - ) : ( - - {!tokenValue || !parseFloat(tokenValue) || parseFloat(tokenValue) === 0 - ? 'Share open request' - : `Share $${tokenValue} request`} - )} + {requestId && + (isCreatingLink || isUpdatingRequest ? ( + + ) : ( + + {!tokenValue || !parseFloat(tokenValue) || parseFloat(tokenValue) === 0 + ? 'Share open request' + : `Share $${tokenValue} request`} + + ))} + {errorState.showError && (
From 59d70643cfbe64c2f972dc0effcfdb2550d6d86f Mon Sep 17 00:00:00 2001 From: Zishan Mohd Date: Thu, 6 Nov 2025 20:41:38 +0530 Subject: [PATCH 11/14] Add bill split for QR payments --- src/app/(mobile-ui)/qr-pay/page.tsx | 23 +++++++++++++++++++ .../link/views/Create.request.link.view.tsx | 7 ++++++ 2 files changed, 30 insertions(+) diff --git a/src/app/(mobile-ui)/qr-pay/page.tsx b/src/app/(mobile-ui)/qr-pay/page.tsx index 1209d64fc..377980c49 100644 --- a/src/app/(mobile-ui)/qr-pay/page.tsx +++ b/src/app/(mobile-ui)/qr-pay/page.tsx @@ -1133,6 +1133,18 @@ export default function QRPayPage() { ) : ( <> + + - - - +