-
Notifications
You must be signed in to change notification settings - Fork 13
[TASK-12883] Add manteca QR payments #1190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9b2cb33
1cecd4a
6915387
31e2c49
1b7aad5
15527d5
a3e15c0
1e6f3dd
5642079
d9b283d
22ac554
da60e40
8009ee5
4f53108
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { generateMetadata } from '@/app/metadata' | ||
import PageContainer from '@/components/0_Bruddle/PageContainer' | ||
import React from 'react' | ||
|
||
export const metadata = generateMetadata({ | ||
title: 'QR Payment | Peanut', | ||
description: 'Use Peanut to pay Argentinian MercadoPago and Brazilian Pix QR codes', | ||
}) | ||
|
||
export default function QRPayLayout({ children }: { children: React.ReactNode }) { | ||
return <PageContainer>{children}</PageContainer> | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,7 +50,12 @@ const MP_AR_REGEX = | |
/^000201((?!6304).)*(?:(?:26|27|28|29|30|31|35|43)\d{2}(?:0015com\.mercadopago|0016com\.mercadolibre)).*5303032.*5802AR((?!6304).)*6304[0-9A-F]{4}$/i | ||
|
||
/* PIX is also a emvco qr code */ | ||
const PIX_REGEX = /^.*00020126.*0014br\.gov\.bcb\.pix.*5303986.*5802BR.*$/i | ||
const PIX_REGEX = /^.*000201.*0014br\.gov\.bcb\.pix.*5303986.*5802BR.*$/i | ||
|
||
export const PAYMENT_PROCESSOR_REGEXES: { [key in QrType]?: RegExp } = { | ||
[EQrType.MERCADO_PAGO]: MP_AR_REGEX, | ||
[EQrType.PIX]: PIX_REGEX, | ||
} | ||
|
||
const EIP_681_REGEX = /^ethereum:(?:pay-)?([^@/?]+)(?:@([^/?]+))?(?:\/([^?]+))?(?:\?(.*))?$/i | ||
|
||
|
@@ -88,6 +93,19 @@ export function recognizeQr(data: string): QrType | null { | |
return null | ||
} | ||
|
||
/** | ||
* Returns true if the given string is a payment processor QR code. | ||
* For example, Mercado Pago, Pix, etc. | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thx |
||
export const isPaymentProcessorQR = (data: string): boolean => { | ||
for (const [_type, regex] of Object.entries(PAYMENT_PROCESSOR_REGEXES)) { | ||
if (regex.test(data)) { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
/** | ||
* Extracts EIP-681 parameters from an Ethereum URI | ||
* @param data The Ethereum URI string (e.g. "ethereum:0x123...?value=1e18") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,6 +125,10 @@ const TokenAmountInput = ({ | |
[displayMode, currency?.price, selectedTokenData?.price, calculateAlternativeValue] | ||
) | ||
|
||
const showConversion = useMemo(() => { | ||
return !hideCurrencyToggle && (displayMode === 'TOKEN' || displayMode === 'FIAT') | ||
}, [hideCurrencyToggle, displayMode]) | ||
|
||
// This is needed because if we change the token we selected the value | ||
// should change. This only depends on the price on purpose!! we don't want | ||
// to change when we change the display mode or the value (we already call | ||
|
@@ -152,11 +156,11 @@ const TokenAmountInput = ({ | |
} | ||
case 'FIAT': { | ||
if (isInputUsd) { | ||
setDisplaySymbol('$') | ||
setDisplaySymbol('USD') | ||
setAlternativeDisplaySymbol(currency?.symbol || '') | ||
} else { | ||
setDisplaySymbol(currency?.symbol || '') | ||
setAlternativeDisplaySymbol('$') | ||
setAlternativeDisplaySymbol('USD') | ||
} | ||
break | ||
} | ||
|
@@ -196,48 +200,62 @@ const TokenAmountInput = ({ | |
return ( | ||
<form | ||
ref={formRef} | ||
className={`relative cursor-text rounded-none border border-n-1 bg-white px-2 py-4 dark:border-white ${className}`} | ||
className={`relative cursor-text rounded-sm border border-n-1 bg-white p-2 dark:border-white ${className}`} | ||
action="" | ||
onClick={handleContainerClick} | ||
> | ||
<div className="flex h-14 w-full flex-row items-center justify-center gap-1"> | ||
<label className={`text-h1 ${displayValue ? 'text-black' : 'text-gray-2'}`}>{displaySymbol}</label> | ||
<input | ||
className={`h-12 max-w-80 bg-transparent text-center text-h1 outline-none transition-colors placeholder:text-h1 focus:border-primary-1 dark:border-white dark:bg-n-1 dark:text-white dark:placeholder:text-white/75 dark:focus:border-primary-1`} | ||
placeholder={'0.00'} | ||
onChange={(e) => { | ||
const value = formatAmountWithoutComma(e.target.value) | ||
onChange(value, isInputUsd) | ||
}} | ||
ref={inputRef} | ||
inputMode="decimal" | ||
type={inputType} | ||
value={displayValue} | ||
step="any" | ||
min="0" | ||
autoComplete="off" | ||
onKeyDown={(e) => { | ||
if (e.key === 'Enter') { | ||
e.preventDefault() | ||
if (onSubmit) onSubmit() | ||
} | ||
}} | ||
onBlur={() => { | ||
if (onBlur) onBlur() | ||
}} | ||
disabled={disabled} | ||
/> | ||
</div> | ||
{walletBalance && !hideBalance && ( | ||
<div className="mt-0.5 text-center text-xs text-grey-1"> | ||
Your balance: {displayMode === 'FIAT' && currency ? 'US$' : '$'} | ||
{walletBalance} | ||
<div className="flex h-full w-full flex-col items-center justify-center gap-1"> | ||
<div className="flex items-center gap-1 font-bold"> | ||
<label className={`text-2xl ${displayValue ? 'text-black' : 'text-gray-2'}`}>{displaySymbol}</label> | ||
|
||
{/* Input */} | ||
<input | ||
className={`h-12 w-[4ch] max-w-80 bg-transparent text-6xl font-black outline-none transition-colors placeholder:text-h1 focus:border-primary-1 dark:border-white dark:bg-n-1 dark:text-white dark:placeholder:text-white/75 dark:focus:border-primary-1`} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really think, in general, we have wayyy too little reuse and too much component specific code. This applies to both styling (as you can see with 100000 million tailwind classses in FE code) and with logic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is literally the TokenAmountInput which is reused in a lot of place and is a building block of the application. But in general, I agree |
||
placeholder={'0.00'} | ||
onChange={(e) => { | ||
const value = formatAmountWithoutComma(e.target.value) | ||
onChange(value, isInputUsd) | ||
}} | ||
ref={inputRef} | ||
inputMode="decimal" | ||
type={inputType} | ||
value={displayValue} | ||
step="any" | ||
min="0" | ||
autoComplete="off" | ||
onKeyDown={(e) => { | ||
if (e.key === 'Enter') { | ||
e.preventDefault() | ||
if (onSubmit) onSubmit() | ||
} | ||
}} | ||
onBlur={() => { | ||
if (onBlur) onBlur() | ||
}} | ||
disabled={disabled} | ||
/> | ||
</div> | ||
)} | ||
{/* Show conversion line and toggle */} | ||
{!hideCurrencyToggle && (displayMode === 'TOKEN' || displayMode === 'FIAT') && ( | ||
|
||
{/* Conversion */} | ||
{showConversion && ( | ||
<label className="text-lg font-bold"> | ||
≈ {alternativeDisplayValue} {alternativeDisplaySymbol} | ||
</label> | ||
)} | ||
|
||
{/* Balance */} | ||
{walletBalance && !hideBalance && ( | ||
<div className="text-center text-lg text-grey-1"> | ||
Balance: {displayMode === 'FIAT' && currency ? 'USD ' : '$ '} | ||
{walletBalance} | ||
</div> | ||
)} | ||
</div> | ||
|
||
{/* Conversion toggle */} | ||
{showConversion && ( | ||
<div | ||
className={`flex w-full cursor-pointer flex-row items-center justify-center gap-1`} | ||
className="absolute right-0 top-1/2 -translate-x-1/2 -translate-y-1/2 transform cursor-pointer" | ||
onClick={(e) => { | ||
e.preventDefault() | ||
const currentValue = displayValue | ||
|
@@ -246,10 +264,7 @@ const TokenAmountInput = ({ | |
setIsInputUsd(!isInputUsd) | ||
}} | ||
> | ||
<label className="text-base text-grey-1"> | ||
{alternativeDisplaySymbol} {alternativeDisplayValue} | ||
</label> | ||
<Icon name={'switch'} className="rotate-90 cursor-pointer fill-grey-1" /> | ||
<Icon name={'switch'} className="ml-5 rotate-90 cursor-pointer" width={32} height={32} /> | ||
</div> | ||
)} | ||
</form> | ||
|
Uh oh!
There was an error while loading. Please reload this page.