Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teller & Plaid #13

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions .env-example
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
NEXT_PUBLIC_SUPABASE_URL=
DUB_API_KEY=
GOCARDLESS_SECRET_ID=
GOCARDLESS_SECRET_KEY=
NEXT_PUBLIC_LOGSNAG_DISABLED=true
LOGSNAG_PRIVATE_TOKEN=
LOOPS_API_KEY=
LOOPS_ENDPOINT=
NEXT_PUBLIC_LOGSNAG_PROJECT=
NEXT_PUBLIC_LOGSNAG_TOKEN=
NEXT_PUBLIC_PLAID_ENVIRONMENT=
NEXT_PUBLIC_PLAID_PUBLIC_KEY=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
NEXT_PUBLIC_SUPABASE_ID=
SUPABASE_SERVICE_KEY=
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_TELLER_APPLICATION_ID=
NEXT_PUBLIC_TELLER_ENVIRONMENT=
NEXT_PUBLIC_TRIGGER_API_KEY=
NOVU_API_KEY=
RESEND_API_KEY=
LOOPS_ENDPOINT=
LOOPS_API_KEY=
GOCARDLESS_SECRET_ID=
GOCARDLESS_SECRET_KEY=
UPSTASH_REDIS_REST_URL=
SUPABASE_SERVICE_KEY=
UPSTASH_REDIS_REST_TOKEN=
NOVU_API_KEY=
NEXT_PUBLIC_TRIGGER_API_KEY=
NEXT_PUBLIC_LOGSNAG_TOKEN=
NEXT_PUBLIC_LOGSNAG_PROJECT=
LOGSNAG_PRIVATE_TOKEN=
LOGSNAG_DISABLE=true
DUB_API_KEY=
UPSTASH_REDIS_REST_URL=
4 changes: 3 additions & 1 deletion apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@baselime/node-opentelemetry": "^0.3.8",
"@hookform/resolvers": "^3.3.4",
"@midday/events": "workspace:*",
"@midday/gocardless": "workspace:*",
"@midday/providers": "workspace:*",
"@midday/jobs": "workspace:*",
"@midday/kv": "workspace:*",
"@midday/location": "workspace:*",
Expand Down Expand Up @@ -57,9 +57,11 @@
"react-intersection-observer": "^9.8.1",
"react-pdf": "^7.7.1",
"react-pin-field": "^3.1.5",
"react-plaid-link": "^3.5.1",
"recharts": "^2.12.1",
"resend": "^3.2.0",
"sharp": "^0.33.2",
"teller-connect-react": "^0.1.0",
"tus-js-client": "^4.0.1",
"typewriter-effect": "^2.21.0",
"use-long-press": "^3.2.0",
Expand Down
13 changes: 13 additions & 0 deletions apps/dashboard/src/actions/connect-bank-account-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,25 @@ export const connectBankAccountAction = action(
icon: LogEvents.ConnectBankCompleted.icon,
user_id: user.data.email,
channel: LogEvents.ConnectBankCompleted.channel,
tags: {
provider,
},
});

return event;
} catch (err) {
console.log(err);

logsnag.track({
event: LogEvents.ConnectBankFailed.name,
icon: LogEvents.ConnectBankFailed.icon,
user_id: user.data.email,
channel: LogEvents.ConnectBankFailed.channel,
tags: {
provider,
},
});

throw new Error("Something went wrong");
}
}
Expand Down
4 changes: 4 additions & 0 deletions apps/dashboard/src/app/[locale]/(app)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export default async function Layout({
<>
{dashboard}
<SetUserIdServerComponent userId={user.id} />

{!process.env.NEXT_PUBLIC_LOGSNAG_DISABLED && (
<SetUserIdServerComponent userId={user.id} />
)}
</>
);
}
Expand Down
1 change: 1 addition & 0 deletions apps/dashboard/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default function Layout({
<LogSnagProvider
token={process.env.NEXT_PUBLIC_LOGSNAG_TOKEN!}
project={process.env.NEXT_PUBLIC_LOGSNAG_PROJECT!}
disableTracking={Boolean(process.env.NEXT_PUBLIC_LOGSNAG_DISABLED!)}
/>
</head>
<body
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
"use client";

import {
buildLink,
createEndUserAgreement,
getBanks,
} from "@midday/gocardless";
import { gocardless } from "@midday/providers";
import { Avatar, AvatarImage } from "@midday/ui/avatar";
import { Button } from "@midday/ui/button";
import {
Expand Down Expand Up @@ -103,7 +99,7 @@ export function ConnectGoCardLessModal({ countryCode }) {

useEffect(() => {
async function fetchData() {
const banks = await getBanks(countryCode);
const banks = await gocardless.getBanks(countryCode);
setLoading(false);

if (banks.length > 0) {
Expand All @@ -118,11 +114,11 @@ export function ConnectGoCardLessModal({ countryCode }) {
}, [isOpen]);

const handleCreateEndUserAgreement = async (institutionId: string) => {
const data = await createEndUserAgreement(institutionId);
const data = await gocardless.createEndUserAgreement(institutionId);

const redirectBase = isDesktopApp() ? "midday://" : location.origin;

const { link } = await buildLink({
const { link } = await gocardless.buildLink({
redirect: `${redirectBase}/${pathname}?step=select-account-gocardless`,
institutionId,
agreement: data.id,
Expand Down
120 changes: 112 additions & 8 deletions apps/dashboard/src/components/modals/connect-transactions-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use client";

import { useLogSnag } from "@midday/events/client";
import { LogEvents } from "@midday/events/events";
import { Card, CardDescription, CardHeader, CardTitle } from "@midday/ui/card";
import {
Dialog,
Expand All @@ -8,46 +10,148 @@ import {
DialogHeader,
DialogTitle,
} from "@midday/ui/dialog";
import {
Tabs,
TabsContent,
// TabsList, TabsTrigger
} from "@midday/ui/tabs";
import { Tabs, TabsContent } from "@midday/ui/tabs";
import Image from "next/image";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { usePlaidLink } from "react-plaid-link";
import { TellerConnectOptions, useTellerConnect } from "teller-connect-react";
import GoCardLessLogo from "./gocardless.png";
import PlaidLogo from "./plaid.png";
import TellerLogo from "./teller.png";

export function ConnectTransactionsModal({ countryCode }) {
const { track } = useLogSnag();
const searchParams = useSearchParams();
const router = useRouter();
const pathname = usePathname();
const isOpen = searchParams.get("step") === "connect";

const { open: openTeller, ready: tellerReady } = useTellerConnect({
applicationId: process.env.NEXT_PUBLIC_TELLER_APPLICATION_ID!,
environment: process.env
.NEXT_PUBLIC_TELLER_ENVIRONMENT as TellerConnectOptions["environment"],
appearance: "system",
onExit: () => {
track({
event: LogEvents.ConnectBankCanceled.name,
icon: LogEvents.ConnectBankCanceled.icon,
channel: LogEvents.ConnectBankCanceled.channel,
tags: {
provider: "teller",
},
});

router.push("?step=connect");
},
onSuccess: (authorization) => {
console.log(authorization);
// Save your access token here
// connectBankAccountAction()

track({
event: LogEvents.ConnectBankAuthorized.name,
icon: LogEvents.ConnectBankAuthorized.icon,
channel: LogEvents.ConnectBankAuthorized.channel,
tags: {
provider: "teller",
},
});
},
// onFailure: () => {},
});

const { open: openPlaid, ready: plaidReady } = usePlaidLink({
token: "",
publicKey: process.env.NEXT_PUBLIC_PLAID_PUBLIC_KEY!,
env: process.env.NEXT_PUBLIC_PLAID_ENVIRONMENT!,
clientName: "Midday",
product: ["transactions"],
onSuccess: (public_token, metadata) => {
console.log(public_token, metadata);
// Save your access token here
// connectBankAccountAction()

track({
event: LogEvents.ConnectBankAuthorized.name,
icon: LogEvents.ConnectBankAuthorized.icon,
channel: LogEvents.ConnectBankAuthorized.channel,
tags: {
provider: "plaid",
},
});
},
onExit: () => {
track({
event: LogEvents.ConnectBankCanceled.name,
icon: LogEvents.ConnectBankCanceled.icon,
channel: LogEvents.ConnectBankCanceled.channel,
tags: {
provider: "plaid",
},
});

router.push("?step=connect");
},
});

const banks = [
{
id: "gocardless",
name: "GoCardless (Europe)",
description:
"More than 2,500 connected banks in 31 countries across the UK and Europe.",
logo: GoCardLessLogo,
onClick: () => router.push("?step=gocardless"),
onClick: () => {
track({
event: LogEvents.ConnectBankProvider.name,
icon: LogEvents.ConnectBankProvider.icon,
channel: LogEvents.ConnectBankProvider.channel,
tags: {
provider: "gocardless",
},
});

router.push("?step=gocardless");
},
},
{
id: "teller",
name: "Teller (US)",
description:
"With Teller we can connect to instantly with more than 5,000 financial institutions in the US.",
logo: TellerLogo,
disabled: true,
onClick: () => {
track({
event: LogEvents.ConnectBankProvider.name,
icon: LogEvents.ConnectBankProvider.icon,
channel: LogEvents.ConnectBankProvider.channel,
tags: {
provider: "teller",
},
});

openTeller();
},
disabled: !tellerReady,
},
{
id: "plaid",
name: "Plaid (US, Canada, UK)",
description: `12,000+ financial institutions across the US, Canada, UK, and Europe are covered by Plaid's network`,
logo: PlaidLogo,
disabled: true,
onClick: () => {
track({
event: LogEvents.ConnectBankProvider.name,
icon: LogEvents.ConnectBankProvider.icon,
channel: LogEvents.ConnectBankProvider.channel,
tags: {
provider: "plaid",
},
});

openPlaid();
},
disabled: !plaidReady,
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { connectBankAccountAction } from "@/actions/connect-bank-account-action";
import { zodResolver } from "@hookform/resolvers/zod";
import { getAccounts } from "@midday/gocardless";
import { gocardless } from "@midday/gocardless";
import { Avatar, AvatarImage } from "@midday/ui/avatar";
import { Button } from "@midday/ui/button";
import { Checkbox } from "@midday/ui/checkbox";
Expand Down Expand Up @@ -128,7 +128,7 @@ export function SelectAccountGoCardLessModal({ countryCode }) {

useEffect(() => {
async function fetchData() {
const data = await getAccounts({
const data = await gocardless.getAccounts({
accountId: searchParams.get("ref"),
countryCode,
});
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/src/components/reconnect-button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { buildLink, createEndUserAgreement } from "@midday/gocardless";
import { buildLink, createEndUserAgreement } from "@midday/providers";
import { Button } from "@midday/ui/button";
import { Icons } from "@midday/ui/icons";
import { isDesktopApp } from "@todesktop/client-core/platform/todesktop";
Expand Down
11 changes: 11 additions & 0 deletions apps/dashboard/src/env.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export const env = createEnv({
NEXT_PUBLIC_TRIGGER_API_KEY: z.string(),
NEXT_PUBLIC_LOGSNAG_TOKEN: z.string(),
NEXT_PUBLIC_LOGSNAG_PROJECT: z.string(),
NEXT_PUBLIC_TELLER_APPLICATION_ID: z.string(),
NEXT_PUBLIC_TELLER_ENVIRONMENT: z.string(),
NEXT_PUBLIC_PLAID_PUBLIC_KEY: z.string(),
NEXT_PUBLIC_PLAID_ENVIRONMENT: z.string(),
NEXT_PUBLIC_LOGSNAG_DISABLED: z.boolean().optional(),
},
/**
* Destructure all variables from `process.env` to make sure they aren't tree-shaken away.
Expand All @@ -46,6 +51,11 @@ export const env = createEnv({
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
NEXT_PUBLIC_SUPABASE_ID: process.env.NEXT_PUBLIC_SUPABASE_ID,
NEXT_PUBLIC_TELLER_APPLICATION_ID:
process.env.NEXT_PUBLIC_TELLER_APPLICATION_ID,
NEXT_PUBLIC_TELLER_ENVIRONMENT: process.env.NEXT_PUBLIC_TELLER_ENVIRONMENT,
NEXT_PUBLIC_PLAID_PUBLIC_KEY: process.env.NEXT_PUBLIC_PLAID_PUBLIC_KEY,
NEXT_PUBLIC_PLAID_ENVIRONMENT: process.env.NEXT_PUBLIC_PLAID_ENVIRONMENT,
RESEND_API_KEY: process.env.RESEND_API_KEY,
PORT: process.env.PORT,
LOOPS_ENDPOINT: process.env.LOOPS_ENDPOINT,
Expand All @@ -63,6 +73,7 @@ export const env = createEnv({
SUPABASE_SERVICE_KEY: process.env.SUPABASE_SERVICE_KEY,
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
API_ROUTE_SECRET: process.env.API_ROUTE_SECRET,
NEXT_PUBLIC_LOGSNAG_DISABLED: process.env.NEXT_PUBLIC_LOGSNAG_DISABLED,
},
skipValidation: !!process.env.CI || !!process.env.SKIP_ENV_VALIDATION,
});
Binary file modified bun.lockb
Binary file not shown.
20 changes: 20 additions & 0 deletions packages/events/src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,26 @@ export const LogEvents = {
icon: "🏦",
channel: "bank",
},
ConnectBankProvider: {
name: "Connect Bank Provider",
icon: "🏦",
channel: "bank",
},
ConnectBankCanceled: {
name: "Connect Bank Canceled",
icon: "🏦",
channel: "bank",
},
ConnectBankAuthorized: {
name: "Connect Bank Authorized",
icon: "🏦",
channel: "bank",
},
ConnectBankFailed: {
name: "Connect Bank Failed",
icon: "🏦",
channel: "bank",
},
DeleteBank: {
name: "Delete Bank",
icon: "🏦",
Expand Down
2 changes: 1 addition & 1 deletion packages/events/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ import { LogSnag } from "@logsnag/next/server";
export const logsnag = new LogSnag({
token: process.env.LOGSNAG_PRIVATE_TOKEN!,
project: process.env.NEXT_PUBLIC_LOGSNAG_PROJECT!,
disableTracking: Boolean(process.env.LOGSNAG_DISABLE!),
disableTracking: Boolean(process.env.NEXT_PUBLIC_LOGSNAG_DISABLED!),
});
Loading
Loading