diff --git a/.env-example b/.env-example index f7fdbbb87c..43bb08067b 100644 --- a/.env-example +++ b/.env-example @@ -1,4 +1,3 @@ -NEXTAUTH_URL=http://localhost:3000 NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= RESEND_API_KEY= diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 503961070a..a2cf0bf1dc 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -5,7 +5,7 @@ "scripts": { "build": "NODE_ENV=production next build", "clean": "git clean -xdf .next .turbo node_modules", - "jobs": "bunx @trigger.dev/cli@latest dev --port 3001", + "jobs": "bunx @trigger.dev/cli@latest dev --port 3001 --client-id=midday-CpkS", "dev": "next dev -p 3001", "lint": "next lint", "format": "biome format --write .", @@ -31,23 +31,23 @@ "framer-motion": "^10.16.5", "next": "14.0.4-canary.4", "next-international": "^1.1.4", - "next-safe-action": "^5.0.3", + "next-safe-action": "^5.1.2", "next-themes": "^0.2.1", "next-usequerystate": "^1.12.2", "react": "18.2.0", "react-dom": "18.2.0", "react-dropzone": "^14.2.3", "react-hook-form": "^7.48.2", - "recharts": "^2.9.3", + "recharts": "^2.10.1", "sharp": "^0.32.6", "zod": "^3.22.4" }, "devDependencies": { "@midday/tsconfig": "workspace:*", "@t3-oss/env-nextjs": "^0.7.1", - "@types/node": "^20.9.1", - "@types/react": "^18.2.37", - "@types/react-dom": "^18.2.15", - "typescript": "^5.2.2" + "@types/node": "^20.9.4", + "@types/react": "^18.2.38", + "@types/react-dom": "^18.2.17", + "typescript": "^5.3.2" } } \ No newline at end of file diff --git a/apps/dashboard/src/actions/export-transactions-action.ts b/apps/dashboard/src/actions/export-transactions-action.ts index 84efa67a31..a051430f5f 100644 --- a/apps/dashboard/src/actions/export-transactions-action.ts +++ b/apps/dashboard/src/actions/export-transactions-action.ts @@ -19,6 +19,6 @@ export const exportTransactionsAction = action( }, }); - console.log(event); + return event; } ); diff --git a/apps/dashboard/src/actions/schema.ts b/apps/dashboard/src/actions/schema.ts index 9506e249ae..d7a0d763bb 100644 --- a/apps/dashboard/src/actions/schema.ts +++ b/apps/dashboard/src/actions/schema.ts @@ -66,6 +66,6 @@ export const createAttachmentsSchema = z.array( export const deleteAttachmentSchema = z.string(); export const exportTransactionsSchema = z.object({ - from: z.string(), - to: z.string(), + from: z.coerce.date(), + to: z.coerce.date(), }); diff --git a/apps/dashboard/src/app/[locale]/@dashboard/(root)/transactions/page.tsx b/apps/dashboard/src/app/[locale]/@dashboard/(root)/transactions/page.tsx index d0a394fca1..03539d1478 100644 --- a/apps/dashboard/src/app/[locale]/@dashboard/(root)/transactions/page.tsx +++ b/apps/dashboard/src/app/[locale]/@dashboard/(root)/transactions/page.tsx @@ -40,7 +40,13 @@ export default async function Transactions({ fallback={} key={page} > - +
diff --git a/apps/dashboard/src/app/api/download/document/route.ts b/apps/dashboard/src/app/api/download/document/route.ts index a3eadb9962..510cbfe5cf 100644 --- a/apps/dashboard/src/app/api/download/document/route.ts +++ b/apps/dashboard/src/app/api/download/document/route.ts @@ -9,7 +9,7 @@ export async function GET(req, res) { const path = requestUrl.searchParams.get("path"); const filename = requestUrl.searchParams.get("filename"); - const { data } = await supabase.storage.from("files").download(path); + const { data } = await supabase.storage.from("vault").download(path); const responseHeaders = new Headers(res.headers); responseHeaders.set( diff --git a/apps/dashboard/src/components/attachments.tsx b/apps/dashboard/src/components/attachments.tsx index d48a6ad4ed..988a193029 100644 --- a/apps/dashboard/src/components/attachments.tsx +++ b/apps/dashboard/src/components/attachments.tsx @@ -87,7 +87,7 @@ export function Attachments({ id, data }) { const uploadedFiles = await Promise.all( acceptedFiles.map(async (acceptedFile) => { const { path } = await uploadFile({ - bucket: "files", + bucket: "vault", path: `${userData?.team_id}/transactions/${id}`, file: acceptedFile, }); @@ -99,7 +99,7 @@ export function Attachments({ id, data }) { transaction_id: id, type: acceptedFile.type, }; - }), + }) ); const { data: newFiles } = await createAttachmentsAction(uploadedFiles); @@ -120,7 +120,7 @@ export function Attachments({ id, data }) {
diff --git a/apps/dashboard/src/components/modals/export-transactions-modal.tsx b/apps/dashboard/src/components/modals/export-transactions-modal.tsx index 2b1586e105..f592a1388f 100644 --- a/apps/dashboard/src/components/modals/export-transactions-modal.tsx +++ b/apps/dashboard/src/components/modals/export-transactions-modal.tsx @@ -10,6 +10,7 @@ import { DialogHeader, DialogTitle, } from "@midday/ui/dialog"; +import { useToast } from "@midday/ui/use-toast"; import { Loader2 } from "lucide-react"; import { useAction } from "next-safe-action/hook"; import { useSearchParams } from "next/navigation"; @@ -17,9 +18,10 @@ import { useEffect } from "react"; export function ExportTransactionsModal({ isOpen, setOpen }) { const searchParams = useSearchParams(); - const { execute, status } = useAction(exportTransactionsAction); + const { execute, status, result } = useAction(exportTransactionsAction); const filter = searchParams.get("filter"); const date = filter ? JSON.parse(filter)?.date : null; + const { toast } = useToast(); useEffect(() => { if (status === "hasSucceeded" && isOpen) { @@ -27,6 +29,21 @@ export function ExportTransactionsModal({ isOpen, setOpen }) { } }, [status]); + useEffect(() => { + if (result.data) { + toast({ + duration: 6000, + title: "Exporting...", + description: "Your export is ready base on 46 transactions.", + // action: ( + // + // Yes + // + // ), + }); + } + }, [result]); + return ( diff --git a/apps/dashboard/src/components/notification-setting.tsx b/apps/dashboard/src/components/notification-setting.tsx index 7a19cc6892..3d81bdc319 100644 --- a/apps/dashboard/src/components/notification-setting.tsx +++ b/apps/dashboard/src/components/notification-setting.tsx @@ -20,7 +20,7 @@ export function NotificationSetting({ ...state, enabled: !state.enabled, }; - }, + } ); const onChange = () => { @@ -35,7 +35,7 @@ export function NotificationSetting({ }; return ( -
+
( + + )); +} + export async function NotificationSettings() { const { data: userData } = await getUser(); const { data: subscriberPreferences } = await getSubscriberPreferences({ diff --git a/apps/dashboard/src/components/notifications-settings-list.tsx b/apps/dashboard/src/components/notifications-settings-list.tsx index ce1145ed3c..a9aad2d9e3 100644 --- a/apps/dashboard/src/components/notifications-settings-list.tsx +++ b/apps/dashboard/src/components/notifications-settings-list.tsx @@ -5,9 +5,11 @@ import { CardHeader, CardTitle, } from "@midday/ui/card"; -import { Skeleton } from "@midday/ui/skeleton"; import { Suspense } from "react"; -import { NotificationSettings } from "./notification-settings"; +import { + NotificationSettings, + NotificationSettingsSkeleton, +} from "./notification-settings"; export async function NotificationsSettingsList() { return ( @@ -20,7 +22,7 @@ export async function NotificationsSettingsList() { - }> + }> diff --git a/apps/dashboard/src/components/tables/transactions/data-table.tsx b/apps/dashboard/src/components/tables/transactions/data-table.tsx index fbb6a3d90b..122d194b22 100644 --- a/apps/dashboard/src/components/tables/transactions/data-table.tsx +++ b/apps/dashboard/src/components/tables/transactions/data-table.tsx @@ -16,12 +16,14 @@ type Item = { type ItemsProps = { data: Item[]; teamId?: string; + initialTransactionId: string; }; -export function DataTable({ data, teamId }: ItemsProps) { +export function DataTable({ data, teamId, initialTransactionId }: ItemsProps) { const supabase = createClient(); const router = useRouter(); const [transactionId, setTransactionId] = useQueryState("id", { + defaultValue: initialTransactionId, shallow: false, // TODO: Fix without this (redirect after mutation) }); @@ -80,7 +82,7 @@ export function DataTable({ data, teamId }: ItemsProps) { .on( "postgres_changes", { - event: "*", + event: "INSERT", schema: "public", table: "transactions", filter: `team_id=eq.${teamId}`, diff --git a/apps/dashboard/src/components/tables/transactions/index.tsx b/apps/dashboard/src/components/tables/transactions/index.tsx index 655d232417..d17e5c028e 100644 --- a/apps/dashboard/src/components/tables/transactions/index.tsx +++ b/apps/dashboard/src/components/tables/transactions/index.tsx @@ -8,7 +8,13 @@ import { Loading } from "./loading"; const pageSize = 50; -export async function Table({ filter, page, sort, noAccounts }) { +export async function Table({ + filter, + page, + sort, + noAccounts, + initialTransactionId, +}) { const hasFilters = Object.keys(filter).length > 0; const { to, from } = getPagination(page, pageSize); const { data: userData } = await getUser(); @@ -30,7 +36,11 @@ export async function Table({ filter, page, sort, noAccounts }) { return ( <> - + {hasFilters ? (
) : ( diff --git a/apps/dashboard/src/jobs/transactions.ts b/apps/dashboard/src/jobs/transactions.ts index dd6bc77e33..dbbd3045ac 100644 --- a/apps/dashboard/src/jobs/transactions.ts +++ b/apps/dashboard/src/jobs/transactions.ts @@ -3,6 +3,7 @@ import { TransactionsEmail } from "@midday/email/emails/transactions"; import { getI18n } from "@midday/email/locales"; import { getTransactions } from "@midday/gocardless"; import { TriggerEvents, triggerBulk } from "@midday/notification"; +import { getTransactionsQuery } from "@midday/supabase/queries"; import { Database } from "@midday/supabase/src/types"; import { renderAsync } from "@react-email/components"; import { eventTrigger } from "@trigger.dev/sdk"; @@ -71,7 +72,7 @@ client.defineJob({ table: "bank_accounts", }), run: async (payload, io) => { - await io.sendEvent("Schedule Transactions", { + await io.sendEvent("Transactions Initial Sync", { id: payload.record.id, name: "transactions.initial.sync", payload: { @@ -86,7 +87,7 @@ client.defineJob({ await dynamicSchedule.register(payload.record.id, { type: "interval", options: { - seconds: 3600 * 4, // every 4h + seconds: 3600, // every 1h }, }); }, @@ -236,7 +237,7 @@ client.defineJob({ client.defineJob({ id: "transactions-initial-sync", - name: "Transactions - Initial", + name: "Transactions - Initial Sync", version: "1.0.0", trigger: eventTrigger({ name: "transactions.initial.sync", @@ -252,6 +253,14 @@ client.defineJob({ const { transactions } = await getTransactions(accountId); + // Update bank account last_accessed + await io.supabase.client + .from("bank_accounts") + .update({ + last_accessed: new Date(), + }) + .eq("id", recordId); + if (!transactions?.booked.length) { await io.logger.info("No transactions found"); } @@ -260,7 +269,7 @@ client.defineJob({ .from("transactions") .insert( transformTransactions(transactions?.booked, { - accountId: recordId, + accountId: recordId, // Bank account record id teamId: teamId, }) ) @@ -287,8 +296,8 @@ client.defineJob({ trigger: eventTrigger({ name: "transactions.export", schema: z.object({ - from: z.string().datetime(), - to: z.string().datetime(), + from: z.coerce.date(), + to: z.coerce.date(), teamId: z.string(), }), }), @@ -296,14 +305,30 @@ client.defineJob({ run: async (payload, io) => { const { from, to, teamId } = payload; - const generateExport = await io.createStatus("generate-export", { - label: "Generating memes", + const client = await io.supabase.client; + + const generateExport = await io.createStatus("generate-export-start", { + label: "Generating export", state: "loading", }); await io.logger.info("Transactions Export"); - await generateExport.update("generate-export", { + const data = await getTransactionsQuery(client, { + teamId, + from: 0, + to: 100000, + filter: { + date: { + from: from.toDateString(), + to: to.toDateString(), + }, + }, + }); + + await io.logger.info(`Transactions: ${JSON.stringify(data, null, 2)}`); + + await generateExport.update("generate-export-done", { state: "success", data: { url: "", diff --git a/apps/website/package.json b/apps/website/package.json index e296e18d71..42dd251f5e 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -23,8 +23,8 @@ }, "devDependencies": { "@midday/tsconfig": "workspace:*", - "@types/node": "^20.9.1", - "@types/react": "^18.2.37", - "@types/react-dom": "^18.2.15" + "@types/node": "^20.9.4", + "@types/react": "^18.2.38", + "@types/react-dom": "^18.2.17" } } diff --git a/apps/website/src/locales/en.ts b/apps/website/src/locales/en.ts index 8eec9db318..fb7ac83de3 100644 --- a/apps/website/src/locales/en.ts +++ b/apps/website/src/locales/en.ts @@ -8,7 +8,7 @@ export default { email: "Enter your email", open: "Open source", live: "Live profit/loss", - document: "Files", + document: "Vault", reciept: "Receipt linking", time: "Time tracking", ai: "AI-enhanced filter & search", diff --git a/bun.lockb b/bun.lockb index a89d178f61..84f7b3489e 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 7c739b77a9..0564c199b0 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,9 @@ "@biomejs/biome": "1.3.3", "@manypkg/cli": "^0.21.0", "turbo": "^1.10.16", - "typescript": "^5.2.2" + "typescript": "^5.3.2" }, "devDependencies": { - "vercel": "^32.5.5" + "vercel": "^32.5.6" } } diff --git a/packages/email/package.json b/packages/email/package.json index ce6f54ff75..d34d67031f 100644 --- a/packages/email/package.json +++ b/packages/email/package.json @@ -17,6 +17,6 @@ "react-email": "1.9.5" }, "devDependencies": { - "typescript": "^5.2.2" + "typescript": "^5.3.2" } } \ No newline at end of file diff --git a/packages/gocardless/package.json b/packages/gocardless/package.json index 6747b315ef..997ced5644 100644 --- a/packages/gocardless/package.json +++ b/packages/gocardless/package.json @@ -14,6 +14,6 @@ "@midday/kv": "workspace:*" }, "devDependencies": { - "typescript": "^5.2.2" + "typescript": "^5.3.2" } } \ No newline at end of file diff --git a/packages/location/package.json b/packages/location/package.json index 92e1f93b71..5e26c9170d 100644 --- a/packages/location/package.json +++ b/packages/location/package.json @@ -11,6 +11,6 @@ "check:types": "tsc --noEmit" }, "devDependencies": { - "typescript": "^5.2.2" + "typescript": "^5.3.2" } } \ No newline at end of file diff --git a/packages/notification/package.json b/packages/notification/package.json index 10391a7004..fceb0f4116 100644 --- a/packages/notification/package.json +++ b/packages/notification/package.json @@ -13,6 +13,6 @@ "@novu/node": "^0.21.0" }, "devDependencies": { - "typescript": "^5.2.2" + "typescript": "^5.3.2" } } \ No newline at end of file diff --git a/packages/supabase/package.json b/packages/supabase/package.json index 63a3208926..aced48ce6b 100644 --- a/packages/supabase/package.json +++ b/packages/supabase/package.json @@ -12,11 +12,11 @@ }, "dependencies": { "@supabase/ssr": "^0.0.10", - "@supabase/supabase-js": "^2.38.4", - "supabase": "^1.112.0" + "@supabase/supabase-js": "^2.38.5", + "supabase": "^1.113.2" }, "devDependencies": { - "typescript": "^5.2.2" + "typescript": "^5.3.2" }, "exports": { "./server": "./src/client/server.ts", diff --git a/packages/supabase/src/mutations/index.ts b/packages/supabase/src/mutations/index.ts index e1782dae21..1129f71201 100644 --- a/packages/supabase/src/mutations/index.ts +++ b/packages/supabase/src/mutations/index.ts @@ -182,7 +182,7 @@ export async function deleteAttachment(supabase: Client, id: string) { .single(); remove(supabase, { - bucket: "files", + bucket: "vault", path: `${data.team_id}/transactions/${data.transaction_id}/${data.name}`, }); diff --git a/packages/supabase/src/queries/cached-queries.ts b/packages/supabase/src/queries/cached-queries.ts index 10c706b2ef..18f6acf96c 100644 --- a/packages/supabase/src/queries/cached-queries.ts +++ b/packages/supabase/src/queries/cached-queries.ts @@ -149,7 +149,6 @@ export const getMetrics = async (params) => { ["metrics", teamId], { tags: [`metrics_${teamId}`], - revalidate: 10, } )(params); }; diff --git a/packages/supabase/src/queries/index.ts b/packages/supabase/src/queries/index.ts index 89ef2fa01c..1c658b00e4 100644 --- a/packages/supabase/src/queries/index.ts +++ b/packages/supabase/src/queries/index.ts @@ -180,8 +180,8 @@ export async function getSpendingQuery( type GetTransactionsParams = { teamId: string; - from: number; to: number; + from: number; sort: { column: string; value: "asc" | "desc"; @@ -218,7 +218,6 @@ export async function getTransactionsQuery( .select( ` *, - currency, assigned:assigned_id(*), attachments(id,size,name) `, diff --git a/packages/ui/package.json b/packages/ui/package.json index 0a82d40186..37e0e3e844 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "autoprefixer": "^10.4.16", - "typescript": "^5.2.2" + "typescript": "^5.3.2" }, "exports": { "./calendar": "./src/components/calendar.tsx", diff --git a/turbo.json b/turbo.json index 5cec5d844e..aa204a991b 100644 --- a/turbo.json +++ b/turbo.json @@ -38,8 +38,6 @@ } }, "globalEnv": [ - "POSTGRES_URL", - "NEXTAUTH_SECRET", - "NEXTAUTH_URL" + "POSTGRES_URL" ] }