├── src
├── react-app-env.d.ts
├── assets
│ └── img
│ │ ├── bb-logo.jpg
│ │ ├── itau-logo.webp
│ │ ├── bradesco-logo.png
│ │ ├── apiplaybook-logo.png
│ │ ├── next-logo.svg
│ │ ├── rate.svg
│ │ ├── illustrations
│ │ ├── account.svg
│ │ ├── credit-card.svg
│ │ └── loan.svg
│ │ └── banco-pan-logo.svg
├── utils
│ ├── fixTaxes.ts
│ ├── omit.ts
│ ├── omitBanks.ts
│ ├── fixMoney.ts
│ ├── toCamelCase.ts
│ ├── getBanksOfApi.ts
│ ├── brandMap.tsx
│ ├── brandMapTest.tsx
│ ├── returnBankLogo.ts
│ ├── fixPayload.ts
│ └── generateGridTemplate.ts
├── setupTests.ts
├── styles
│ ├── App.ts
│ ├── CallApiPage.styled.ts
│ └── global.ts
├── components
│ ├── Layout
│ │ └── Layout.tsx
│ ├── Header
│ │ ├── Header.tsx
│ │ └── Header.styled.ts
│ ├── Modal
│ │ ├── index.tsx
│ │ └── modal.style.ts
│ └── ComparisonMatrix
│ │ ├── components
│ │ ├── BrandMiniPayload
│ │ │ ├── BrandMiniPayload.styled.ts
│ │ │ └── index.tsx
│ │ ├── MatrixCell
│ │ │ └── MatrixCell.styled.ts
│ │ └── MatrixHeader
│ │ │ └── index.tsx
│ │ ├── ComparisonMatrix.styled.ts
│ │ └── index.tsx
├── index.tsx
├── reportWebVitals.ts
├── routes.ts
├── services
│ ├── callApisOpenBanking.ts
│ └── api.ts
├── hooks
│ └── Modal.tsx
├── App.tsx
├── pages
│ ├── Home
│ │ ├── index.tsx
│ │ ├── HomeData.ts
│ │ └── Home.styled.ts
│ ├── PersonalFinancings
│ │ └── index.tsx
│ ├── BusinessFinancing
│ │ └── index.tsx
│ ├── PersonalAccounts
│ │ └── index.tsx
│ ├── PersonalLoans
│ │ └── index.tsx
│ ├── BusinessLoans
│ │ └── index.tsx
│ ├── BusinessAccounts
│ │ └── index.tsx
│ ├── PersonalCreditCards
│ │ └── index.tsx
│ └── BusinessCreditCards
│ │ └── index.tsx
├── constants
│ ├── banks.ts
│ └── apis.ts
└── logo.svg
├── favicon.ico
├── logo192.png
├── logo512.png
├── robots.txt
├── public
├── robots.txt
├── favicon.ico
├── logo192.png
├── logo512.png
├── manifest.json
└── index.html
├── static
├── media
│ ├── itau-logo.96cc5dd0.webp
│ ├── bradesco-logo.d69a0ae7.png
│ ├── next-logo.d5228214.svg
│ ├── account.228c857b.svg
│ ├── banco-pan-logo.c0fd5379.svg
│ ├── credit-card.11093fcb.svg
│ └── loan.c6bc1e1a.svg
└── js
│ ├── 2.8b206ba6.chunk.js.LICENSE.txt
│ ├── runtime-main.07745ca7.js
│ ├── 3.f4a706e7.chunk.js
│ ├── 3.f4a706e7.chunk.js.map
│ └── runtime-main.07745ca7.js.map
├── .gitignore
├── manifest.json
├── tsconfig.json
├── LICENCE
├── package.json
├── asset-manifest.json
├── README.md
└── index.html
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/favicon.ico
--------------------------------------------------------------------------------
/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/logo192.png
--------------------------------------------------------------------------------
/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/logo512.png
--------------------------------------------------------------------------------
/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/src/assets/img/bb-logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/src/assets/img/bb-logo.jpg
--------------------------------------------------------------------------------
/src/assets/img/itau-logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/src/assets/img/itau-logo.webp
--------------------------------------------------------------------------------
/src/assets/img/bradesco-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/src/assets/img/bradesco-logo.png
--------------------------------------------------------------------------------
/src/assets/img/apiplaybook-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/src/assets/img/apiplaybook-logo.png
--------------------------------------------------------------------------------
/static/media/itau-logo.96cc5dd0.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/static/media/itau-logo.96cc5dd0.webp
--------------------------------------------------------------------------------
/static/media/bradesco-logo.d69a0ae7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apiplaybook/open-banking-brasil/HEAD/static/media/bradesco-logo.d69a0ae7.png
--------------------------------------------------------------------------------
/src/utils/fixTaxes.ts:
--------------------------------------------------------------------------------
1 | export const fixTaxes = (tax: string) => {
2 | return `${parseFloat(tax).toFixed(3).toString().replace(/[.\s]/g, ',')}%`
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/omit.ts:
--------------------------------------------------------------------------------
1 | // Omite uma propriedade em um objeto
2 | export const omit = (key: string, obj: any) => {
3 | const { [key]: omitted, ...rest } = obj
4 | return rest
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/omitBanks.ts:
--------------------------------------------------------------------------------
1 | import { banks } from '../constants/banks'
2 |
3 | export const omitBanks = (omitApis: string[]) => {
4 | return banks.filter((bank) => !omitApis.includes(bank.brandName))
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/fixMoney.ts:
--------------------------------------------------------------------------------
1 | export const fixMoney = (money: string) => {
2 | if (money === 'NA') {
3 | return 'N/A'
4 | }
5 | return `R$${parseFloat(money).toFixed(2).toString().replace(/[.\s]/g, ',')}`
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/toCamelCase.ts:
--------------------------------------------------------------------------------
1 | export const toCamelCase = (str: string) =>
2 | str
3 | .replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
4 | return index === 0 ? word.toLowerCase() : word.toUpperCase()
5 | })
6 | .replace(/\s+/g, '')
7 |
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/styles/App.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | const AppStyled = styled.div`
4 | display: flex;
5 | flex-direction: column;
6 | background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
7 | min-height: 100vh;
8 | `
9 |
10 | export default AppStyled
11 |
--------------------------------------------------------------------------------
/src/components/Layout/Layout.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Header from '../Header/Header'
3 |
4 | const Layout = ({ title, children }: { title?: string; children: any }) => {
5 | return (
6 | <>
7 |
8 | {children}
9 | >
10 | )
11 | }
12 |
13 | export default Layout
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | .eslintcache
26 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import reportWebVitals from './reportWebVitals'
5 | import { GlobalStyles } from './styles/global'
6 |
7 | import { ModalProvider } from './hooks/Modal'
8 |
9 | ReactDOM.render(
10 |
11 |
12 |
13 |
14 |
15 | ,
16 | document.getElementById('root')
17 | )
18 |
19 | reportWebVitals()
20 |
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/routes.ts:
--------------------------------------------------------------------------------
1 | export const HOME = '/'
2 | export const BUSINESS_LOANS = '/business-loans'
3 | export const PERSONAL_LOANS = '/personal-loans'
4 | export const PERSONAL_ACCOUNTS = '/personal-accounts'
5 | export const BUSINESS_ACCOUNTS = '/business-accounts'
6 | export const PERSONAL_FINANCINGS = '/personal-financings'
7 | export const BUSINESS_FINANCINGS = '/business-financings'
8 | export const PERSONAL_CREDIT_CARDS = '/personal-credit-cards'
9 | export const BUSINESS_CREDIT_CARDS = '/business-credit-cards'
10 |
--------------------------------------------------------------------------------
/src/components/Header/Header.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router-dom'
3 | import { HOME } from '../../routes'
4 | import { HeaderStyled } from './Header.styled'
5 |
6 | import logo from '../../assets/img/apiplaybook-logo.png'
7 |
8 | const Header = ({ title }: { title?: string }) => {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 | {title && {title} }
16 |
17 | )
18 | }
19 |
20 | export default Header
21 |
--------------------------------------------------------------------------------
/src/components/Header/Header.styled.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const HeaderStyled = styled.header`
4 | display: flex;
5 | width: 100%;
6 | padding: 10px 35px;
7 |
8 | a {
9 | height: fit-content;
10 | width: fit-content;
11 | transform: scale(0.8);
12 | }
13 |
14 | h1 {
15 | font-family: 'Inter', sans-serif;
16 | margin: auto;
17 | transform: translateX(-70px);
18 | }
19 | @media only screen and (max-width: 1400px) {
20 | padding: 5px 15px;
21 | height: 100px;
22 | a {
23 | transform: scale(0.6);
24 | }
25 | }
26 | `
27 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/src/utils/getBanksOfApi.ts:
--------------------------------------------------------------------------------
1 | import { apis } from './../constants/apis'
2 | import { banks } from './../constants/banks'
3 |
4 | export const getBanksOfApi = (apiEndpoint: string) => {
5 | const apiBanks = apis.filter((api) => api.endpoint === apiEndpoint)[0].banks
6 | const apiBanksCompanies = apiBanks.flatMap((bank) => bank.companies)
7 | const apiBanksName = apiBanks.flatMap((bank) => bank.brand)
8 |
9 | return banks
10 | .filter(({ brandName }) => apiBanksName.includes(brandName))
11 | .map((bank) => {
12 | return {
13 | ...bank,
14 | companies: bank.companies.filter((company) => apiBanksCompanies.includes(company)),
15 | }
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/brandMap.tsx:
--------------------------------------------------------------------------------
1 | //@ts-nocheck
2 | import { fixTaxes } from './fixTaxes'
3 | import { omit } from './omit'
4 |
5 | export const brandMap = (interestRates: any, brand: string) => {
6 | return (
7 | interestRates.brand === brand &&
8 | Object.values(omit('brand', interestRates)).map((interestRates) => (
9 |
10 |
11 | {interestRates.referentialRateIndexer.replace(/[_\s]/g, ' ')}
12 |
13 |
{fixTaxes(interestRates.minimumRate)}%
14 |
{fixTaxes(interestRates.maximumRate)}%
15 |
16 | ))
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/src/utils/brandMapTest.tsx:
--------------------------------------------------------------------------------
1 | interface IPayload {
2 | name: string
3 | minimum: string
4 | maximum: string
5 | brand: string
6 | }
7 |
8 | export const brandMap = (payload: IPayload, requiredBrand: string, fixFunction?: any) => {
9 | return (
10 | payload.brand === requiredBrand && (
11 |
12 |
13 | {payload.name.replace(/[_\s]/g, ' ')}
14 |
15 |
16 |
17 | {fixFunction ? fixFunction(payload.minimum) : payload.minimum}
18 |
19 |
20 | {fixFunction ? fixFunction(payload.maximum) : payload.maximum}
21 |
22 |
23 | )
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/returnBankLogo.ts:
--------------------------------------------------------------------------------
1 | import bbLogo from '../assets/img/bb-logo.jpg'
2 | import bancoPanLogo from '../assets/img/banco-pan-logo.svg'
3 | import bradescoLogo from '../assets/img/bradesco-logo.png'
4 | import itauLogo from '../assets/img/itau-logo.webp'
5 | import nextLogo from '../assets/img/next-logo.svg'
6 |
7 | export const returnBankLogo = (brandName: string) => {
8 | switch (brandName) {
9 | case 'Banco do Brasil S/A':
10 | return bbLogo
11 |
12 | case 'Grupo Pan':
13 | return bancoPanLogo
14 |
15 | case 'Banco Bradesco':
16 | return bradescoLogo
17 |
18 | case 'Banco Digital Next':
19 | return nextLogo
20 |
21 | case 'Itaú':
22 | case 'ITAU':
23 | case 'Itau Unibanco S.A.':
24 | return itauLogo
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/services/callApisOpenBanking.ts:
--------------------------------------------------------------------------------
1 | import { getBanksOfApi } from './../utils/getBanksOfApi'
2 | import { callOpenBanking } from './api'
3 |
4 | export const callApisOpenBanking = async (endpoint: string, omit?: string[]) => {
5 | // Realiza as consultas às APIs
6 | try {
7 | const banks = getBanksOfApi(endpoint)
8 | const urls = omit
9 | ? banks.map((bank) => !omit.includes(bank.brandName) && bank.apiUrl)
10 | : banks.map((bank) => bank.apiUrl)
11 |
12 | const apiResponses = await Promise.all(
13 | urls.filter(Boolean).map(async (url) => {
14 | // @ts-ignore
15 | const response = await callOpenBanking(url, endpoint)
16 | return response
17 | })
18 | )
19 | return apiResponses
20 | } catch (error) {
21 | console.log('Error to call api:', error)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/services/api.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import { toCamelCase } from '../utils/toCamelCase'
3 | import { banks } from './../constants/banks'
4 |
5 | export const callOpenBanking = async (baseURL: string, endpoint: string) => {
6 | const api = axios.create({
7 | baseURL: `${baseURL}/open-banking/products-services/v1`,
8 | })
9 |
10 | const currentBank = banks.filter((bank) => bank.apiUrl === baseURL)[0]
11 |
12 | const payloadName = toCamelCase(
13 | endpoint.substr(1, endpoint.length - 1).replace(/[-\s]/g, ' ')
14 | )
15 |
16 | return await api
17 | .get(endpoint)
18 | .then((response) => response.data.data.brand)
19 | .catch(() => {
20 | return {
21 | name: currentBank.brandName,
22 | companies: [
23 | {
24 | name: 'INDISPONÍVEL',
25 | cnpjNumber: '00000000000000',
26 | urlComplementaryList: null,
27 | [payloadName]: [],
28 | },
29 | ],
30 | }
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/Modal/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useModal } from '../../hooks/Modal'
3 |
4 | import { LightBox, ModalWrapper, CloseButtonModal } from './modal.style'
5 |
6 | export const Modal: React.FC = () => {
7 | const { moreInfo, removeMoreInfo } = useModal()
8 | return (
9 | <>
10 | {moreInfo && (
11 |
12 |
13 |
14 |
15 |
{moreInfo.name.replace(/[_\s]/g, ' ')}
16 |
{moreInfo.chargingTriggerInfo}
17 |
18 |
19 |
Termos e Condições
20 |
{moreInfo.termsConditions?.additionalInfo}
21 |
{moreInfo.termsConditions?.elegibilityCriteriaInfo}
22 |
Informações de Processo de Cancelamento
23 |
{moreInfo.termsConditions?.closingProcessInfo}
24 |
25 |
26 |
27 | )}
28 | >
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/ComparisonMatrix/components/BrandMiniPayload/BrandMiniPayload.styled.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const BrandMiniPayloadStyled = styled.div`
4 | display: grid;
5 | text-align: center;
6 | height: 100%;
7 | max-height: 200px;
8 | div {
9 | display: flex;
10 | justify-content: space-around;
11 | align-items: center;
12 | padding: 5px 0;
13 | }
14 | .index {
15 | grid-area: index;
16 | background-color: #e5ebf3;
17 | border-bottom: 1px solid #c6c6c650;
18 | font-weight: 600;
19 | font-size: 10pt;
20 | word-break: break-all;
21 | }
22 | .max {
23 | border-left: 1px solid #c6c6c650;
24 | border-bottom: 1px solid #c6c6c650;
25 | grid-area: max;
26 | height: 100%;
27 | }
28 | .min {
29 | border-bottom: 1px solid #c6c6c650;
30 | grid-area: min;
31 | height: 100%;
32 | }
33 | .miniFont {
34 | font-size: 9pt;
35 | min-height: 30px;
36 | padding: 2px;
37 |
38 | &.title {
39 | font-size: 8pt;
40 | }
41 | }
42 | grid-template-areas:
43 | 'index index'
44 | 'min max';
45 | `
46 |
--------------------------------------------------------------------------------
/src/styles/CallApiPage.styled.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const MatrixPageStyled = styled.div`
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: center;
8 | height: 100%;
9 | width: 100%;
10 | h3 {
11 | max-width: 500px;
12 | font-weight: 600;
13 | text-align: center;
14 | margin-bottom: 30px;
15 | font-family: 'Inter', sans-serif;
16 | }
17 | `
18 |
19 | export const CompanyStyled = styled.div`
20 | display: flex;
21 | flex-direction: column;
22 | width: fit-content;
23 | div:first-child {
24 | background-color: #f0f4f7;
25 | width: 100%;
26 | margin-bottom: 20px;
27 | padding: 10px;
28 | font-size: 14pt;
29 | justify-content: space-between;
30 | }
31 | `
32 |
33 | export const TableStyled = styled.table`
34 | border-collapse: collapse;
35 | width: 900px;
36 | margin-bottom: 40px;
37 | th,
38 | td {
39 | background-color: #f0f4f7;
40 | padding: 10px 20px;
41 | border-bottom: 1px solid #aaa;
42 | font-weight: 600;
43 | }
44 | th {
45 | font-weight: 700;
46 | }
47 | `
48 |
--------------------------------------------------------------------------------
/src/utils/fixPayload.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | export const fixPayload = (payload) => {
3 | let types = []
4 | let lastBrand = false
5 | let fixedBrand = []
6 | let fixedType = []
7 | Object.keys(types).forEach((typeIndex) => {
8 | types[typeIndex].forEach((brand, brandIndex) => {
9 | if (lastBrand === false) {
10 | lastBrand = brand
11 | if (types[typeIndex].length === brandIndex + 1) {
12 | types[typeIndex] = [brand]
13 | lastBrand = false
14 | }
15 | } else {
16 | if (brand.brand === lastBrand.brand && brand.company === lastBrand.company) {
17 | fixedBrand.push(omit('company', omit('brand', lastBrand))[0])
18 | lastBrand = brand
19 | } else {
20 | if (fixedBrand.length > 0) {
21 | fixedBrand = {
22 | ...fixedBrand,
23 | brand: lastBrand.brand,
24 | company: lastBrand.company,
25 | }
26 |
27 | fixedType.push(fixedBrand)
28 | }
29 | fixedType.push(brand)
30 | }
31 | }
32 | if (types[typeIndex].length === brandIndex + 1) {
33 | types[typeIndex] = fixedType
34 | fixedType = []
35 | lastBrand = false
36 | }
37 | })
38 | })
39 | return types
40 | }
41 |
--------------------------------------------------------------------------------
/src/hooks/Modal.tsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState, useContext } from 'react'
2 | import { Modal } from '../components/Modal'
3 |
4 | interface IModalContextData {
5 | addMoreInfo(data: IModalProps): void
6 | removeMoreInfo(): void
7 | moreInfo: IModalProps | null
8 | }
9 |
10 | export interface IModalProps {
11 | name: string
12 | chargingTriggerInfo: string
13 | termsConditions: {
14 | additionalInfo?: string
15 | elegibilityCriteriaInfo?: string
16 | closingProcessInfo?: string
17 | }
18 | }
19 |
20 | const ModalContext = createContext({} as IModalContextData)
21 |
22 | export const ModalProvider: React.FC = ({ children }) => {
23 | const [moreInfo, setMoreInfo] = useState(null)
24 |
25 | const addMoreInfo = (data: IModalProps) => {
26 | setMoreInfo(data)
27 | }
28 |
29 | const removeMoreInfo = () => {
30 | setMoreInfo(null)
31 | }
32 |
33 | return (
34 |
35 |
36 | {children}
37 |
38 | )
39 | }
40 |
41 | export function useModal() {
42 | const context = useContext(ModalContext)
43 |
44 | return context
45 | }
46 |
--------------------------------------------------------------------------------
/src/components/ComparisonMatrix/components/BrandMiniPayload/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { BrandMiniPayloadStyled } from './BrandMiniPayload.styled'
3 |
4 | interface IPayload {
5 | name: string
6 | minimum: string
7 | maximum: string
8 | brand: string
9 | }
10 |
11 | interface Props {
12 | props: {
13 | payload: IPayload
14 | requiredBrand: string
15 | fixFunction?: any
16 | }
17 | }
18 |
19 | const BrandMiniPayload = ({ props }: Props) => {
20 | const { payload, requiredBrand, fixFunction } = props
21 | return (
22 | payload.brand === requiredBrand && (
23 |
24 | 30 && 'miniFont'}`}>
25 | {payload.name.replace(/[_\s]/g, ' ')}
26 |
27 | 5 && 'miniFont'}`}>
28 | {fixFunction ? fixFunction(payload.minimum) : payload.minimum}
29 |
30 | 5 && 'miniFont'}`}>
31 | {fixFunction ? fixFunction(payload.maximum) : payload.maximum}
32 |
33 |
34 | )
35 | )
36 | }
37 |
38 | export default BrandMiniPayload
39 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2021 API Connect (CHEZI PRESTACAO DE SERVICOS DE MARKETING E EVENTOS EIRELI)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/utils/generateGridTemplate.ts:
--------------------------------------------------------------------------------
1 | import { IBankProps } from './../constants/banks'
2 |
3 | export const generateGridTemplate = (banks: IBankProps[]) => {
4 | let template = '200px'
5 | banks.forEach((bank) => {
6 | template += ` ${bank.companies.length === 0 ? 130 : 130 * bank.companies.length}px`
7 | })
8 |
9 | return template
10 | }
11 | export const generateGridTemplateByLength = (length: number) => {
12 | let template = ''
13 |
14 | for (let i = 0; i < length; i++) {
15 | template += i === 0 ? '130px' : ' 130px'
16 | }
17 |
18 | return template
19 | }
20 |
21 | export const generateCellGridConfig = (companiesLength: number) => {
22 | let areas = ''
23 | let templateAreas = ''
24 | for (let i = 0; i < companiesLength; i++) {
25 | areas += ` div.cellCompanyColumn${i} { grid-area: cellCompanyColumn${i}; }`
26 | templateAreas += ` cellCompanyColumn${i}`
27 | }
28 | areas = areas.trim()
29 | templateAreas = templateAreas.trim()
30 |
31 | return `max-width: ${
32 | companiesLength === 0 ? 130 : 130 * companiesLength
33 | }px; ${areas} grid-template-columns: ${generateGridTemplateByLength(
34 | companiesLength === 0 ? 1 : companiesLength
35 | )}; grid-template-areas: '${templateAreas}' !important;`
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/Modal/modal.style.ts:
--------------------------------------------------------------------------------
1 | import styled, { keyframes } from 'styled-components'
2 | import { MdClose } from 'react-icons/md'
3 |
4 | const appearFromMiddle = keyframes`
5 | from {
6 | opacity: 0;
7 | transform:translateY(-100%)
8 | } to {
9 | opacity: 1;
10 | transform: translateY(0%)
11 | }
12 | `
13 |
14 | export const LightBox = styled.div`
15 | display: block;
16 | position: fixed;
17 | width: 100%;
18 | height: 100vh;
19 | background-color: rgba(0, 0, 0, 0.3);
20 | z-index: 1;
21 | overflow-x: auto;
22 | padding: 60px 20px;
23 | `
24 |
25 | export const ModalWrapper = styled.div`
26 | position: relative;
27 | background-color: #ffff;
28 | color: #888888;
29 | width: 600px;
30 | margin: 0 auto;
31 | padding-top: 60px;
32 | padding: 50px;
33 | box-shadow: 0 5px 16px rgba(0, 0, 0, 0.4);
34 | overflow-y: auto;
35 | animation: ${appearFromMiddle} 0.2s;
36 |
37 | div {
38 | h1 {
39 | font-size: 21px;
40 | margin-top: 20px;
41 | margin-bottom: 10px;
42 | color: #666666;
43 | }
44 | }
45 | `
46 |
47 | export const CloseButtonModal = styled(MdClose)`
48 | position: absolute;
49 | top: 20px;
50 | right: 20px;
51 | font-weight: 800;
52 |
53 | &:hover {
54 | color: #111111;
55 | cursor: pointer;
56 | }
57 | `
58 |
--------------------------------------------------------------------------------
/src/components/ComparisonMatrix/components/MatrixCell/MatrixCell.styled.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | interface MatrixCellProps {
4 | gridConfig: string
5 | }
6 |
7 | export const MatrixCellStyled = styled.div`
8 | display: grid !important;
9 | padding: 0 !important;
10 | ${({ gridConfig }) => gridConfig}
11 | max-height: fit-content;
12 | div.cellCompanyColumn {
13 | width: 100%;
14 | display: flex;
15 | flex-direction: column;
16 | border-right: 1px solid #c6c6c650;
17 | border-left: 1px solid #c6c6c650;
18 | }
19 | div.minMax {
20 | display: grid;
21 | text-align: center;
22 | height: 100%;
23 | width: 100%;
24 | div {
25 | display: flex;
26 | justify-content: space-around;
27 | align-items: center;
28 | }
29 |
30 | .max {
31 | border-left: 1px solid #c6c6c650;
32 | grid-area: max;
33 | height: 100%;
34 | }
35 | .min {
36 | grid-area: min;
37 | height: 100%;
38 | }
39 | .miniHeader {
40 | border-bottom: 1px solid #c6c6c650;
41 | grid-area: miniHeader;
42 | height: 100%;
43 | font-size: 10pt;
44 | }
45 | grid-template-rows: 60px 40px;
46 | grid-template-areas:
47 | 'miniHeader miniHeader'
48 | 'min max';
49 | }
50 |
51 | /* ${({ gridConfig }) => gridConfig} */
52 | `
53 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "homepage": "http://apiplaybook.github.io/open-banking-brasil",
3 | "name": "open-banking-brasil",
4 | "version": "0.1.0",
5 | "private": true,
6 | "dependencies": {
7 | "@testing-library/jest-dom": "^5.11.4",
8 | "@testing-library/react": "^11.1.0",
9 | "@testing-library/user-event": "^12.1.10",
10 | "@types/jest": "^26.0.15",
11 | "@types/node": "^12.0.0",
12 | "@types/react": "^16.9.53",
13 | "@types/react-dom": "^16.9.8",
14 | "@types/react-router-dom": "^5.1.7",
15 | "axios": "^0.21.1",
16 | "react": "^17.0.1",
17 | "react-dom": "^17.0.1",
18 | "react-github-btn": "^1.2.0",
19 | "react-icons": "^4.2.0",
20 | "react-router-dom": "^5.2.0",
21 | "react-scripts": "4.0.1",
22 | "react-spinners-css": "^1.2.2",
23 | "styled-components": "^5.2.1",
24 | "typescript": "^4.0.3",
25 | "web-vitals": "^0.2.4"
26 | },
27 | "scripts": {
28 | "predeploy": "yarn build",
29 | "deploy": "gh-pages -d build",
30 | "start": "react-scripts start",
31 | "build": "react-scripts build",
32 | "test": "react-scripts test",
33 | "eject": "react-scripts eject"
34 | },
35 | "eslintConfig": {
36 | "extends": [
37 | "react-app",
38 | "react-app/jest"
39 | ]
40 | },
41 | "browserslist": {
42 | "production": [
43 | ">0.2%",
44 | "not dead",
45 | "not op_mini all"
46 | ],
47 | "development": [
48 | "last 1 chrome version",
49 | "last 1 firefox version",
50 | "last 1 safari version"
51 | ]
52 | },
53 | "devDependencies": {
54 | "@types/react-icons": "^3.0.0",
55 | "@types/styled-components": "^5.1.7",
56 | "gh-pages": "^3.1.0"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/static/js/2.8b206ba6.chunk.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*
2 | object-assign
3 | (c) Sindre Sorhus
4 | @license MIT
5 | */
6 |
7 | /*!
8 | Copyright (c) 2017 Jed Watson.
9 | Licensed under the MIT License (MIT), see
10 | http://jedwatson.github.io/classnames
11 | */
12 |
13 | /*!
14 | * github-buttons v2.14.2
15 | * (c) 2021 なつき
16 | * @license BSD-2-Clause
17 | */
18 |
19 | /** @license React v0.20.1
20 | * scheduler.production.min.js
21 | *
22 | * Copyright (c) Facebook, Inc. and its affiliates.
23 | *
24 | * This source code is licensed under the MIT license found in the
25 | * LICENSE file in the root directory of this source tree.
26 | */
27 |
28 | /** @license React v16.13.1
29 | * react-is.production.min.js
30 | *
31 | * Copyright (c) Facebook, Inc. and its affiliates.
32 | *
33 | * This source code is licensed under the MIT license found in the
34 | * LICENSE file in the root directory of this source tree.
35 | */
36 |
37 | /** @license React v17.0.1
38 | * react-dom.production.min.js
39 | *
40 | * Copyright (c) Facebook, Inc. and its affiliates.
41 | *
42 | * This source code is licensed under the MIT license found in the
43 | * LICENSE file in the root directory of this source tree.
44 | */
45 |
46 | /** @license React v17.0.1
47 | * react-jsx-runtime.production.min.js
48 | *
49 | * Copyright (c) Facebook, Inc. and its affiliates.
50 | *
51 | * This source code is licensed under the MIT license found in the
52 | * LICENSE file in the root directory of this source tree.
53 | */
54 |
55 | /** @license React v17.0.1
56 | * react.production.min.js
57 | *
58 | * Copyright (c) Facebook, Inc. and its affiliates.
59 | *
60 | * This source code is licensed under the MIT license found in the
61 | * LICENSE file in the root directory of this source tree.
62 | */
63 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { HashRouter as Router, Switch, Route } from 'react-router-dom'
3 |
4 | import HomePage from './pages/Home'
5 | import BusinessLoansPage from './pages/BusinessLoans'
6 | import PersonalLoansPage from './pages/PersonalLoans'
7 | import PersonalAccountsPage from './pages/PersonalAccounts'
8 | import BusinessAccountsPage from './pages/BusinessAccounts'
9 | import PersonalFinancingsPage from './pages/PersonalFinancings'
10 | import BusinessFinancingsPage from './pages/BusinessFinancing'
11 | import PersonalCreditCardsPage from './pages/PersonalCreditCards'
12 | import BusinessCreditCardsPage from './pages/BusinessCreditCards'
13 |
14 | import {
15 | HOME,
16 | PERSONAL_LOANS,
17 | BUSINESS_LOANS,
18 | PERSONAL_ACCOUNTS,
19 | BUSINESS_ACCOUNTS,
20 | PERSONAL_FINANCINGS,
21 | BUSINESS_FINANCINGS,
22 | BUSINESS_CREDIT_CARDS,
23 | PERSONAL_CREDIT_CARDS,
24 | } from './routes'
25 | import AppStyled from './styles/App'
26 |
27 | function App() {
28 | return (
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | )
45 | }
46 |
47 | export default App
48 |
--------------------------------------------------------------------------------
/src/components/ComparisonMatrix/ComparisonMatrix.styled.ts:
--------------------------------------------------------------------------------
1 | //@ts-nocheck
2 | import styled from 'styled-components'
3 |
4 | interface ComparisonMatrixProps {
5 | gridTemplateColumns: string
6 | }
7 |
8 | export const ComparisonMatrixStyled = styled.div`
9 | width: fit-content;
10 | display: grid;
11 | grid-template-columns: ${({ gridTemplateColumns }) => gridTemplateColumns};
12 | grid-template-rows: auto;
13 | .mainIndex {
14 | background-color: #3e446c;
15 | color: #f0f4f7;
16 | }
17 | & > div {
18 | display: flex;
19 | background-color: #f0f4f7;
20 | padding: 50px;
21 | justify-content: space-around;
22 | border: 1px solid #c6c6c650;
23 | }
24 | .header {
25 | grid-area: header;
26 | }
27 | div.mini {
28 | display: flex;
29 | flex-direction: row;
30 | justify-content: flex-start;
31 | padding: 0;
32 | max-height: fit-content;
33 | div.miniHeaders {
34 | display: flex;
35 | flex-direction: row;
36 | width: 100%;
37 | }
38 | div.miniCompanyColumn {
39 | width: 100%;
40 | display: flex;
41 | flex-direction: column;
42 | &:last-child {
43 | border-left: 1px solid #c6c6c650;
44 | }
45 | }
46 | div.minMax {
47 | display: grid;
48 | text-align: center;
49 | height: 100%;
50 | width: 100%;
51 | div {
52 | display: flex;
53 | justify-content: space-around;
54 | align-items: center;
55 | }
56 |
57 | .max {
58 | border-left: 1px solid #c6c6c650;
59 | grid-area: max;
60 | height: 100%;
61 | }
62 | .min {
63 | grid-area: min;
64 | height: 100%;
65 | }
66 | .miniHeader {
67 | border-bottom: 1px solid #c6c6c650;
68 | grid-area: miniHeader;
69 | height: 100%;
70 | font-size: 10pt;
71 | }
72 | grid-template-rows: 60px 40px;
73 | grid-template-areas:
74 | 'miniHeader miniHeader'
75 | 'min max';
76 | }
77 | }
78 | `
79 |
--------------------------------------------------------------------------------
/src/styles/global.ts:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from 'styled-components'
2 |
3 | export const GlobalStyles = createGlobalStyle`
4 | html {
5 | box-sizing: border-box;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | scroll-behavior: smooth;
9 | }
10 |
11 | *,
12 | *::before,
13 | *::after {
14 | box-sizing: inherit;
15 | }
16 | * {
17 | margin: 0;
18 | padding: 0;
19 | }
20 | a {
21 | text-decoration: none;
22 | color: #000;
23 | }
24 |
25 | button.blue, a.blue {
26 | color: #2e93db;
27 | background: none;
28 | font-weight: bold;
29 |
30 | &:hover {
31 | cursor: pointer;
32 | opacity: 0.5;
33 | }
34 | }
35 |
36 | strong,
37 | b {
38 | font-weight: 700;
39 | }
40 |
41 | body {
42 | color: rgba(0, 0, 0, 0.87);
43 | font-size: 0.875rem;
44 | font-family: 'Open Sans', 'Helvetica', 'Arial', sans-serif;
45 | font-weight: 400;
46 | line-height: 1.43;
47 | letter-spacing: 0.01071em;
48 | background-color: #f5f5f5;
49 | overflow-x: hidden;
50 | &.dark {
51 | background-color: #1b1b1b;
52 | color: #fff;
53 | input:-webkit-autofill,
54 | input:-webkit-autofill:hover,
55 | input:-webkit-autofill:focus,
56 | input:-webkit-autofill:active {
57 | -webkit-box-shadow: 0 0 0 30px rgba(255, 255, 255, 0.1) inset !important;
58 | box-shadow: 0 0 0 30px rgba(255, 255, 255, 0.1) inset !important;
59 | }
60 | input:-internal-autofill-selected {
61 | background-color: transparent !important;
62 | }
63 | }
64 | }
65 |
66 | input, button {
67 | outline: 0;
68 | border: 0 none;
69 | }
70 | @media print {
71 | body {
72 | background-color: #fff;
73 | &.dark {
74 | background-color: #1b1b1b;
75 | }
76 | }
77 | }
78 | `
79 |
--------------------------------------------------------------------------------
/src/components/ComparisonMatrix/components/MatrixHeader/index.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import React from 'react'
3 | import { IBankProps } from '../../../../constants/banks'
4 | import { returnBankLogo } from '../../../../utils/returnBankLogo'
5 |
6 | interface Props {
7 | banks: IBankProps[]
8 | }
9 |
10 | const MatrixHeader = ({ banks }: Props) => {
11 | return (
12 | <>
13 |
14 | {banks.map((bank) => (
15 |
16 |
21 |
22 | ))}
23 |
24 | {banks.map((bank, index) => (
25 |
26 |
31 | {bank.companies.length === 0 ? (
32 |
33 |
34 | INDISPONÍVEL
35 |
36 |
37 | ) : (
38 | bank.companies.map((company, i) => (
39 |
0 ? { borderLeft: '2px solid #c6c6c650' } : {}}
43 | >
44 |
45 | {company}
46 |
47 |
48 | MÍN.
49 |
50 |
51 | MÁX.
52 |
53 |
54 | ))
55 | )}
56 |
57 |
58 | ))}
59 | >
60 | )
61 | }
62 |
63 | export default MatrixHeader
64 |
--------------------------------------------------------------------------------
/src/pages/Home/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router-dom'
3 | import Layout from '../../components/Layout/Layout'
4 |
5 | import {
6 | HomeStyled,
7 | LeftSideStyled,
8 | CardStyled,
9 | HomeButtonStyled,
10 | ApiCardStyled,
11 | HomeButtonRedirect,
12 | HomeMainContent,
13 | ButtonContainer,
14 | GitHubButtonContainer,
15 | } from './Home.styled'
16 | import home from '../../assets/img/home.svg'
17 | import GitHubButton from 'react-github-btn'
18 |
19 | import { HomeData } from './HomeData'
20 |
21 | const HomePage = () => {
22 | return (
23 |
24 |
25 |
26 |
34 | Star
35 |
36 |
37 |
38 |
39 | Seja bem-vindo ao Open Banking Brasil!
40 |
41 | Por meio de um sistema financeiro aberto, regulamentado pelo Banco Central do
42 | Brasil, os dados do cliente podem ser compartilhados de forma segura, mediante
43 | autorização.
44 |
45 |
46 |
47 |
48 | Veja todos os comparativos
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | {HomeData.map((item) => (
57 |
58 |
59 |
60 | {item.title}
61 |
62 | {item.description}
63 |
64 |
65 |
66 | ))}
67 |
68 |
69 |
70 | )
71 | }
72 |
73 | export default HomePage
74 |
--------------------------------------------------------------------------------
/src/constants/banks.ts:
--------------------------------------------------------------------------------
1 | export interface IBankProps {
2 | brandName: string
3 | apiUrl: string
4 | style: any
5 | logoWidth: string
6 | companies: string[]
7 | }
8 | export const banks: IBankProps[] = [
9 | {
10 | brandName: 'Banco do Brasil S/A',
11 | companies: ['Banco do Brasil S/A'],
12 | apiUrl: 'https://bb-api.concore.io',
13 | style: {
14 | backgroundColor: '#FBAB7E',
15 | backgroundImage: 'linear-gradient(62deg, #FBAB7E 0%, #F7CE68 100%)',
16 | },
17 | logoWidth: '40px',
18 | },
19 | {
20 | brandName: 'Grupo Pan',
21 | companies: ['Banco Pan'],
22 | apiUrl: 'https://bancopan-api.concore.io',
23 | style: {
24 | backgroundImage:
25 | 'radial-gradient( circle 732px at -23.9% -25.1%, #0043ff 6.1%, #00C5FF 100.2% )',
26 | },
27 | logoWidth: '40px',
28 | },
29 | {
30 | brandName: 'Banco Bradesco',
31 | companies: ['Banco Bradesco S.A.'],
32 | apiUrl: 'https://api.bradesco.com/bradesco',
33 | style: { background: 'linear-gradient(180deg, #cc092f 0%, #b2207b 100%)' },
34 | logoWidth: '50px',
35 | },
36 | {
37 | brandName: 'Itaú',
38 | companies: ['BANCO ITAU CONSIGNADO S.A.', 'BANCO ITAU UNIBANCO S.A.'],
39 | apiUrl: 'https://itau-api.concore.io',
40 | style: {
41 | background: 'linear-gradient( 0deg, #ff9d00 11.2%, rgba(255,0,0,1) 100.2% )',
42 | },
43 | logoWidth: '50px',
44 | },
45 | {
46 | brandName: 'Itau Unibanco S.A.',
47 | companies: ['Itau Unibanco S.A.', 'Banco Itaucard S.A.'],
48 | apiUrl: 'https://itau-api.concore.io',
49 | style: {
50 | background: 'linear-gradient( 0deg, #ff9d00 11.2%, rgba(255,0,0,1) 100.2% )',
51 | },
52 | logoWidth: '50px',
53 | },
54 | {
55 | brandName: 'ITAU',
56 | companies: [
57 | 'INVESTCRED',
58 | 'LUIZACRED CFI',
59 | 'FIC FINANCEIRA',
60 | 'HIPERCARD BM',
61 | 'BANCO ITAUCARD',
62 | ],
63 | apiUrl: 'https://itau-api.concore.io',
64 | style: {
65 | background: 'linear-gradient( 0deg, #ff9d00 11.2%, rgba(255,0,0,1) 100.2% )',
66 | },
67 | logoWidth: '50px',
68 | },
69 | {
70 | brandName: 'Banco Digital Next',
71 | companies: ['Banco Bradesco S.A.'],
72 | apiUrl: 'https://api.bradesco.com/next',
73 | style: {
74 | background: 'linear-gradient( 110deg, #1D3B3B 11.2%, #3cc974 100.2% )',
75 | },
76 | logoWidth: '35px',
77 | },
78 | ]
79 |
--------------------------------------------------------------------------------
/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "main.js": "/open-banking-brasil/static/js/main.2f04f596.chunk.js",
4 | "main.js.map": "/open-banking-brasil/static/js/main.2f04f596.chunk.js.map",
5 | "runtime-main.js": "/open-banking-brasil/static/js/runtime-main.07745ca7.js",
6 | "runtime-main.js.map": "/open-banking-brasil/static/js/runtime-main.07745ca7.js.map",
7 | "static/css/2.adb2dfaf.chunk.css": "/open-banking-brasil/static/css/2.adb2dfaf.chunk.css",
8 | "static/js/2.8b206ba6.chunk.js": "/open-banking-brasil/static/js/2.8b206ba6.chunk.js",
9 | "static/js/2.8b206ba6.chunk.js.map": "/open-banking-brasil/static/js/2.8b206ba6.chunk.js.map",
10 | "static/js/3.f4a706e7.chunk.js": "/open-banking-brasil/static/js/3.f4a706e7.chunk.js",
11 | "static/js/3.f4a706e7.chunk.js.map": "/open-banking-brasil/static/js/3.f4a706e7.chunk.js.map",
12 | "index.html": "/open-banking-brasil/index.html",
13 | "static/css/2.adb2dfaf.chunk.css.map": "/open-banking-brasil/static/css/2.adb2dfaf.chunk.css.map",
14 | "static/js/2.8b206ba6.chunk.js.LICENSE.txt": "/open-banking-brasil/static/js/2.8b206ba6.chunk.js.LICENSE.txt",
15 | "static/media/account.228c857b.svg": "/open-banking-brasil/static/media/account.228c857b.svg",
16 | "static/media/banco-pan-logo.c0fd5379.svg": "/open-banking-brasil/static/media/banco-pan-logo.c0fd5379.svg",
17 | "static/media/bradesco-logo.d69a0ae7.png": "/open-banking-brasil/static/media/bradesco-logo.d69a0ae7.png",
18 | "static/media/credit-card.11093fcb.svg": "/open-banking-brasil/static/media/credit-card.11093fcb.svg",
19 | "static/media/financings.868a4c70.svg": "/open-banking-brasil/static/media/financings.868a4c70.svg",
20 | "static/media/home.5c01ce36.svg": "/open-banking-brasil/static/media/home.5c01ce36.svg",
21 | "static/media/itau-logo.96cc5dd0.webp": "/open-banking-brasil/static/media/itau-logo.96cc5dd0.webp",
22 | "static/media/loan.c6bc1e1a.svg": "/open-banking-brasil/static/media/loan.c6bc1e1a.svg",
23 | "static/media/next-logo.d5228214.svg": "/open-banking-brasil/static/media/next-logo.d5228214.svg"
24 | },
25 | "entrypoints": [
26 | "static/js/runtime-main.07745ca7.js",
27 | "static/css/2.adb2dfaf.chunk.css",
28 | "static/js/2.8b206ba6.chunk.js",
29 | "static/js/main.2f04f596.chunk.js"
30 | ]
31 | }
--------------------------------------------------------------------------------
/src/pages/Home/HomeData.ts:
--------------------------------------------------------------------------------
1 | import loan from '../../assets/img/illustrations/loan.svg'
2 | import account from '../../assets/img/illustrations/account.svg'
3 | import creditcard from '../../assets/img/illustrations/credit-card.svg'
4 | import financings from '../../assets/img/illustrations/financings.svg'
5 |
6 | import {
7 | PERSONAL_LOANS,
8 | PERSONAL_ACCOUNTS,
9 | PERSONAL_CREDIT_CARDS,
10 | PERSONAL_FINANCINGS,
11 | BUSINESS_LOANS,
12 | BUSINESS_ACCOUNTS,
13 | BUSINESS_CREDIT_CARDS,
14 | BUSINESS_FINANCINGS,
15 | } from '../../routes'
16 |
17 | export const HomeData = [
18 | {
19 | path: PERSONAL_LOANS,
20 | title: 'Juros - Empréstimos PF',
21 | img: {
22 | src: loan,
23 | alt: 'Api de Empréstimos pessoa física',
24 | },
25 | description: 'Api de Empréstimos PJ',
26 | },
27 | {
28 | path: BUSINESS_LOANS,
29 | title: 'Juros - Empréstimos PJ',
30 | img: {
31 | src: loan,
32 | alt: 'Api de Empréstimos pessoa jurídica',
33 | },
34 | description: 'Api de Empréstimos PJ',
35 | },
36 | {
37 | path: PERSONAL_ACCOUNTS,
38 | title: 'Tarifas - Conta PF',
39 | img: {
40 | src: account,
41 | alt: 'Tarifas Conta Pessoal',
42 | },
43 | description: 'Api de Conta pessoa física',
44 | },
45 | {
46 | path: BUSINESS_ACCOUNTS,
47 | title: 'Tarifas - Conta PJ',
48 | img: {
49 | src: account,
50 | alt: 'Tarifas - Conta Jurídica',
51 | },
52 | description: 'Api de Conta pessoa jurídica',
53 | },
54 | {
55 | path: PERSONAL_CREDIT_CARDS,
56 | title: 'Tarifas - Cartão PF',
57 | img: {
58 | src: creditcard,
59 | alt: 'Tarifas - Cartão PF',
60 | },
61 | description: 'Api de Cartão de Crédito PF',
62 | },
63 | {
64 | path: BUSINESS_CREDIT_CARDS,
65 | title: 'Tarifas - Cartão PJ',
66 | img: {
67 | src: creditcard,
68 | alt: 'Tarifas - Cartão PJ',
69 | },
70 | description: 'Api de Cartão de Crédito PJ',
71 | },
72 | {
73 | path: PERSONAL_FINANCINGS,
74 | title: 'Tarifas - Financiamento PF',
75 | img: {
76 | src: financings,
77 | alt: 'Tarifas - Financiamento PF',
78 | },
79 | description: 'Api de Financiamento PF',
80 | },
81 | {
82 | path: BUSINESS_FINANCINGS,
83 | title: 'Tarifas - Financiamento PJ',
84 | img: {
85 | src: financings,
86 | alt: 'Tarifas - Financiamento PJ',
87 | },
88 | description: 'Api de Financiamento PJ',
89 | },
90 | ]
91 |
--------------------------------------------------------------------------------
/static/js/runtime-main.07745ca7.js:
--------------------------------------------------------------------------------
1 | !function(e){function r(r){for(var n,i,u=r[0],c=r[1],l=r[2],s=0,p=[];s
--------------------------------------------------------------------------------
/src/assets/img/next-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/static/media/next-logo.d5228214.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Feito com ♥ pelo time de Developer Experience da API Playbook! [Fale conosco](https://www.apiplaybook.com/) ;D.
2 |
3 | Licença MIT.
4 |
5 | # Open Banking Brasil
6 |
7 | No dia 1º de fevereiro de 2021, foi implementado o Open Banking no Brasil. Ele promete revolucionar o mercado financeiro, pois com ele será possível o compartilhamento de informações bancárias entre diferentes instituições.
8 |
9 | A primeira fase do Open Banking Brasil disponibiliza informações sobre as instituições financeiras, como taxas e tarifas cobradas por serviços prestados pelos bancos. Neste primeiro momento, isso permite que o cliente possa comparar as instituições e que escolha a melhor opção para o seu caso, incentivando a competição por serviços e crédito mais barato e de melhor qualidade.
10 |
11 | Essas informações públicas são disponibilizadas através de _RESTful APIs_. Para mais informações sobre as APIs, consulte esta [documentação](https://openbanking-brasil.github.io/areadesenvolvedor/).
12 |
13 | ## Como realizar as consultas às APIs
14 |
15 | As APIs disponíveis, na primeira fase, possuem um funcionamento muito simples. Basta realizar uma requisição `GET` ao _URI_ da API desejada e será retornada a resposta em um `JSON`
16 |
17 | Os URIs das APIs de diferentes bancos seguem o mesmo princípio:
18 |
19 | https://**url-base-disponibilizado-pelo-banco**/open-banking/products-services/v1/**api**
20 |
21 | O URL base fica disponível no portal dev da instituição financeira e **normalmente** seguem o padrão:
22 |
23 | https://api.**banco**.com
24 |
25 | Algumas APIs podem sofrer com um problema de acesso bloqueado pelo `CORS` (_Cross-origin resource sharing_). Se isso ocorrer, será necessário o uso de um _proxy_ para intermediar a requisição à API que está sofrendo com este problema.
26 |
27 | Para mais informações sobre as APIs do **Open Banking Brasil**, consulte esta [documentação](https://openbanking-brasil.github.io/areadesenvolvedor/).
28 |
29 | ## `Contas pessoa física`
30 |
31 | A API de contas pessoa física leva o nome de **`personal-accounts`** e retorna as formas de movimentações e suas tarifas, termos e condições de contrato, entre outras coisas.
32 |
33 | `GET` https://**url-base-disponibilizado-pelo-banco**/open-banking/products-services/v1/**personal-accounts**
34 |
35 | ## `Empréstimo pessoa física`
36 |
37 | A API de empréstimo pessoa física leva o nome de **`personal-loans`** e retorna as taxas cobradas para os diferentes tipos de empréstimo, termos e condições de contrato e outras informações sobre empréstimo para pessoa física.
38 |
39 | `GET` https://**url-base-disponibilizado-pelo-banco**/open-banking/products-services/v1/**personal-loans**
40 |
41 | ## `Empréstimo pessoa jurídica`
42 |
43 | A API de empréstimo pessoa jurpidica leva o nome de **`business-loans`** e retorna as taxas cobradas para os diferentes tipos de empréstimo, termos e condições de contrato e outras informações sobre empréstimo para pessoa jurídica.
44 |
45 | `GET` https://**url-base-disponibilizado-pelo-banco**/open-banking/products-services/v1/**business-loans**
46 |
--------------------------------------------------------------------------------
/src/constants/apis.ts:
--------------------------------------------------------------------------------
1 | interface IBank {
2 | brand: string
3 | companies: string[]
4 | }
5 | export interface IApis {
6 | endpoint: string
7 | banks: IBank[]
8 | }
9 |
10 | export const apis: IApis[] = [
11 | {
12 | endpoint: '/personal-accounts',
13 | banks: [
14 | { brand: 'Banco do Brasil S/A', companies: ['Banco do Brasil S/A'] },
15 | { brand: 'Grupo Pan', companies: ['Banco Pan'] },
16 | { brand: 'Banco Bradesco', companies: ['Banco Bradesco S.A.'] },
17 | {
18 | brand: 'Itau Unibanco S.A.',
19 | companies: ['Itau Unibanco S.A.'],
20 | },
21 | { brand: 'Banco Digital Next', companies: ['Banco Bradesco S.A.'] },
22 | ],
23 | },
24 | {
25 | endpoint: '/business-accounts',
26 | banks: [
27 | { brand: 'Banco do Brasil S/A', companies: ['Banco do Brasil S/A'] },
28 | { brand: 'Banco Bradesco', companies: ['Banco Bradesco S.A.'] },
29 | {
30 | brand: 'Itau Unibanco S.A.',
31 | companies: ['Itau Unibanco S.A.'],
32 | },
33 | ],
34 | },
35 | {
36 | endpoint: '/personal-loans',
37 | banks: [
38 | { brand: 'Banco do Brasil S/A', companies: ['Banco do Brasil S/A'] },
39 | { brand: 'Grupo Pan', companies: ['Banco Pan'] },
40 | { brand: 'Banco Bradesco', companies: ['Banco Bradesco S.A.'] },
41 | {
42 | brand: 'Itaú',
43 | companies: ['BANCO ITAU CONSIGNADO S.A.', 'BANCO ITAU UNIBANCO S.A.'],
44 | },
45 | { brand: 'Banco Digital Next', companies: ['Banco Bradesco S.A.'] },
46 | ],
47 | },
48 | {
49 | endpoint: '/business-loans',
50 | banks: [
51 | { brand: 'Banco do Brasil S/A', companies: ['Banco do Brasil S/A'] },
52 | { brand: 'Banco Bradesco', companies: ['Banco Bradesco S.A.'] },
53 | {
54 | brand: 'Itaú',
55 | companies: ['BANCO ITAU UNIBANCO S.A.'],
56 | },
57 | ],
58 | },
59 | {
60 | endpoint: '/personal-financings',
61 | banks: [
62 | { brand: 'Banco do Brasil S/A', companies: ['Banco do Brasil S/A'] },
63 | { brand: 'Banco Bradesco', companies: ['Banco Bradesco S.A.'] },
64 | {
65 | brand: 'Itaú',
66 | companies: ['BANCO ITAU UNIBANCO S.A.'],
67 | },
68 | ],
69 | },
70 | {
71 | endpoint: '/business-financings',
72 | banks: [
73 | { brand: 'Banco do Brasil S/A', companies: ['Banco do Brasil S/A'] },
74 | { brand: 'Banco Bradesco', companies: ['Banco Bradesco S.A.'] },
75 | {
76 | brand: 'Itaú',
77 | companies: ['BANCO ITAU UNIBANCO S.A.', 'BANCO ITAUCARD'],
78 | },
79 | ],
80 | },
81 |
82 | {
83 | endpoint: '/personal-credit-cards',
84 | banks: [
85 | { brand: 'Banco do Brasil S/A', companies: ['Banco do Brasil S/A'] },
86 | { brand: 'Banco Bradesco', companies: ['Banco Bradesco S.A.'] },
87 | {
88 | brand: 'ITAU',
89 | companies: [
90 | 'INVESTCRED',
91 | 'LUIZACRED CFI',
92 | 'FIC FINANCEIRA',
93 | 'HIPERCARD BM',
94 | 'BANCO ITAUCARD',
95 | ],
96 | },
97 | ],
98 | },
99 |
100 | {
101 | endpoint: '/business-credit-cards',
102 | banks: [
103 | { brand: 'Banco do Brasil S/A', companies: ['Banco do Brasil S/A'] },
104 | { brand: 'Banco Bradesco', companies: ['Banco Bradesco S.A.'] },
105 | {
106 | brand: 'ITAU',
107 | companies: ['BANCO ITAUCARD'],
108 | },
109 | ],
110 | },
111 | ]
112 |
--------------------------------------------------------------------------------
/static/js/3.f4a706e7.chunk.js:
--------------------------------------------------------------------------------
1 | (this["webpackJsonpopen-banking-brasil"]=this["webpackJsonpopen-banking-brasil"]||[]).push([[3],{113:function(t,n,e){"use strict";e.r(n),e.d(n,"getCLS",(function(){return v})),e.d(n,"getFCP",(function(){return g})),e.d(n,"getFID",(function(){return h})),e.d(n,"getLCP",(function(){return y})),e.d(n,"getTTFB",(function(){return F}));var i,a,r=function(){return"".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)},o=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1;return{name:t,value:n,delta:0,entries:[],id:r(),isFinal:!1}},u=function(t,n){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){var e=new PerformanceObserver((function(t){return t.getEntries().map(n)}));return e.observe({type:t,buffered:!0}),e}}catch(t){}},s=!1,c=!1,p=function(t){s=!t.persisted},d=function(){addEventListener("pagehide",p),addEventListener("beforeunload",(function(){}))},f=function(t){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];c||(d(),c=!0),addEventListener("visibilitychange",(function(n){var e=n.timeStamp;"hidden"===document.visibilityState&&t({timeStamp:e,isUnloading:s})}),{capture:!0,once:n})},l=function(t,n,e,i){var a;return function(){e&&n.isFinal&&e.disconnect(),n.value>=0&&(i||n.isFinal||"hidden"===document.visibilityState)&&(n.delta=n.value-(a||0),(n.delta||n.isFinal||void 0===a)&&(t(n),a=n.value))}},v=function(t){var n,e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=o("CLS",0),a=function(t){t.hadRecentInput||(i.value+=t.value,i.entries.push(t),n())},r=u("layout-shift",a);r&&(n=l(t,i,r,e),f((function(t){var e=t.isUnloading;r.takeRecords().map(a),e&&(i.isFinal=!0),n()})))},m=function(){return void 0===i&&(i="hidden"===document.visibilityState?0:1/0,f((function(t){var n=t.timeStamp;return i=n}),!0)),{get timeStamp(){return i}}},g=function(t){var n,e=o("FCP"),i=m(),a=u("paint",(function(t){"first-contentful-paint"===t.name&&t.startTime1&&void 0!==arguments[1]&&arguments[1],i=o("LCP"),a=m(),r=function(t){var e=t.startTime;e {
24 | let pageCompanies: any = ['INDISPONÍVEL']
25 | stateCompanies.forEach((array: string[][]) =>
26 | array.forEach((companyName) => pageCompanies.push(companyName))
27 | )
28 | let fixedBanks = banks
29 | banks.forEach((banks: any, index: number) => {
30 | if (fixedBanks[index].companies.length === 0) {
31 | fixedBanks[index].companies = ['INDISPONÍVEL']
32 | } else {
33 | fixedBanks[index].companies = fixedBanks[
34 | index
35 | ].companies.filter((companyName: string) => pageCompanies.includes(companyName))
36 | }
37 | })
38 | return (
39 |
40 |
41 | {Object.keys(typesState).map((index) => (
42 |
43 |
44 | {index.replace(/[_\s]/g, ' ')}
45 |
46 | {banks
47 | .map((bank) => bank.brandName)
48 | .map((requiredBrand) => (
49 | brandName === requiredBrand)[0].companies
52 | .length
53 | )}
54 | key={`matrixCell${requiredBrand}_${index}${Math.random()}`}
55 | id="matrixCell"
56 | >
57 | {typesState[index].map((brand) => {
58 | return banks
59 | .filter(({ brandName }) => brandName === requiredBrand)[0]
60 | .companies.map((companyName, cIndex) => {
61 | return (
62 | omit('brand', brand).company === companyName &&
63 | brand.brand === requiredBrand && (
64 |
69 | {Object.values(omit('company', omit('brand', brand))).map(
70 | ({ name, minimum, maximum }) => {
71 | return (
72 |
88 | )
89 | }
90 | )}
91 |
92 | )
93 | )
94 | })
95 | })}
96 |
97 | ))}
98 |
99 | ))}
100 |
101 | )
102 | }
103 |
104 | export default ComparisonMatrix
105 |
--------------------------------------------------------------------------------
/src/pages/Home/Home.styled.ts:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | export const HomeStyled = styled.div`
4 | display: flex;
5 | flex-direction: column;
6 | max-width: 1120px;
7 | margin: 0 auto;
8 | `
9 | export const LeftSideStyled = styled.div`
10 | img {
11 | width: 600px;
12 | }
13 | display: grid;
14 | grid-template-columns: 0.9fr 1.1fr;
15 | & > img {
16 | max-width: 50vw;
17 | }
18 | @media only screen and (max-width: 1600px) {
19 | grid-template-columns: 1.2fr 0.8fr;
20 | & > img {
21 | max-width: 43vw;
22 | }
23 | h1 {
24 | font-size: 30pt !important;
25 | }
26 | p {
27 | font-size: 12pt !important;
28 | }
29 | & > div {
30 | padding: 0 0 0 50px;
31 | }
32 | }
33 | @media only screen and (max-width: 1100px) {
34 | grid-template-columns: 1.5fr 0.5fr;
35 | & > img {
36 | max-width: 40vw;
37 | }
38 | h1 {
39 | font-size: 26pt !important;
40 | }
41 |
42 | & > div {
43 | padding: 0 40px;
44 | }
45 | }
46 | @media only screen and (max-width: 800px) {
47 | display: flex;
48 | flex-direction: column;
49 | & > img {
50 | align-self: center;
51 | max-width: 80vw;
52 | }
53 | }
54 | `
55 | export const CardStyled = styled.div`
56 | margin-top: 20px;
57 |
58 | h1 {
59 | font-family: 'Inter', sans-serif;
60 | margin-top: 35px;
61 | margin-bottom: 15px;
62 | font-size: 40px;
63 | }
64 |
65 | p {
66 | margin-top: 30px;
67 | text-align: justify;
68 | font-size: 16px;
69 | font-weight: 500;
70 | }
71 | `
72 | export const HomeButtonStyled = styled.div`
73 | display: flex;
74 | justify-content: center;
75 | align-items: center;
76 | `
77 | export const ApiCardStyled = styled.div`
78 | width: 400px;
79 | position: relative;
80 | top: -35px;
81 | display: flex;
82 | flex-direction: column;
83 | align-content: center;
84 | justify-content: center;
85 | height: fit-content;
86 | width: fit-content;
87 | max-width: 600px;
88 | background: #f0f4f7;
89 | padding: 30px;
90 | border-radius: 5px;
91 | box-shadow: 0px 0px 24px rgb(0 0 0 / 14%);
92 | margin-bottom: 50px;
93 | cursor: pointer;
94 | transition: all 0.2s ease-in-out;
95 | &:hover {
96 | transform: scale(1.1);
97 | background: linear-gradient(180deg, #46236f 0%, #7b2987 100%);
98 | color: #fff;
99 | z-index: 1;
100 | }
101 | h3 {
102 | margin-bottom: 15px;
103 | text-align: center;
104 | }
105 | h3::before {
106 | content: '';
107 | width: 50px;
108 | height: 4px;
109 | display: block;
110 | background: #3e446c;
111 | position: absolute;
112 | left: 50%;
113 | bottom: 0;
114 | -ms-transform: translateX(-50%);
115 | transform: translateX(-50%);
116 | }
117 | img {
118 | height: 150px;
119 | margin: auto;
120 | margin-bottom: 15px;
121 | }
122 | p {
123 | text-align: center;
124 | font-size: 11pt;
125 | }
126 | `
127 |
128 | export const HomeButtonRedirect = styled.button`
129 | background-color: #6c63ff;
130 | height: 40px;
131 | font-weight: bold;
132 | padding: 0 30px;
133 | color: #ffff;
134 | cursor: pointer;
135 | transition: all 0.2s ease-in-out;
136 | &:hover {
137 | opacity: 0.5;
138 | }
139 | `
140 |
141 | export const HomeMainContent = styled.div`
142 | padding-top: 150px;
143 | max-width: 1120px;
144 | width: 100%;
145 | display: flex;
146 | align-items: center;
147 | justify-content: space-evenly;
148 | flex-wrap: wrap;
149 | margin-top: 150px;
150 | margin-bottom: 80px;
151 | margin: 0 auto;
152 | `
153 |
154 | export const ButtonContainer = styled.div`
155 | margin-top: 25px;
156 | width: 100%;
157 | display: flex;
158 | align-items: center;
159 |
160 | a {
161 | flex: 1;
162 | }
163 | `
164 |
165 | export const GitHubButtonContainer = styled.div`
166 | width: 100%;
167 | display: flex;
168 | flex-direction: row-reverse;
169 | padding-right: 59px;
170 | @media only screen and (max-width: 1600px) {
171 | padding-right: 40px;
172 | }
173 | @media only screen and (max-width: 1100px) {
174 | padding-right: 30px;
175 | }
176 | @media only screen and (max-width: 1100px) {
177 | padding-right: 25px;
178 | }
179 | `
180 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
11 |
12 |
16 |
17 |
18 |
19 |
28 | API Playbook - Comparador de Taxas
29 |
32 |
33 |
36 |
39 |
40 |
73 |
74 |
75 |
76 | You need to enable JavaScript to run this app.
77 |
78 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 | API Playbook - Comparador de Taxas You need to enable JavaScript to run this app.
--------------------------------------------------------------------------------
/src/assets/img/rate.svg:
--------------------------------------------------------------------------------
1 | #119_analyzing process_twocolour
--------------------------------------------------------------------------------
/static/media/account.228c857b.svg:
--------------------------------------------------------------------------------
1 | #95_profile analysis_twocolour
--------------------------------------------------------------------------------
/src/assets/img/illustrations/account.svg:
--------------------------------------------------------------------------------
1 | #95_profile analysis_twocolour
--------------------------------------------------------------------------------
/src/assets/img/banco-pan-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Banco PAN - 616161 e azul
5 | Created with Sketch.
6 |
22 |
--------------------------------------------------------------------------------
/static/media/banco-pan-logo.c0fd5379.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Banco PAN - 616161 e azul
5 | Created with Sketch.
6 |
22 |
--------------------------------------------------------------------------------
/src/pages/PersonalFinancings/index.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 |
3 | import React, { useState, useEffect, useMemo } from 'react'
4 | import { Ellipsis } from 'react-spinners-css'
5 |
6 | import { callApisOpenBanking } from '../../services/callApisOpenBanking'
7 | import { getBanksOfApi } from '../../utils/getBanksOfApi'
8 | import { fixMoney } from '../../utils/fixMoney'
9 |
10 | import ComparisonMatrix from '../../components/ComparisonMatrix'
11 | import Layout from '../../components/Layout/Layout'
12 | import {
13 | CompanyStyled,
14 | MatrixPageStyled,
15 | TableStyled,
16 | } from '../../styles/CallApiPage.styled'
17 |
18 | const PersonalFinancingsPage = () => {
19 | const [state, setState] = useState([])
20 |
21 | const endpoint = '/personal-financings'
22 | const banks = getBanksOfApi(endpoint)
23 |
24 | // Realiza as consultas às APIs
25 | useEffect(() => {
26 | ;(async () => {
27 | const apiResponses = await callApisOpenBanking('/personal-financings')
28 |
29 | setState(apiResponses)
30 | })()
31 | }, [])
32 |
33 | // Organiza as informações para serem lidas pela matriz
34 | const typesState = useMemo(() => {
35 | let types = []
36 | state.forEach((brand) =>
37 | brand.companies.forEach((company) => {
38 | company.personalFinancings.forEach((financing) => {
39 | const services = financing.fees.services.map(({ name, minimum, maximum }) => {
40 | return {
41 | name: name,
42 | minimum: minimum.value,
43 | maximum: maximum.value,
44 | }
45 | })
46 |
47 | if (types[financing.type]) {
48 | types[financing.type] = [
49 | ...types[financing.type],
50 | {
51 | ...services,
52 | brand: brand.name,
53 | company: company.name,
54 | },
55 | ]
56 | } else {
57 | types[financing.type] = [
58 | {
59 | ...services,
60 | brand: brand.name,
61 | company: company.name,
62 | },
63 | ]
64 | }
65 | })
66 | })
67 | )
68 |
69 | return types
70 | }, [state])
71 |
72 | return (
73 |
74 |
75 |
76 | Estas são todas as tarifas dos serviços de financiamento para pessoa física dos
77 | bancos:
78 | {banks.map((bank, index) =>
79 | index === 0 ? `${bank.brandName}` : `, ${bank.brandName}`
80 | )}
81 | .
82 |
83 | {state.length > 0 && (
84 | bank.brandName)
88 | .map(
89 | (requiredBrand) => state.filter((brand) => brand.name === requiredBrand)[0]
90 | )
91 | .map(({ companies }) =>
92 | companies.map(({ name }) => {
93 | return name
94 | })
95 | )
96 | .map((array) => Object.values(array))}
97 | typesState={typesState}
98 | fixFunction={fixMoney}
99 | />
100 | )}
101 | {Object.keys(typesState).length === 0 && }
102 |
103 | Tabelas completas com as tarifas dos serviços de financiamento para pessoa física:
104 |
105 | {state &&
106 | state.map((brand, index) =>
107 | brand.companies.map((company) => (
108 |
109 |
121 |
122 |
123 |
124 | Tipo de financiamento
125 | Serviço
126 | Tarifa Mín.
127 | Tarifa Máx.
128 | Termos
129 |
130 |
131 |
132 | {company.personalFinancings &&
133 | company.personalFinancings.map(({ type, fees, termsConditions }) =>
134 | fees.services.map(({ name, minimum, maximum }, index) => (
135 |
136 | {type.replace(/[_\s]/g, ' ')}
137 | {name.replace(/[_\s]/g, ' ')}
138 | {fixMoney(minimum.value)}
139 | {fixMoney(maximum.value)}
140 |
141 | {!termsConditions ? (
142 | NA
143 | ) : (
144 |
150 | Termos
151 |
152 | )}
153 |
154 |
155 | ))
156 | )}
157 |
158 |
159 |
160 | ))
161 | )}
162 |
163 |
164 | )
165 | }
166 |
167 | export default PersonalFinancingsPage
168 |
--------------------------------------------------------------------------------
/src/pages/BusinessFinancing/index.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 |
3 | import React, { useState, useEffect, useMemo } from 'react'
4 | import { Ellipsis } from 'react-spinners-css'
5 |
6 | import { callApisOpenBanking } from '../../services/callApisOpenBanking'
7 | import { getBanksOfApi } from '../../utils/getBanksOfApi'
8 | import { fixMoney } from '../../utils/fixMoney'
9 |
10 | import ComparisonMatrix from '../../components/ComparisonMatrix'
11 | import Layout from '../../components/Layout/Layout'
12 | import {
13 | CompanyStyled,
14 | MatrixPageStyled,
15 | TableStyled,
16 | } from '../../styles/CallApiPage.styled'
17 | const BusinessFinancingsPage = () => {
18 | const [state, setState] = useState([])
19 |
20 | const endpoint = '/business-financings'
21 | const banks = getBanksOfApi(endpoint)
22 |
23 | // Realiza as consultas às APIs
24 | useEffect(() => {
25 | ;(async () => {
26 | const apiResponses = await callApisOpenBanking('/business-financings')
27 |
28 | setState(apiResponses)
29 | })()
30 | }, [])
31 |
32 | // Organiza as informações para serem lidas pela matriz
33 | const typesState = useMemo(() => {
34 | let types = []
35 | state.forEach((brand) =>
36 | brand.companies.forEach((company) => {
37 | company.businessFinancings.forEach((financing) => {
38 | const rates = financing.interestRates.map((rate) => {
39 | return {
40 | name: rate.referentialRateIndexer,
41 | minimum: rate.minimumRate,
42 | maximum: rate.maximumRate,
43 | }
44 | })
45 | if (types[financing.type]) {
46 | types[financing.type] = [
47 | ...types[financing.type],
48 | {
49 | ...rates,
50 | brand: brand.name,
51 | company: company.name,
52 | },
53 | ]
54 | } else {
55 | types[financing.type] = [
56 | {
57 | ...rates,
58 | brand: brand.name,
59 | company: company.name,
60 | },
61 | ]
62 | }
63 | })
64 | })
65 | )
66 |
67 | return types
68 | }, [state])
69 |
70 | return (
71 |
72 |
73 |
74 | Estas são todas as tarifas dos serviços de financiamento para pessoa juridica dos
75 | bancos:
76 | {banks.map((bank, index) =>
77 | index === 0 ? `${bank.brandName}` : `, ${bank.brandName}`
78 | )}
79 | .
80 |
81 | {state.length > 0 && (
82 | bank.brandName)
86 | .map(
87 | (requiredBrand) => state.filter((brand) => brand.name === requiredBrand)[0]
88 | )
89 | .map(({ companies }) =>
90 | companies.map(({ name }) => {
91 | return name
92 | })
93 | )
94 | .map((array) => Object.values(array))}
95 | typesState={typesState}
96 | fixFunction={fixMoney}
97 | />
98 | )}
99 | {Object.keys(typesState).length === 0 && }
100 |
101 | Tabelas completas com as tarifas dos serviços de financiamento para pessoa
102 | juridica:
103 |
104 | {state &&
105 | state.map((brand, index) =>
106 | brand.companies.map((company) => (
107 |
108 |
120 |
121 |
122 |
123 | Tipo de financiamento
124 | Serviço
125 | Tarifa Mín.
126 | Tarifa Máx.
127 | Termos
128 |
129 |
130 |
131 | {company.businessFinancings &&
132 | company.businessFinancings.map(({ type, fees, termsConditions }) =>
133 | fees.services.map(
134 | ({ name, chargingTriggerInfo, minimum, maximum }, index) => (
135 |
136 | {type.replace(/[_\s]/g, ' ')}
137 | {name.replace(/[_\s]/g, ' ')}
138 | {fixMoney(minimum.value)}
139 | {fixMoney(maximum.value)}
140 |
141 |
142 | {termsConditions === 'NA' ? (
143 | NA
144 | ) : (
145 |
151 | Termos
152 |
153 | )}
154 |
155 |
156 | )
157 | )
158 | )}
159 |
160 |
161 |
162 | ))
163 | )}
164 |
165 |
166 | )
167 | }
168 |
169 | export default BusinessFinancingsPage
170 |
--------------------------------------------------------------------------------
/src/pages/PersonalAccounts/index.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-extra-semi */
2 | // @ts-nocheck
3 | import React, { useState, useEffect, useMemo } from 'react'
4 | import { Ellipsis } from 'react-spinners-css'
5 |
6 | import Layout from '../../components/Layout/Layout'
7 | import {
8 | CompanyStyled,
9 | MatrixPageStyled,
10 | TableStyled,
11 | } from '../../styles/CallApiPage.styled'
12 | import { fixMoney } from '../../utils/fixMoney'
13 | import { useModal } from '../../hooks/Modal'
14 |
15 | import { callApisOpenBanking } from '../../services/callApisOpenBanking'
16 | import ComparisonMatrix from '../../components/ComparisonMatrix'
17 |
18 | import { getBanksOfApi } from '../../utils/getBanksOfApi'
19 |
20 | const PersonalLoansPage = () => {
21 | const [state, setState] = useState([])
22 | const { addMoreInfo } = useModal()
23 |
24 | const endpoint = '/personal-accounts'
25 | const banks = getBanksOfApi(endpoint)
26 |
27 | // Realiza as consultas às APIs
28 | useEffect(() => {
29 | ;(async () => {
30 | const apiResponses = await callApisOpenBanking(endpoint)
31 | setState(apiResponses)
32 | })()
33 | }, [])
34 |
35 | // Organiza as informações para serem lidas pela matriz
36 | const typesState = useMemo(() => {
37 | let services = []
38 | let servicesList = []
39 | let companies = []
40 | state &&
41 | state.forEach((brand) => {
42 | brand.companies.forEach((company) => {
43 | company.personalAccounts.forEach((account) => {
44 | account.fees.priorityServices.forEach(({ code, minimum, maximum }) => {
45 | const fare = {
46 | code,
47 | name: account.type,
48 | minimum: minimum.value,
49 | maximum: maximum.value,
50 | }
51 |
52 | companies[company.name]
53 | ? companies[company.name].push(fare)
54 | : (companies[company.name] = [fare])
55 |
56 | !servicesList.includes(code) && servicesList.push(code)
57 | })
58 | })
59 | servicesList.forEach((serviceCode) => {
60 | const servicePayload = company.name !== 'INDISPONÍVEL' && {
61 | ...companies[company.name]
62 | .filter((fare) => fare.code === serviceCode)
63 | .map((fare) => {
64 | return {
65 | name: fare.name,
66 | minimum: fare.minimum,
67 | maximum: fare.maximum,
68 | }
69 | }),
70 | brand: brand.name,
71 | company: company.name,
72 | }
73 | services[serviceCode]
74 | ? services[serviceCode].push(servicePayload)
75 | : (services[serviceCode] = [servicePayload])
76 | })
77 | })
78 | })
79 |
80 | return services
81 | }, [state])
82 |
83 | return (
84 |
85 |
86 |
87 | Estas são todas as taxas dos produtos e serviços para contas de pessoa fisica dos
88 | bancos:
89 | {banks.map((bank, index) =>
90 | index === 0 ? `${bank.brandName}` : `, ${bank.brandName}`
91 | )}
92 | .
93 |
94 | {state.length > 0 && (
95 | bank.brandName)
99 | .map(
100 | (requiredBrand) => state.filter((brand) => brand.name === requiredBrand)[0]
101 | )
102 | .map(({ companies }) =>
103 | companies.map(({ name }) => {
104 | return name
105 | })
106 | )
107 | .map((array) => Object.values(array))}
108 | typesState={typesState}
109 | fixFunction={fixMoney}
110 | />
111 | )}
112 |
113 | {Object.keys(typesState).length === 0 && }
114 |
115 | Tabelas completas com as tarifas de contas para pessoas físicas.
116 |
117 | {state &&
118 | state.map((brand, index) =>
119 | brand.companies.map((company) => (
120 |
121 |
133 |
134 |
135 |
136 | Taxas de juros
137 | Tipo de conta
138 | Mín
139 | Máx
140 | Informações
141 |
142 |
143 |
144 | {company.personalAccounts &&
145 | company.personalAccounts.map(({ type, fees, termsConditions }) =>
146 | fees.priorityServices.map(
147 | (
148 | { name, chargingTriggerInfo, code, minimum, maximum },
149 | index
150 | ) => (
151 |
152 | {code.replace(/[_\s]/g, ' ')}
153 | {type.replace(/[_\s]/g, ' ')}
154 | {fixMoney(minimum.value)}
155 | {fixMoney(maximum.value)}
156 |
157 |
159 | addMoreInfo({
160 | name,
161 | chargingTriggerInfo,
162 | termsConditions,
163 | })
164 | }
165 | className="blue"
166 | >
167 | Mais Informações
168 |
169 |
170 |
171 | )
172 | )
173 | )}
174 |
175 |
176 |
177 | ))
178 | )}
179 |
180 |
181 | )
182 | }
183 |
184 | export default PersonalLoansPage
185 |
--------------------------------------------------------------------------------
/src/pages/PersonalLoans/index.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import React, { useState, useEffect, useMemo } from 'react'
3 | import { Ellipsis } from 'react-spinners-css'
4 |
5 | import { callApisOpenBanking } from '../../services/callApisOpenBanking'
6 | import { fixTaxes } from '../../utils/fixTaxes'
7 | import { getBanksOfApi } from '../../utils/getBanksOfApi'
8 |
9 | import Layout from '../../components/Layout/Layout'
10 | import ComparisonMatrix from '../../components/ComparisonMatrix'
11 | import {
12 | CompanyStyled,
13 | MatrixPageStyled,
14 | TableStyled,
15 | } from '../../styles/CallApiPage.styled'
16 |
17 | const PersonalLoansPage = () => {
18 | const [state, setState] = useState([])
19 |
20 | const endpoint = '/personal-loans'
21 | const banks = getBanksOfApi(endpoint)
22 |
23 | // Realiza as consultas às APIs
24 | useEffect(() => {
25 | ;(async () => {
26 | const apiResponses = await callApisOpenBanking('/personal-loans')
27 | setState(apiResponses)
28 | })()
29 | }, [])
30 |
31 | // Organiza as informações para serem lidas pela matriz
32 | const typesState = useMemo(() => {
33 | let types = []
34 | state.forEach((brand) =>
35 | brand.companies.forEach((company) => {
36 | company.personalLoans.forEach((loan) => {
37 | const rates = loan.interestRates.map(
38 | ({ referentialRateIndexer, minimumRate, maximumRate }) => {
39 | return {
40 | name: referentialRateIndexer,
41 | minimum: minimumRate,
42 | maximum: maximumRate,
43 | }
44 | }
45 | )
46 | if (types[loan.type]) {
47 | types[loan.type] = [
48 | ...types[loan.type],
49 | {
50 | ...rates,
51 | brand: brand.name,
52 | company: company.name,
53 | },
54 | ]
55 | } else {
56 | types[loan.type] = [
57 | {
58 | ...rates,
59 | brand: brand.name,
60 | company: company.name,
61 | },
62 | ]
63 | }
64 | })
65 | })
66 | )
67 | return types
68 | }, [state])
69 |
70 | return (
71 |
72 |
73 |
74 | Este é um comparativo das taxas de empréstimos para pessoas físicas dos
75 | bancos:
76 | {banks.map((bank, index) =>
77 | index === 0 ? `${bank.brandName}` : `, ${bank.brandName}`
78 | )}
79 | .
80 |
81 |
82 | {state.length > 0 && (
83 | bank.brandName)
87 | .map(
88 | (requiredBrand) => state.filter((brand) => brand.name === requiredBrand)[0]
89 | )
90 | .map(({ companies }) =>
91 | companies.map(({ name }) => {
92 | return name
93 | })
94 | )
95 | .map((array) => Object.values(array))}
96 | typesState={typesState}
97 | fixFunction={fixTaxes}
98 | />
99 | )}
100 | {Object.keys(typesState).length === 0 && }
101 |
102 | Tabelas completas com as taxas de empréstimos para pessoas físicas.
103 |
104 | {state &&
105 | state.map((brand, index) =>
106 | brand.companies.map((company) => (
107 |
108 |
119 |
120 |
121 |
122 | Tipo
123 | Taxas de juros
124 | Mín
125 | Máx
126 | Garantias Requeridas
127 | Termos
128 |
129 |
130 |
131 | {company.personalLoans &&
132 | company.personalLoans.map(
133 | ({ type, interestRates, requiredWarranties, termsConditions }) => (
134 |
135 | {type.replace(/[_\s]/g, ' ')}
136 |
137 | {interestRates.map(
138 | (
139 | { referentialRateIndexer, minimumRate, maximumRate },
140 | index
141 | ) => (
142 |
143 | {referentialRateIndexer.replace(/[_\s]/g, ' ')}
144 |
145 | )
146 | )}
147 |
148 |
149 | {interestRates.map(({ minimumRate }, index) => (
150 |
151 | {fixTaxes(minimumRate)}
152 |
153 | ))}
154 |
155 |
156 | {interestRates.map(({ maximumRate }, index) => (
157 |
158 | {fixTaxes(maximumRate)}
159 |
160 | ))}
161 |
162 | {requiredWarranties[0].replace(/[_\s]/g, ' ')}
163 |
164 | {termsConditions === 'NA' ? (
165 | NA
166 | ) : (
167 |
173 | Termos
174 |
175 | )}
176 |
177 |
178 | )
179 | )}
180 |
181 |
182 |
183 | ))
184 | )}
185 |
186 |
187 | )
188 | }
189 |
190 | export default PersonalLoansPage
191 |
--------------------------------------------------------------------------------
/src/pages/BusinessLoans/index.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-extra-semi */
2 | // @ts-nocheck
3 | import React, { useState, useEffect, useMemo } from 'react'
4 | import { Ellipsis } from 'react-spinners-css'
5 |
6 | import { fixTaxes } from '../../utils/fixTaxes'
7 | import { callApisOpenBanking } from '../../services/callApisOpenBanking'
8 | import { getBanksOfApi } from '../../utils/getBanksOfApi'
9 |
10 | import Layout from '../../components/Layout/Layout'
11 | import ComparisonMatrix from '../../components/ComparisonMatrix'
12 | import {
13 | CompanyStyled,
14 | MatrixPageStyled,
15 | TableStyled,
16 | } from '../../styles/CallApiPage.styled'
17 |
18 | const BusinessLoansPage = () => {
19 | const [state, setState] = useState([])
20 |
21 | const endpoint = '/business-loans'
22 | const banks = getBanksOfApi(endpoint)
23 |
24 | // Realiza as consultas às APIs
25 | useEffect(() => {
26 | ;(async () => {
27 | const apiResponses = await callApisOpenBanking(endpoint)
28 | setState(apiResponses)
29 | })()
30 | }, [])
31 |
32 | // Organiza as informações para serem lidas pela matriz
33 | const typesState = useMemo(() => {
34 | let types = []
35 | state &&
36 | state.forEach((brand) => {
37 | brand.companies.forEach((company) => {
38 | // No retorno do banco orignal ele retorna como personalLoans
39 | const businessLoans = company.personalLoans
40 | ? company.personalLoans
41 | : company.businessLoans
42 | businessLoans.forEach((loan) => {
43 | const rates = loan.interestRates.map(
44 | ({ referentialRateIndexer, minimumRate, maximumRate }) => {
45 | return {
46 | name: referentialRateIndexer,
47 | minimum: minimumRate,
48 | maximum: maximumRate,
49 | }
50 | }
51 | )
52 | if (types[loan.type]) {
53 | types[loan.type] = [
54 | ...types[loan.type],
55 | {
56 | ...rates,
57 | brand: brand.name,
58 | company: company.name,
59 | },
60 | ]
61 | } else {
62 | types[loan.type] = [
63 | {
64 | ...rates,
65 | brand: brand.name,
66 | company: company.name,
67 | },
68 | ]
69 | }
70 | })
71 | })
72 | })
73 |
74 | return types
75 | }, [state])
76 |
77 | return (
78 |
79 |
80 |
81 | Este é um comparativo das taxas de empréstimos para pessoas jurídicas dos
82 | bancos:
83 | {banks.map((bank, index) =>
84 | index === 0 ? `${bank.brandName}` : `, ${bank.brandName}`
85 | )}
86 |
87 |
88 | {state.length > 0 && (
89 | bank.brandName)
93 | .map(
94 | (requiredBrand) => state.filter((brand) => brand.name === requiredBrand)[0]
95 | )
96 | .map(({ companies }) =>
97 | companies.map(({ name }) => {
98 | return name
99 | })
100 | )
101 | .map((array) => Object.values(array))}
102 | typesState={typesState}
103 | fixFunction={fixTaxes}
104 | />
105 | )}
106 | {Object.keys(typesState).length === 0 && }
107 |
108 | Tabelas completas com as taxas de empréstimos para pessoas jurídica.
109 |
110 | {state &&
111 | state.map((brand, index) =>
112 | brand.companies.map((company) => (
113 |
114 |
125 |
126 |
127 |
128 | Tipo
129 | Taxas de juros
130 | Mín
131 | Máx
132 | Garantias Requeridas
133 | Termos
134 |
135 |
136 |
137 | {company.businessLoans &&
138 | company.businessLoans.map(
139 | (
140 | { type, interestRates, requiredWarranties, termsConditions },
141 | i
142 | ) => (
143 |
144 | {type.replace(/[_\s]/g, ' ')}
145 |
146 | {interestRates.map(
147 | (
148 | { referentialRateIndexer, minimumRate, maximumRate },
149 | index
150 | ) => (
151 |
152 | {referentialRateIndexer.replace(/[_\s]/g, ' ')}
153 |
154 | )
155 | )}
156 |
157 |
158 | {interestRates.map(({ minimumRate }, index) => (
159 |
160 | {fixTaxes(minimumRate)}
161 |
162 | ))}
163 |
164 |
165 | {interestRates.map(({ maximumRate }, index) => (
166 |
167 | {fixTaxes(maximumRate)}
168 |
169 | ))}
170 |
171 | {requiredWarranties[0].replace(/[_\s]/g, ' ')}
172 |
173 | {termsConditions === 'NA' ? (
174 | NA
175 | ) : (
176 |
182 | Termos
183 |
184 | )}
185 |
186 |
187 | )
188 | )}
189 |
190 |
191 |
192 | ))
193 | )}
194 |
195 |
196 | )
197 | }
198 |
199 | export default BusinessLoansPage
200 |
--------------------------------------------------------------------------------
/src/pages/BusinessAccounts/index.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-extra-semi */
2 | // @ts-nocheck
3 | import React, { useState, useEffect, useMemo } from 'react'
4 | import { Ellipsis } from 'react-spinners-css'
5 |
6 | import Layout from '../../components/Layout/Layout'
7 | import {
8 | CompanyStyled,
9 | MatrixPageStyled,
10 | TableStyled,
11 | } from '../../styles/CallApiPage.styled'
12 | import { fixMoney } from '../../utils/fixMoney'
13 |
14 | import { callApisOpenBanking } from '../../services/callApisOpenBanking'
15 | import ComparisonMatrix from '../../components/ComparisonMatrix'
16 | import { useModal } from '../../hooks/Modal'
17 |
18 | import { getBanksOfApi } from '../../utils/getBanksOfApi'
19 |
20 | interface IResponsePersonalAccounts {
21 | name: string
22 | companies: ICompanies[]
23 | }
24 |
25 | interface ICompanies {
26 | name: string
27 | cnpjNumber: string
28 | urlComplementaryList: string
29 | businessAccounts: IBusinessAccounts[]
30 | }
31 |
32 | interface IBusinessAccounts {
33 | type: string
34 | fees: {
35 | services: IService[]
36 | }
37 | serviceBundles: IServiceBundles[]
38 | openingClosingChannels: []
39 | additionalInfo: []
40 | transactionMethods: []
41 | termsConditions: {}
42 | incomeRate: {}
43 | }
44 |
45 | interface IService {
46 | name: string
47 | code: string
48 | chargingTriggerInfo: string
49 | prices: IPrice[]
50 | minimum: {
51 | value: string
52 | currency: string
53 | }
54 | maximum: {
55 | value: string
56 | currency: string
57 | }
58 | }
59 |
60 | interface IPrice {
61 | interval: string
62 | value: string
63 | currency: string
64 | customers: {
65 | rate: number
66 | }
67 | }
68 |
69 | const PersonalLoansPage = () => {
70 | const [state, setState] = useState([])
71 | const { addMoreInfo } = useModal()
72 |
73 | const endpoint = '/business-accounts'
74 | const banks = getBanksOfApi(endpoint)
75 |
76 | // Realiza as consultas às APIs
77 | useEffect(() => {
78 | ;(async () => {
79 | const apiResponses = await callApisOpenBanking(endpoint)
80 | setState(apiResponses)
81 | })()
82 | }, [])
83 |
84 | // Organiza as informações para serem lidas pela matriz
85 | const typesState = useMemo(() => {
86 | let services = []
87 | let servicesList = []
88 | let companies = []
89 | state &&
90 | state.forEach((brand) => {
91 | brand.companies.forEach((company) => {
92 | company.businessAccounts.forEach((account) => {
93 | account.fees.services.forEach(({ code, minimum, maximum }) => {
94 | const fare = {
95 | code,
96 | name: account.type,
97 | minimum: minimum.value,
98 | maximum: maximum.value,
99 | }
100 |
101 | companies[company.name]
102 | ? companies[company.name].push(fare)
103 | : (companies[company.name] = [fare])
104 |
105 | !servicesList.includes(code) && servicesList.push(code)
106 | })
107 | })
108 | servicesList.forEach((serviceCode) => {
109 | const servicePayload = company.name !== 'INDISPONÍVEL' && {
110 | ...companies[company.name]
111 | .filter((fare) => fare.code === serviceCode)
112 | .map((fare) => {
113 | return {
114 | name: fare.name,
115 | minimum: fare.minimum,
116 | maximum: fare.maximum,
117 | }
118 | }),
119 | brand: brand.name,
120 | company: company.name,
121 | }
122 | services[serviceCode]
123 | ? services[serviceCode].push(servicePayload)
124 | : (services[serviceCode] = [servicePayload])
125 | })
126 | })
127 | })
128 |
129 | return services
130 | }, [state])
131 |
132 | return (
133 |
134 |
135 |
136 | Estas são todas as tarifas dos serviços prestados para contas de pessoa jurídica
137 | dos bancos:
138 | {banks.map((bank, index) =>
139 | index === 0 ? `${bank.brandName}` : `, ${bank.brandName}`
140 | )}
141 | .
142 |
143 | {state.length > 0 && (
144 | bank.brandName)
148 | .map(
149 | (requiredBrand) => state.filter((brand) => brand.name === requiredBrand)[0]
150 | )
151 | .map(({ companies }) =>
152 | companies.map(({ name }) => {
153 | return name
154 | })
155 | )
156 | .map((array) => Object.values(array))}
157 | typesState={typesState}
158 | fixFunction={fixMoney}
159 | />
160 | )}
161 |
162 | {Object.keys(typesState).length === 0 && }
163 |
164 | Tabelas completas com as tarifas de contas para pessoas físicas.
165 |
166 | {state &&
167 | state.map((brand, index) =>
168 | brand.companies.map((company) => (
169 |
170 |
182 |
183 |
184 |
185 | Taxas de juros
186 | Tipo de conta
187 | Mín
188 | Máx
189 | Informações
190 |
191 |
192 |
193 | {company.businessAccounts &&
194 | company.businessAccounts.map(({ type, fees, termsConditions }) =>
195 | fees.services.map(
196 | (
197 | { name, chargingTriggerInfo, code, minimum, maximum },
198 | index
199 | ) => (
200 |
201 | {code.replace(/[_\s]/g, ' ')}
202 | {type.replace(/[_\s]/g, ' ')}
203 | {fixMoney(minimum.value)}
204 | {fixMoney(maximum.value)}
205 |
206 |
208 | addMoreInfo({
209 | name,
210 | chargingTriggerInfo,
211 | termsConditions,
212 | })
213 | }
214 | className="blue"
215 | >
216 | Mais Informações
217 |
218 |
219 |
220 | )
221 | )
222 | )}
223 |
224 |
225 |
226 | ))
227 | )}
228 |
229 |
230 | )
231 | }
232 |
233 | export default PersonalLoansPage
234 |
--------------------------------------------------------------------------------
/static/js/3.f4a706e7.chunk.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../node_modules/web-vitals/dist/web-vitals.es5.min.js"],"names":["v","t","n","e","concat","Date","now","Math","floor","random","i","arguments","length","name","value","delta","entries","id","isFinal","a","PerformanceObserver","supportedEntryTypes","includes","getEntries","map","observe","type","buffered","r","o","s","persisted","u","addEventListener","c","timeStamp","document","visibilityState","isUnloading","capture","once","l","disconnect","p","hadRecentInput","push","takeRecords","d","startTime","f","processingStart","window","perfMetrics","onFirstInputDelay","entryType","target","cancelable","m","Promise","passive","g","then","h","performance","getEntriesByType","timing","max","navigationStart","responseStart","readyState","setTimeout"],"mappings":"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","file":"static/js/3.f4a706e7.chunk.js","sourcesContent":["var t,n,e=function(){return\"\".concat(Date.now(),\"-\").concat(Math.floor(8999999999999*Math.random())+1e12)},i=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1;return{name:t,value:n,delta:0,entries:[],id:e(),isFinal:!1}},a=function(t,n){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){var e=new PerformanceObserver((function(t){return t.getEntries().map(n)}));return e.observe({type:t,buffered:!0}),e}}catch(t){}},r=!1,o=!1,s=function(t){r=!t.persisted},u=function(){addEventListener(\"pagehide\",s),addEventListener(\"beforeunload\",(function(){}))},c=function(t){var n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];o||(u(),o=!0),addEventListener(\"visibilitychange\",(function(n){var e=n.timeStamp;\"hidden\"===document.visibilityState&&t({timeStamp:e,isUnloading:r})}),{capture:!0,once:n})},l=function(t,n,e,i){var a;return function(){e&&n.isFinal&&e.disconnect(),n.value>=0&&(i||n.isFinal||\"hidden\"===document.visibilityState)&&(n.delta=n.value-(a||0),(n.delta||n.isFinal||void 0===a)&&(t(n),a=n.value))}},p=function(t){var n,e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],r=i(\"CLS\",0),o=function(t){t.hadRecentInput||(r.value+=t.value,r.entries.push(t),n())},s=a(\"layout-shift\",o);s&&(n=l(t,r,s,e),c((function(t){var e=t.isUnloading;s.takeRecords().map(o),e&&(r.isFinal=!0),n()})))},d=function(){return void 0===t&&(t=\"hidden\"===document.visibilityState?0:1/0,c((function(n){var e=n.timeStamp;return t=e}),!0)),{get timeStamp(){return t}}},v=function(t){var n,e=i(\"FCP\"),r=d(),o=a(\"paint\",(function(t){\"first-contentful-paint\"===t.name&&t.startTime1&&void 0!==arguments[1]&&arguments[1],r=i(\"LCP\"),o=d(),s=function(t){var e=t.startTime;e {
84 | const [state, setState] = useState([])
85 | const { addMoreInfo } = useModal()
86 |
87 | const endpoint = '/personal-credit-cards'
88 | const banks = getBanksOfApi(endpoint)
89 |
90 | // Realiza as consultas às APIs
91 | useEffect(() => {
92 | ;(async () => {
93 | const apiResponses = await callApisOpenBanking('/personal-credit-cards')
94 |
95 | setState(apiResponses)
96 | })()
97 | }, [])
98 |
99 | // Organiza as informações para serem lidas pela matriz
100 | const typesState = useMemo(() => {
101 | let services = []
102 | let servicesList = []
103 | let companies = []
104 | state.forEach((brand) =>
105 | brand.companies.forEach((company) => {
106 | company.personalCreditCards.forEach((creditcard) => {
107 | creditcard.fees.services.forEach(({ code, minimum, maximum }) => {
108 | const fare = {
109 | code,
110 | name: creditcard.name,
111 | minimum: minimum.value,
112 | maximum: maximum.value,
113 | }
114 |
115 | companies[company.name]
116 | ? companies[company.name].push(fare)
117 | : (companies[company.name] = [fare])
118 |
119 | !servicesList.includes(code) && servicesList.push(code)
120 | })
121 | })
122 | servicesList.forEach((serviceCode) => {
123 | const servicePayload = company.name !== 'INDISPONÍVEL' && {
124 | ...companies[company.name]
125 | .filter((fare) => fare.code === serviceCode)
126 | .map((fare) => {
127 | return {
128 | name: fare.name,
129 | minimum: fare.minimum,
130 | maximum: fare.maximum,
131 | }
132 | }),
133 | brand: brand.name,
134 | company: company.name,
135 | }
136 | services[serviceCode]
137 | ? services[serviceCode].push(servicePayload)
138 | : (services[serviceCode] = [servicePayload])
139 | })
140 | })
141 | )
142 |
143 | return services
144 | }, [state])
145 |
146 | return (
147 |
148 |
149 |
150 | Estas são todas as tarifas dos serviços de cartão de crédito para pessoa física
151 | dos bancos:
152 | {banks.map((bank, index) =>
153 | index === 0 ? `${bank.brandName}` : `, ${bank.brandName}`
154 | )}
155 | .
156 |
157 | {state.length > 0 && (
158 | bank.brandName)
162 | .map(
163 | (requiredBrand) => state.filter((brand) => brand.name === requiredBrand)[0]
164 | )
165 | .map(({ companies }) =>
166 | companies.map(({ name }) => {
167 | return name
168 | })
169 | )
170 | .map((array) => Object.values(array))}
171 | typesState={typesState}
172 | fixFunction={fixMoney}
173 | />
174 | )}
175 | {Object.keys(typesState).length === 0 && }
176 |
177 | Tabelas completas com as taxas de cartão de crédito para pessoa física.
178 |
179 | {state &&
180 | state.map((brand, index) =>
181 | brand.companies.map((company) => (
182 |
183 |
195 |
196 |
197 |
198 | Serviço
199 | Cartão
200 | Emissor
201 | Mín
202 | Máx
203 | Informações
204 |
205 |
206 |
207 | {company.personalCreditCards &&
208 | company.personalCreditCards.map(
209 | ({ identification, fees, termsConditions }) =>
210 | fees.services.map(
211 | (
212 | { name, code, chargingTriggerInfo, minimum, maximum },
213 | index
214 | ) => (
215 |
216 | {code.replace(/[_\s]/g, ' ')}
217 |
218 | {identification.product.type.replace(/[_\s]/g, ' ')}
219 |
220 |
221 | {identification.creditCard.network.replace(/[_\s]/g, ' ')}
222 |
223 | {fixMoney(minimum.value)}
224 | {fixMoney(maximum.value)}
225 |
226 |
228 | addMoreInfo({
229 | name,
230 | chargingTriggerInfo,
231 | termsConditions,
232 | })
233 | }
234 | className="blue"
235 | >
236 | Mais Informações
237 |
238 |
239 |
240 | )
241 | )
242 | )}
243 |
244 |
245 |
246 | ))
247 | )}
248 |
249 |
250 | )
251 | }
252 |
253 | export default PersonalCreditCardsPage
254 |
--------------------------------------------------------------------------------
/static/media/credit-card.11093fcb.svg:
--------------------------------------------------------------------------------
1 | credit card 2 CREDIT CARD CREDIT CARD
--------------------------------------------------------------------------------
/src/assets/img/illustrations/credit-card.svg:
--------------------------------------------------------------------------------
1 | credit card 2 CREDIT CARD CREDIT CARD
--------------------------------------------------------------------------------
/src/pages/BusinessCreditCards/index.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 |
3 | import React, { useState, useEffect, useMemo } from 'react'
4 |
5 | import { callApisOpenBanking } from '../../services/callApisOpenBanking'
6 | import { getBanksOfApi } from '../../utils/getBanksOfApi'
7 | import { fixMoney } from '../../utils/fixMoney'
8 | import { useModal } from '../../hooks/Modal'
9 |
10 | import ComparisonMatrix from '../../components/ComparisonMatrix'
11 | import Layout from '../../components/Layout/Layout'
12 | import {
13 | MatrixPageStyled,
14 | CompanyStyled,
15 | TableStyled,
16 | } from '../../styles/CallApiPage.styled'
17 |
18 | interface IResponseBusinessCreditCard {
19 | name: string
20 | companies: ICompanies[]
21 | }
22 |
23 | interface ICompanies {
24 | name: string
25 | cnpjNumber: string
26 | urlComplementaryList: string
27 | businessCreditCards: IBusinessCreditCards[]
28 | }
29 |
30 | interface IBusinessCreditCards {
31 | name: string
32 | identification: {
33 | product: {
34 | type: string
35 | additionalInfo: string
36 | }
37 | creditCard: {
38 | network: string
39 | additionalInfo: string
40 | }
41 | }
42 | rewardsProgram: {
43 | hasRewardProgram: boolean
44 | rewardProgramInfo: string
45 | }
46 | fees: {
47 | services: IService[]
48 | }
49 | interest: IInterest[]
50 | termsConditions: {
51 | minimumFeeRate: string
52 | additionalInfo: string | null
53 | elegibilityCriteriaInfo: string
54 | closingProcessInfo: string
55 | }
56 | }
57 |
58 | interface IService {
59 | name: string
60 | code: string
61 | chargingTriggerInfo: string
62 | prices: IPrice[]
63 | minimum: {
64 | value: string
65 | currency: string
66 | }
67 | maximum: {
68 | value: string
69 | currency: string
70 | }
71 | }
72 |
73 | interface IPrice {
74 | interval: string
75 | value: string
76 | currency: string
77 | customers: {
78 | rate: number
79 | }
80 | }
81 |
82 | interface IInterest {
83 | rates: IRates[]
84 | instalmentRates: IInstalmentRates[]
85 | otherCredits: IOtherCredits[]
86 | }
87 |
88 | const BusinessCreditCardsPage = () => {
89 | const [state, setState] = useState([])
90 | const { addMoreInfo } = useModal()
91 |
92 | const endpoint = '/business-credit-cards'
93 | const banks = getBanksOfApi(endpoint)
94 |
95 | // Realiza as consultas às APIs
96 | useEffect(() => {
97 | ;(async () => {
98 | const apiResponses = await callApisOpenBanking('/business-credit-cards')
99 |
100 | setState(apiResponses)
101 | })()
102 | }, [])
103 |
104 | // Organiza as informações para serem lidas pela matriz
105 | const typesState = useMemo(() => {
106 | let services = []
107 | let servicesList = []
108 | let companies = []
109 | state.forEach((brand) =>
110 | brand.companies.forEach((company) => {
111 | company.businessCreditCards.forEach((creditCard) => {
112 | creditCard.fees.services.forEach(({ code, minimum, maximum }) => {
113 | const fare = {
114 | code,
115 | name: creditCard.name,
116 | minimum: minimum.value,
117 | maximum: maximum.value,
118 | }
119 | if (fare.minimum !== 'NA' || fare.maximum !== 'NA') {
120 | companies[company.name]
121 | ? companies[company.name].push(fare)
122 | : (companies[company.name] = [fare])
123 | !servicesList.includes(code) && servicesList.push(code)
124 | }
125 | })
126 | })
127 | servicesList.forEach((serviceCode) => {
128 | const servicePayload = company.name !== 'INDISPONÍVEL' && {
129 | ...companies[company.name]
130 | .filter((fare) => fare.code === serviceCode)
131 | .map((fare) => {
132 | return {
133 | name: fare.name,
134 | minimum: fare.minimum,
135 | maximum: fare.maximum,
136 | }
137 | }),
138 | brand: brand.name,
139 | company: company.name,
140 | }
141 | services[serviceCode]
142 | ? services[serviceCode].push(servicePayload)
143 | : (services[serviceCode] = [servicePayload])
144 | })
145 | })
146 | )
147 |
148 | return services
149 | }, [state])
150 |
151 | return (
152 | <>
153 |
154 |
155 |
156 | Estas são todas as tarifas dos serviços de cartões de crédito para pessoa
157 | jurídica dos bancos:
158 | {banks.map((bank, index) =>
159 | index === 0 ? `${bank.brandName}` : `, ${bank.brandName}`
160 | )}
161 | .
162 |
163 | {state.length > 0 && (
164 | bank.brandName)
168 | .map(
169 | (requiredBrand) =>
170 | state.filter((brand) => brand.name === requiredBrand)[0]
171 | )
172 | .map(({ companies }) =>
173 | companies.map(({ name }) => {
174 | return name
175 | })
176 | )
177 | .map((array) => Object.values(array))}
178 | typesState={typesState}
179 | fixFunction={fixMoney}
180 | />
181 | )}
182 |
183 | Tabelas completas com as taxas de cartão de crédito para pessoa Jurídica.
184 |
185 | {state &&
186 | state.map((brand, index) =>
187 | brand.companies.map((company) => (
188 |
189 |
201 |
202 |
203 |
204 | Serviço
205 | Cartão
206 | Emissor
207 | Mín
208 | Máx
209 | Informações
210 |
211 |
212 |
213 | {company.businessCreditCards &&
214 | company.businessCreditCards.map(
215 | ({ identification, fees, termsConditions }) =>
216 | fees.services.map(
217 | (
218 | { code, name, chargingTriggerInfo, maximum, minimum },
219 | index
220 | ) => (
221 |
222 | {code.replace(/[_\s]/g, ' ')}
223 |
224 | {identification.product.type.replace(/[_\s]/g, ' ')}
225 |
226 |
227 | {identification.creditCard.network.replace(
228 | /[_\s]/g,
229 | ' '
230 | )}
231 |
232 | {fixMoney(minimum.value)}
233 | {fixMoney(maximum.value)}
234 |
235 |
237 | addMoreInfo({
238 | name,
239 | chargingTriggerInfo,
240 | termsConditions,
241 | })
242 | }
243 | className="blue"
244 | >
245 | Mais Informações
246 |
247 |
248 |
249 | )
250 | )
251 | )}
252 |
253 |
254 |
255 | ))
256 | )}
257 |
258 |
259 | >
260 | )
261 | }
262 |
263 | export default BusinessCreditCardsPage
264 |
--------------------------------------------------------------------------------
/static/media/loan.c6bc1e1a.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/img/illustrations/loan.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/static/js/runtime-main.07745ca7.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../webpack/bootstrap"],"names":["webpackJsonpCallback","data","moduleId","chunkId","chunkIds","moreModules","executeModules","i","resolves","length","Object","prototype","hasOwnProperty","call","installedChunks","push","modules","parentJsonpFunction","shift","deferredModules","apply","checkDeferredModules","result","deferredModule","fulfilled","j","depId","splice","__webpack_require__","s","installedModules","1","exports","module","l","e","promises","installedChunkData","promise","Promise","resolve","reject","onScriptComplete","script","document","createElement","charset","timeout","nc","setAttribute","src","p","jsonpScriptSrc","error","Error","event","onerror","onload","clearTimeout","chunk","errorType","type","realSrc","target","message","name","request","undefined","setTimeout","head","appendChild","all","m","c","d","getter","o","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","oe","err","console","jsonpArray","this","oldJsonpFunction","slice"],"mappings":"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","file":"static/js/runtime-main.07745ca7.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tfunction webpackJsonpCallback(data) {\n \t\tvar chunkIds = data[0];\n \t\tvar moreModules = data[1];\n \t\tvar executeModules = data[2];\n\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(data);\n\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n\n \t\t// add entry modules from loaded chunk to deferred list\n \t\tdeferredModules.push.apply(deferredModules, executeModules || []);\n\n \t\t// run deferred modules when all chunks ready\n \t\treturn checkDeferredModules();\n \t};\n \tfunction checkDeferredModules() {\n \t\tvar result;\n \t\tfor(var i = 0; i < deferredModules.length; i++) {\n \t\t\tvar deferredModule = deferredModules[i];\n \t\t\tvar fulfilled = true;\n \t\t\tfor(var j = 1; j < deferredModule.length; j++) {\n \t\t\t\tvar depId = deferredModule[j];\n \t\t\t\tif(installedChunks[depId] !== 0) fulfilled = false;\n \t\t\t}\n \t\t\tif(fulfilled) {\n \t\t\t\tdeferredModules.splice(i--, 1);\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = deferredModule[0]);\n \t\t\t}\n \t\t}\n\n \t\treturn result;\n \t}\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// undefined = chunk not loaded, null = chunk preloaded/prefetched\n \t// Promise = chunk loading, 0 = chunk loaded\n \tvar installedChunks = {\n \t\t1: 0\n \t};\n\n \tvar deferredModules = [];\n\n \t// script path function\n \tfunction jsonpScriptSrc(chunkId) {\n \t\treturn __webpack_require__.p + \"static/js/\" + ({}[chunkId]||chunkId) + \".\" + {\"3\":\"f4a706e7\"}[chunkId] + \".chunk.js\"\n \t}\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId) {\n \t\tvar promises = [];\n\n\n \t\t// JSONP chunk loading for javascript\n\n \t\tvar installedChunkData = installedChunks[chunkId];\n \t\tif(installedChunkData !== 0) { // 0 means \"already installed\".\n\n \t\t\t// a Promise means \"currently loading\".\n \t\t\tif(installedChunkData) {\n \t\t\t\tpromises.push(installedChunkData[2]);\n \t\t\t} else {\n \t\t\t\t// setup Promise in chunk cache\n \t\t\t\tvar promise = new Promise(function(resolve, reject) {\n \t\t\t\t\tinstalledChunkData = installedChunks[chunkId] = [resolve, reject];\n \t\t\t\t});\n \t\t\t\tpromises.push(installedChunkData[2] = promise);\n\n \t\t\t\t// start chunk loading\n \t\t\t\tvar script = document.createElement('script');\n \t\t\t\tvar onScriptComplete;\n\n \t\t\t\tscript.charset = 'utf-8';\n \t\t\t\tscript.timeout = 120;\n \t\t\t\tif (__webpack_require__.nc) {\n \t\t\t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n \t\t\t\t}\n \t\t\t\tscript.src = jsonpScriptSrc(chunkId);\n\n \t\t\t\t// create error before stack unwound to get useful stacktrace later\n \t\t\t\tvar error = new Error();\n \t\t\t\tonScriptComplete = function (event) {\n \t\t\t\t\t// avoid mem leaks in IE.\n \t\t\t\t\tscript.onerror = script.onload = null;\n \t\t\t\t\tclearTimeout(timeout);\n \t\t\t\t\tvar chunk = installedChunks[chunkId];\n \t\t\t\t\tif(chunk !== 0) {\n \t\t\t\t\t\tif(chunk) {\n \t\t\t\t\t\t\tvar errorType = event && (event.type === 'load' ? 'missing' : event.type);\n \t\t\t\t\t\t\tvar realSrc = event && event.target && event.target.src;\n \t\t\t\t\t\t\terror.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';\n \t\t\t\t\t\t\terror.name = 'ChunkLoadError';\n \t\t\t\t\t\t\terror.type = errorType;\n \t\t\t\t\t\t\terror.request = realSrc;\n \t\t\t\t\t\t\tchunk[1](error);\n \t\t\t\t\t\t}\n \t\t\t\t\t\tinstalledChunks[chunkId] = undefined;\n \t\t\t\t\t}\n \t\t\t\t};\n \t\t\t\tvar timeout = setTimeout(function(){\n \t\t\t\t\tonScriptComplete({ type: 'timeout', target: script });\n \t\t\t\t}, 120000);\n \t\t\t\tscript.onerror = script.onload = onScriptComplete;\n \t\t\t\tdocument.head.appendChild(script);\n \t\t\t}\n \t\t}\n \t\treturn Promise.all(promises);\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/open-banking-brasil/\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n \tvar jsonpArray = this[\"webpackJsonpopen-banking-brasil\"] = this[\"webpackJsonpopen-banking-brasil\"] || [];\n \tvar oldJsonpFunction = jsonpArray.push.bind(jsonpArray);\n \tjsonpArray.push = webpackJsonpCallback;\n \tjsonpArray = jsonpArray.slice();\n \tfor(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);\n \tvar parentJsonpFunction = oldJsonpFunction;\n\n\n \t// run deferred modules from other chunks\n \tcheckDeferredModules();\n"],"sourceRoot":""}
--------------------------------------------------------------------------------