Skip to content

Commit

Permalink
Added Pix Keys validation (#7)
Browse files Browse the repository at this point in the history
* index.tsx:
-Added import for validate functions;
-Set `chave aleatória` max length to 36 (Same as UUId v4);
-Added a validation function to help avoid transferring to incorrect key.

utils.ts:
-Added function to validate CPF, CNPJ, Email and `Chave Aleatória`.

* Update pages/index.tsx

* Update lib/utils.ts

---------

Co-authored-by: diegor <[email protected]>
Co-authored-by: Rafael Lins <[email protected]>
Co-authored-by: Rafael Lins <[email protected]>
  • Loading branch information
4 people authored Jul 6, 2023
1 parent 5d4d3ce commit 1fde596
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 4 deletions.
47 changes: 47 additions & 0 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,50 @@ export const formatCurrency = (number: number) => {

return brlCurrencyFormatter.format(numberResult)
}

export const isValidCPF = (cpfStr: string) => {
if (!cpfStr || typeof cpfStr !== 'string') return false

cpfStr = cpfStr.replace(/[^\d]+/g, '')
if (cpfStr.length !== 11 || !!cpfStr.match(/(\d)\1{10}/)) return false

const cpfNumArr = cpfStr.split('').map(el => +el)
const remainder = (count) => (
cpfNumArr.slice(0, count-12).reduce(
(sum, el, index) => (sum + el * (count-index)), 0 ) * 10) % 11 % 10

return remainder(10) === cpfNumArr[9] && remainder(11) === cpfNumArr[10]
}

export const isValidCNPJ = (cnpjStr: string) => {
if (!cnpjStr || typeof cnpjStr !== 'string') return false

cnpjStr = cnpjStr.replace(/[^\d]+/g, '')
if (cnpjStr.length !== 14 || !!cnpjStr.match(/(\d)\1{13}/)) return false

const cnpjNumArr = cnpjStr.split('').map(el => +el)

const remainder = (count) => {
return cnpjNumArr.slice(0, count).reduce(
(sum, el, index) => {
return sum + el * (count - index - (count - index - 7 > 1 ? 7 : -1))
}, 0) * 10 % 11 % 10
}
return (remainder(12) === cnpjNumArr[12]) && remainder(13) === cnpjNumArr[13];
}

export const isValidEmail = (emailStr: string) => {
return String(emailStr)
.toLowerCase()
.match(
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
);
}

export const isValidChaveAleatoria = (chaveAleatoriaStr: string) => {
return String(chaveAleatoriaStr)
.toLowerCase()
.match(
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
);
}
30 changes: 26 additions & 4 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {io} from "@/lib/qrcode-kotlin"
import {PatternFormat} from "react-number-format";
import {CurrencyInput} from "@/components/ui/currency-input";
import QRCode = io.github.g0dkar.qrcode.QRCode;
import {isValidCPF, isValidCNPJ, isValidEmail, isValidChaveAleatoria} from "@/lib/utils";

const CampoPix = ({show, campo, className = ""}) => {
const campoValue = campo?.valueStr || campo?.value
Expand Down Expand Up @@ -126,7 +127,7 @@ const Index = () => {
} else if (tipo === "4") {
return 10
} else if (tipo === "5") {
return 70
return 36
}

return 0
Expand Down Expand Up @@ -193,6 +194,19 @@ const Index = () => {
})
}

const isValidChave = () => {
if (tipo === "0" && chave().length === chaveMaxSize() && !isValidCPF(chave())) {
return false
} else if (tipo === "1" && chave().length === chaveMaxSize() && !isValidCNPJ(chave())) {
return false
} else if (tipo === "2" && chave().length > 3 && !isValidEmail(chave())) {
return false
} else if (tipo === "5" && chave().length === chaveMaxSize() && !isValidChaveAleatoria(chave())) {
return false
}
return true
}

return <Layout>
<Head>
<title>QRCode do Pix</title>
Expand Down Expand Up @@ -283,14 +297,22 @@ const Index = () => {
{tipo === "5" ?
<Input type="text" id="chave" value={chaveAleatorio}
onChange={(evt) => setChaveAleatorio(evt.target.value)}
placeholder="Chave Pix - Chave Aleatória" tabIndex={2} maxLength={70}
placeholder="Chave Pix - Chave Aleatória" tabIndex={2} maxLength={36}
disabled={gerandoQrCode}/>
: <></>}
</div>
</div>
<p className="text-sm text-slate-500">
<span
className="pr-3 font-medium leading-none text-slate-700 dark:text-slate-300">Tamanho: {chave().length - (tipo === "3" || tipo === "4" ? 3 : 0)}/{chaveMaxSize()}</span>
className="pr-3 font-medium leading-none text-slate-700 dark:text-slate-300">
Tamanho: {chave().length - (tipo === "3" || tipo === "4" ? 3 : 0)}/{chaveMaxSize()}
</span>
{!isValidChave() ?
<span className="text-red-700 font-semibold mr-1">
A chave digitada é inválida.
</span>
:
<></> }
Chave Pix que irá receber a transferência.</p>
</div>

Expand Down Expand Up @@ -362,7 +384,7 @@ const Index = () => {

<div className="mt-6 grid w-full items-center justify-items-center gap-3 md:flex">
<Button type="submit"
disabled={gerandoQrCode || chave() === "" || nome === "" || cidade === ""} size="lg"
disabled={gerandoQrCode || chave() === "" || nome === "" || cidade === "" || !isValidChave()} size="lg"
className="text-md w-full bg-emerald-500 px-8 hover:bg-emerald-600 dark:bg-emerald-500 dark:hover:bg-emerald-600 md:w-fit"
onClick={gerarQRCode}>
<QrCode className="mr-2 inline-block w-4"/>
Expand Down

1 comment on commit 1fde596

@vercel
Copy link

@vercel vercel bot commented on 1fde596 Jul 6, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.