Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusab committed Dec 22, 2024
1 parent decd0f6 commit 3a7cc1e
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 6 deletions.
1 change: 0 additions & 1 deletion apps/dashboard/src/components/connect-bank-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useConnectParams } from "@/hooks/use-connect-params";
import { useAction } from "next-safe-action/hooks";
import { BankConnectButton } from "./bank-connect-button";
import { GoCardLessConnect } from "./gocardless-connect";
import { PluggyConnect } from "./pluggy-connect";
import { TellerConnect } from "./teller-connect";

type Props = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { Input } from "@midday/ui/input";
import { Skeleton } from "@midday/ui/skeleton";
import { useDebounce, useScript } from "@uidotdev/usehooks";
import { useTheme } from "next-themes";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { usePlaidLink } from "react-plaid-link";
Expand Down Expand Up @@ -97,6 +98,7 @@ export function ConnectTransactionsModal({
countryCode: initialCountryCode,
}: ConnectTransactionsModalProps) {
const router = useRouter();
const { theme } = useTheme();
const [loading, setLoading] = useState(true);
const [results, setResults] = useState<Institutions["data"]>([]);
const [plaidToken, setPlaidToken] = useState<string | undefined>();
Expand Down Expand Up @@ -152,6 +154,8 @@ export function ConnectTransactionsModal({

const { open: openPluggy } = usePluggyLink({
token: pluggyToken,
theme: theme === "dark" ? "dark" : "light",
language: "en",
onSuccess: (itemData) => {
// const { access_token, item_id } = await exchangePublicToken(public_token);

Expand Down
6 changes: 6 additions & 0 deletions apps/dashboard/src/hooks/use-pluggy-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ type Props = {
onSuccess: (itemData: any) => void;
onError: () => void;
includeSandbox?: boolean;
theme?: "light" | "dark";
language?: string;
};

export function usePluggyLink({
Expand All @@ -17,6 +19,8 @@ export function usePluggyLink({
onSuccess,
onError,
includeSandbox = false,
language = "pt",
theme,
}: Props) {
const [connectToken, setConnectToken] = useState<string>("");
const [selectedConnectorId, setSelectedConnectorId] = useState<
Expand All @@ -34,6 +38,8 @@ export function usePluggyLink({
onClose: onExit,
onSuccess,
onError,
theme,
language,
});

const handleOpen = ({ institutionId }: { institutionId?: string }) => {
Expand Down
13 changes: 10 additions & 3 deletions apps/engine/src/providers/pluggy/pluggy-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
ConnectTokenResponse,
GetAccountsRequest,
GetInstitutionsRequest,
GetInstitutionsResponse,
GetStatusResponse,
GetTransactionsParams,
LinkTokenCreateRequest,
Expand Down Expand Up @@ -109,9 +110,15 @@ export class PluggyApi {
};
}

async getInstitutions({ countries }: GetInstitutionsRequest) {
const response = await this.#get("/connectors", undefined, {
countries: countries,
async getInstitutions({
countries,
sandbox,
}: GetInstitutionsRequest): Promise<GetInstitutionsResponse> {
const apiKey = await this.#getApiKey();

const response = await this.#get("/connectors", apiKey, {
countries,
sandbox: sandbox ? "true" : "false",
});

return response.results;
Expand Down
93 changes: 93 additions & 0 deletions apps/engine/src/providers/pluggy/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type GetStatusResponse = {

export type GetInstitutionsRequest = {
countries?: string[];
sandbox?: boolean;
};

export type GetAccountsRequest = {
Expand All @@ -34,3 +35,95 @@ export type LinkTokenCreateRequest = {
export type ConnectTokenResponse = {
accessToken: string;
};

export const CREDENTIAL_TYPES = [
"number",
"password",
"text",
"image",
"select",
"ethaddress",
"hcaptcha",
] as const;

export const CONNECTOR_TYPES = [
"PERSONAL_BANK",
"BUSINESS_BANK",
"INVOICE",
"INVESTMENT",
"TELECOMMUNICATION",
"DIGITAL_ECONOMY",
"PAYMENT_ACCOUNT",
"OTHER",
] as const;
/**
* @typedef ConnectorType
* Type of connectors available
*/
export type ConnectorType = (typeof CONNECTOR_TYPES)[number];

export type CredentialSelectOption = {
/** Value of the option */
value: string;
/** Displayable text or label of the option */
label: string;
};

export type CredentialType = (typeof CREDENTIAL_TYPES)[number];

export type ConnectorCredential = {
/** parameter label that describes it */
label: string;
/** parameter key name */
name: string;
/** type of parameter to create the form */
type?: CredentialType;
/** If parameter is used for MFA. */
mfa?: boolean;
/** If parameter is image, base64 string is provided */
data?: string;
/** Assistive information to help the user provide us the credential */
assistiveText?: string;
/** Available options if credential is of type 'select' */
options?: CredentialSelectOption[];
/** Regex to validate input */
validation?: string;
/** Error message of input validation on institution language */
validationMessage?: string;
/** Input's placeholder for help */
placeholder?: string;
/** Is this credential optional? */
optional?: boolean;
/** Applies to MFA credential only - Detailed information that includes details/hints that the user should be aware of */
instructions?: string;
/** Parameter expiration date, input value should be submitted before this date. */
expiresAt?: Date;
};

export type Connector = {
id: number;
/** Financial institution name */
name: string;
/** Url of the institution that the connector represents */
institutionUrl: string;
/** Image url of the institution. */
imageUrl: string;
/** Primary color of the institution */
primaryColor: string;
/** Type of the connector */
type: ConnectorType;
/** Country of the institution */
country: string;
/** List of parameters needed to execute the connector */
credentials: ConnectorCredential[];
/** Has MFA steps */
hasMFA: boolean;
/** If true, connector has an Oauth login */
oauth?: boolean;
/** (only for OAuth connector) this URL is used to connect the user and on success it will redirect to create the new item */
oauthUrl?: string;
};

export type GetInstitutionsResponse = {
results: Connector[];
};
4 changes: 3 additions & 1 deletion apps/engine/tasks/download-pluggy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ async function main() {
},
});

const data = await provider.getInstitutions({ countries: ["BR"] });
const data = await provider.getInstitutions({
countries: ["BR"],
});

const tasks = data.map(async (institution) => {
const extension = getFileExtension(institution.imageUrl);
Expand Down
4 changes: 3 additions & 1 deletion apps/engine/tasks/get-institutions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ export async function getPluggyInstitutions() {
},
});

const data = await provider.getInstitutions({ countries: ["BR"] });
const data = await provider.getInstitutions({
countries: ["BR"],
});

return data.map((institution) => {
const extension = getFileExtension(institution.imageUrl);
Expand Down

0 comments on commit 3a7cc1e

Please sign in to comment.