Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusab committed Dec 21, 2024
1 parent 53569b0 commit 1d832a9
Show file tree
Hide file tree
Showing 23 changed files with 518 additions and 70 deletions.
2 changes: 2 additions & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"next-themes": "^0.3.0",
"nuqs": "^1.19.3",
"papaparse": "^5.4.1",
"pluggy-connect-sdk": "^2.9.1",
"react": "18.3.1",
"react-colorful": "^5.6.1",
"react-dom": "18.3.1",
Expand All @@ -67,6 +68,7 @@
"react-intersection-observer": "^9.13.1",
"react-markdown": "^9.0.1",
"react-plaid-link": "^3.6.0",
"react-pluggy-connect": "^2.10.2",
"react-use-draggable-scroll": "^0.4.7",
"recharts": "^2.12.7",
"resend": "^4.0.1",
Expand Down
31 changes: 31 additions & 0 deletions apps/dashboard/src/actions/institutions/create-pluggy-link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"use server";

import { client } from "@midday/engine/client";
import { getSession } from "@midday/supabase/cached-queries";

export const createPluggyLinkTokenAction = async (accessToken?: string) => {
const {
data: { session },
} = await getSession();

if (!session?.user.id) {
throw new Error("User not found");
}

const pluggyResponse = await client.auth.pluggy.link.$post({
json: {
userId: session.user.id,
environment: "production",
},
});

if (!pluggyResponse.ok) {
throw new Error("Failed to create pluggy link token");
}

const { data } = await pluggyResponse.json();

console.log(data);

return data.access_token;
};
16 changes: 15 additions & 1 deletion apps/dashboard/src/components/connect-bank-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ 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 = {
id: string;
provider: string;
availableHistory: number;
openPlaid: () => void;
openPluggy: (props: { institutionId?: string }) => void;
};

export function ConnectBankProvider({
id,
provider,
openPlaid,
openPluggy,
availableHistory,
}: Props) {
const { setParams } = useConnectParams();
Expand Down Expand Up @@ -51,7 +54,7 @@ export function ConnectBankProvider({
/>
);
}
case "plaid":
case "plaid": {
return (
<BankConnectButton
onClick={() => {
Expand All @@ -60,6 +63,17 @@ export function ConnectBankProvider({
}}
/>
);
}
case "pluggy": {
return (
<BankConnectButton
onClick={() => {
updateUsage();
openPluggy({ institutionId: id });
}}
/>
);
}
default:
return null;
}
Expand Down
2 changes: 2 additions & 0 deletions apps/dashboard/src/components/institution-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export function InstitutionInfo({ provider, children }: Props) {
return `With Plaid we can connect to 12,000+ financial institutions across the US, Canada, UK, and Europe are covered by Plaid's network`;
case "teller":
return "With Teller we can connect instantly to more than 5,000 financial institutions in the US.";
case "pluggy":
return "With Pluggy we can connect to all major financial institutions in Brazil.";
default:
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"use client";

import { createPlaidLinkTokenAction } from "@/actions/institutions/create-plaid-link";
import { createPluggyLinkTokenAction } from "@/actions/institutions/create-pluggy-link";
import { exchangePublicToken } from "@/actions/institutions/exchange-public-token";
import { getInstitutions } from "@/actions/institutions/get-institutions";
import { useConnectParams } from "@/hooks/use-connect-params";
import { usePluggyLink } from "@/hooks/use-pluggy-link";
import type { Institutions } from "@midday-ai/engine/resources/institutions/institutions";
import { track } from "@midday/events/client";
import { LogEvents } from "@midday/events/events";
Expand Down Expand Up @@ -49,6 +51,7 @@ type SearchResultProps = {
provider: string;
availableHistory: number;
openPlaid: () => void;
openPluggy: () => void;
};

function SearchResult({
Expand All @@ -58,6 +61,7 @@ function SearchResult({
provider,
availableHistory,
openPlaid,
openPluggy,
}: SearchResultProps) {
return (
<div className="flex justify-between">
Expand All @@ -79,6 +83,7 @@ function SearchResult({
provider={provider}
openPlaid={openPlaid}
availableHistory={availableHistory}
openPluggy={openPluggy}
/>
</div>
);
Expand All @@ -95,6 +100,7 @@ export function ConnectTransactionsModal({
const [loading, setLoading] = useState(true);
const [results, setResults] = useState<Institutions["data"]>([]);
const [plaidToken, setPlaidToken] = useState<string | undefined>();
const [pluggyToken, setPluggyToken] = useState<string | undefined>();

const {
countryCode,
Expand Down Expand Up @@ -144,6 +150,35 @@ export function ConnectTransactionsModal({
},
});

const { open: openPluggy } = usePluggyLink({
token: pluggyToken,
onSuccess: (itemData) => {
// const { access_token, item_id } = await exchangePublicToken(public_token);

// setParams({
// step: "account",
// provider: "pluggy",
// token: access_token,
// ref: item_id,
// institution_id: metadata.institution?.institution_id,
// });
track({
event: LogEvents.ConnectBankAuthorized.name,
channel: LogEvents.ConnectBankAuthorized.channel,
provider: "pluggy",
});
},
onExit: () => {
setParams({ step: "connect" });

track({
event: LogEvents.ConnectBankCanceled.name,
channel: LogEvents.ConnectBankCanceled.channel,
provider: "pluggy",
});
},
});

const handleOnClose = () => {
setParams(
{
Expand Down Expand Up @@ -202,6 +237,21 @@ export function ConnectTransactionsModal({
}
}, [isOpen, countryCode]);

useEffect(() => {
async function createLinkToken() {
const token = await createPluggyLinkTokenAction();

if (token) {
setPluggyToken(token);
}
}

// NOTE: Only run where Pluggy is supported (Brazil)
if (isOpen && countryCode === "BR") {
createLinkToken();
}
}, [isOpen, countryCode]);

return (
<Dialog open={isOpen} onOpenChange={handleOnClose}>
<DialogContent>
Expand Down Expand Up @@ -271,6 +321,10 @@ export function ConnectTransactionsModal({
setParams({ step: null });
openPlaid();
}}
openPluggy={() => {
setParams({ step: null });
openPluggy({ institutionId: institution.id });
}}
/>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export function SelectBankAccountsModal() {
useEffect(() => {
async function fetchData() {
const { data } = await getAccounts({
provider: provider as "teller" | "plaid" | "gocardless",
provider: provider as "teller" | "plaid" | "gocardless" | "pluggy",
id: ref ?? undefined,
accessToken: token ?? undefined,
institutionId: institution_id ?? undefined,
Expand Down
62 changes: 62 additions & 0 deletions apps/dashboard/src/components/pluggy-connect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useConnectParams } from "@/hooks/use-connect-params";
import { track } from "@midday/events/client";
import { LogEvents } from "@midday/events/events";
import { useTheme } from "next-themes";
import { useState } from "react";
import { PluggyConnect as PluggySDK } from "react-pluggy-connect";
import { BankConnectButton } from "./bank-connect-button";

type Props = {
id: string;
onSelect: (id: string) => void;
};

export function PluggyConnect({ id, onSelect }: Props) {
const [institution, setInstitution] = useState<string | undefined>();
const [isOpen, setIsOpen] = useState(false);
const { setParams } = useConnectParams();
const { theme } = useTheme();

return (
<>
<BankConnectButton
onClick={() => {
onSelect(id);
setInstitution(id);
setIsOpen(true);
}}
/>

{isOpen && (
<PluggySDK
theme={theme as "light" | "dark"}
selectedConnectorId={Number(institution)}
connectToken={"your-connect-token-here"}
onError={() => {
setParams({ step: "connect" });
track({
event: LogEvents.ConnectBankCanceled.name,
channel: LogEvents.ConnectBankCanceled.channel,
provider: "pluggy",
});

setParams({ step: "connect" });
}}
onSuccess={() => {
// setParams({
// step: "account",
// provider: "pluggy",
// token: authorization.accessToken,
// enrollment_id: authorization.enrollment.id,
// });
// track({
// event: LogEvents.ConnectBankAuthorized.name,
// channel: LogEvents.ConnectBankAuthorized.channel,
// provider: "pluggy",
// });
}}
/>
)}
</>
);
}
47 changes: 47 additions & 0 deletions apps/dashboard/src/hooks/use-pluggy-link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as PluggyConnect from "pluggy-connect-sdk";
import { useEffect, useState } from "react";

type Props = {
token: string;
institutionId?: string;
onExit: () => void;
onSuccess: (itemData: any) => void;
onError: () => void;
includeSandbox?: boolean;
};

export function usePluggyLink({
token,
institutionId,
onExit,
onSuccess,
onError,
includeSandbox = false,
}: Props) {
const [connectToken, setConnectToken] = useState<string>("");
const [selectedConnectorId, setSelectedConnectorId] = useState<
number | undefined
>(institutionId ? Number(institutionId) : undefined);

useEffect(() => {
setConnectToken(token);
}, [token]);

const pluggyConnect = new PluggyConnect.PluggyConnect({
connectToken,
includeSandbox,
selectedConnectorId,
onClose: onExit,
onSuccess,
onError,
});

const handleOpen = ({ institutionId }: { institutionId?: string }) => {
setSelectedConnectorId(Number(institutionId));
pluggyConnect.init();
};

return {
open: handleOpen,
};
}
4 changes: 3 additions & 1 deletion apps/engine/.dev.vars-example
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ TYPESENSE_API_KEY=
TYPESENSE_ENDPOINT=
TYPESENSE_ENDPOINT_US=
TYPESENSE_ENDPOINT_EU=
TYPESENSE_ENDPOINT_AU=
TYPESENSE_ENDPOINT_AU=
PLUGGY_CLIENT_ID=
PLUGGY_SECRET=
10 changes: 0 additions & 10 deletions apps/engine/.env-example

This file was deleted.

12 changes: 6 additions & 6 deletions apps/engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@
"dependencies": {
"@hono/swagger-ui": "^0.5.0",
"@hono/zod-openapi": "^0.18.3",
"@hono/zod-validator": "^0.4.1",
"hono": "^4.6.13",
"@hono/zod-validator": "^0.4.2",
"hono": "^4.6.14",
"plaid": "^30.0.0",
"pluggy-sdk": "^0.64.0",
"pluggy-sdk": "^0.65.1",
"typesense": "^1.8.2",
"workers-ai-provider": "^0.0.10",
"xior": "^0.6.1",
"zod": "^3.23.8"
"zod": "^3.24.1"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20241205.0",
"@cloudflare/workers-types": "^4.20241218.0",
"@types/bun": "^1.1.14",
"wrangler": "^3.93.0"
"wrangler": "^3.99.0"
},
"exports": {
"./client": "./src/client/index.ts",
Expand Down
2 changes: 2 additions & 0 deletions apps/engine/src/common/bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export type Bindings = {
PLAID_CLIENT_ID: string;
PLAID_ENVIRONMENT: string;
PLAID_SECRET: string;
PLUGGY_CLIENT_ID: string;
PLUGGY_SECRET: string;
TYPESENSE_API_KEY: string;
TYPESENSE_ENDPOINT_AU: string;
TYPESENSE_ENDPOINT_EU: string;
Expand Down
Loading

0 comments on commit 1d832a9

Please sign in to comment.