From 7a5e166d31d96de227b2300a1c068ba35c0a174d Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 24 Jun 2025 15:21:13 -0400 Subject: [PATCH 01/16] feat: add dub referral tab and embed --- apps/app/package.json | 2 + .../referrals/components/DubReferral.tsx | 79 ++++++ .../src/app/(app)/[orgId]/referrals/page.tsx | 5 + apps/app/src/app/api/dub/embed-token/route.ts | 43 +++ apps/app/src/components/main-menu.tsx | 9 + apps/app/src/env.mjs | 4 + bun.lock | 74 +++++- yarn.lock | 249 ++++++++++++++---- 8 files changed, 409 insertions(+), 56 deletions(-) create mode 100644 apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx create mode 100644 apps/app/src/app/(app)/[orgId]/referrals/page.tsx create mode 100644 apps/app/src/app/api/dub/embed-token/route.ts diff --git a/apps/app/package.json b/apps/app/package.json index 5a3231ea77..5bbc9ac49d 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -19,6 +19,7 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@dub/embed-react": "^0.0.14", "@hookform/resolvers": "^5.1.1", "@mendable/firecrawl-js": "^1.24.0", "@nangohq/frontend": "^0.53.2", @@ -46,6 +47,7 @@ "axios": "^1.9.0", "better-auth": "^1.2.8", "d3": "^7.9.0", + "dub": "^0.63.5", "framer-motion": "^12.18.1", "geist": "^1.3.1", "motion": "^12.9.2", diff --git a/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx b/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx new file mode 100644 index 0000000000..17efbe348c --- /dev/null +++ b/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx @@ -0,0 +1,79 @@ +'use client'; + +import { DubEmbed } from '@dub/embed-react'; +import { useEffect, useState } from 'react'; + +export const DubReferral = () => { + const [publicToken, setPublicToken] = useState(''); + const [error, setError] = useState(null); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const fetchPublicToken = async () => { + try { + setIsLoading(true); + setError(null); + + const response = await fetch('/api/dub/embed-token'); + + if (!response.ok) { + throw new Error(`Failed to fetch token: ${response.status} ${response.statusText}`); + } + + const data = await response.json(); + + if (!data.publicToken) { + throw new Error('No public token received from server'); + } + + setPublicToken(data.publicToken); + } catch (err) { + console.error('Error fetching public token:', err); + setError(err instanceof Error ? err.message : 'An unexpected error occurred'); + } finally { + setIsLoading(false); + } + }; + + fetchPublicToken(); + }, []); + + if (isLoading) { + return
Loading...
; + } + + if (error) { + return ( +
+
+

Oops, something went wrong

+

{error}

+

+ Please refresh the page and try again. If the problem persists,{' '} + + contact us + + . +

+
+
+ ); + } + + if (!publicToken) { + return ( +
+

+ No token available. Please try refreshing the page. +

+
+ ); + } + + return ; +}; diff --git a/apps/app/src/app/(app)/[orgId]/referrals/page.tsx b/apps/app/src/app/(app)/[orgId]/referrals/page.tsx new file mode 100644 index 0000000000..65055c2428 --- /dev/null +++ b/apps/app/src/app/(app)/[orgId]/referrals/page.tsx @@ -0,0 +1,5 @@ +import { DubReferral } from './components/DubReferral'; + +export default function ReferralsPage() { + return ; +} diff --git a/apps/app/src/app/api/dub/embed-token/route.ts b/apps/app/src/app/api/dub/embed-token/route.ts new file mode 100644 index 0000000000..c039131c42 --- /dev/null +++ b/apps/app/src/app/api/dub/embed-token/route.ts @@ -0,0 +1,43 @@ +import { env } from '@/env.mjs'; +import { auth } from '@/utils/auth'; +import { Dub } from 'dub'; +import { NextResponse } from 'next/server'; + +const dub = new Dub({ + token: env.DUB_API_KEY, +}); + +export async function GET(request: Request) { + const session = await auth.api.getSession({ + headers: request.headers, + }); + const user = session?.user; + + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const programId = env.DUB_PROGRAM_ID; + + if (!programId) { + return NextResponse.json({ error: 'Program ID is not set' }, { status: 500 }); + } + + try { + const { publicToken } = await dub.embedTokens.referrals({ + programId, // program ID from your Dub dashboard (in the URL) + tenantId: user.id, // the user's ID within your application + partner: { + name: user.name, // the user's name + email: user.email, // the user's email + image: user.image, // the user's image/avatar + tenantId: user.id, // the user's ID within your application + }, + }); + + return NextResponse.json({ publicToken }); + } catch (error) { + console.error('Error fetching embed token:', error); + return NextResponse.json({ error: 'Failed to fetch embed token' }, { status: 500 }); + } +} diff --git a/apps/app/src/components/main-menu.tsx b/apps/app/src/components/main-menu.tsx index 784f0a7941..89ca2cea34 100644 --- a/apps/app/src/components/main-menu.tsx +++ b/apps/app/src/components/main-menu.tsx @@ -9,6 +9,7 @@ import { Blocks, FlaskConical, Gauge, + Gift, ListCheck, NotebookText, ShieldEllipsis, @@ -126,6 +127,14 @@ export function MainMenu({ organizationId, isCollapsed = false, onItemClick }: P variant: 'secondary', }, }, + { + id: 'referrals', + path: '/:organizationId/referrals', + name: 'Referrals', + disabled: false, + icon: Gift, + protected: false, + }, { id: 'settings', path: '/:organizationId/settings', diff --git a/apps/app/src/env.mjs b/apps/app/src/env.mjs index cbd8ab54e3..dafc2f360a 100644 --- a/apps/app/src/env.mjs +++ b/apps/app/src/env.mjs @@ -36,6 +36,8 @@ export const env = createEnv({ ZAPIER_HUBSPOT_WEBHOOK_URL: z.string().optional(), FLEET_URL: z.string().optional(), FLEET_TOKEN: z.string().optional(), + DUB_API_KEY: z.string().optional(), + DUB_PROGRAM_ID: z.string().optional(), }, client: { @@ -87,6 +89,8 @@ export const env = createEnv({ process.env.NEXT_PUBLIC_STRIPE_SUBSCRIPTION_MANAGED_MONTHLY_PRICE_ID, NEXT_PUBLIC_STRIPE_SUBSCRIPTION_MANAGED_YEARLY_PRICE_ID: process.env.NEXT_PUBLIC_STRIPE_SUBSCRIPTION_MANAGED_YEARLY_PRICE_ID, + DUB_API_KEY: process.env.DUB_API_KEY, + DUB_PROGRAM_ID: process.env.DUB_PROGRAM_ID, }, skipValidation: !!process.env.CI || !!process.env.SKIP_ENV_VALIDATION, diff --git a/bun.lock b/bun.lock index f7a36012d5..22656ccbe0 100644 --- a/bun.lock +++ b/bun.lock @@ -76,6 +76,7 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@dub/embed-react": "^0.0.14", "@hookform/resolvers": "^5.1.1", "@mendable/firecrawl-js": "^1.24.0", "@nangohq/frontend": "^0.53.2", @@ -103,6 +104,7 @@ "axios": "^1.9.0", "better-auth": "^1.2.8", "d3": "^7.9.0", + "dub": "^0.63.5", "framer-motion": "^12.18.1", "geist": "^1.3.1", "motion": "^12.9.2", @@ -368,10 +370,10 @@ "@tiptap/extension-image": "2.14.0", "@tiptap/extension-link": "2.14.0", "@tiptap/extension-placeholder": "2.14.0", - "@tiptap/extension-table": "2.14.0", - "@tiptap/extension-table-cell": "2.14.0", - "@tiptap/extension-table-header": "2.14.0", - "@tiptap/extension-table-row": "2.14.0", + "@tiptap/extension-table": "^2.22.3", + "@tiptap/extension-table-cell": "^2.22.3", + "@tiptap/extension-table-header": "^2.22.3", + "@tiptap/extension-table-row": "^2.22.3", "@tiptap/extension-task-item": "2.14.0", "@tiptap/extension-task-list": "2.14.0", "@tiptap/extension-text-align": "2.14.0", @@ -673,6 +675,10 @@ "@dnd-kit/utilities": ["@dnd-kit/utilities@3.2.2", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg=="], + "@dub/embed-core": ["@dub/embed-core@0.0.14", "", { "dependencies": { "@floating-ui/dom": "^1.6.12" } }, "sha512-2oD8NOlpysa4XgF70+gvJbHyysm+QboujTmD93tvQ2Dt+br7lUV+3cx51+Ho0WTZ06+DnFYQJ5fG/dtXSmyHrg=="], + + "@dub/embed-react": ["@dub/embed-react@0.0.14", "", { "dependencies": { "@dub/embed-core": "^0.0.14", "class-variance-authority": "^0.7.0", "vite": "5.2.9" }, "peerDependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" } }, "sha512-qJg08k8GE5ElduCpWxKHlpPsDQYfWu4n+n1p+bChdTNxX2BvFnyqQl3LTxBYKqJ7RwXxSSW7GARpFgajvXVJCA=="], + "@effect/platform": ["@effect/platform@0.81.0", "", { "dependencies": { "find-my-way-ts": "^0.1.5", "msgpackr": "^1.11.2", "multipasta": "^0.2.5" }, "peerDependencies": { "effect": "^3.14.21" } }, "sha512-RZ0pqpSUET0Ab3CBjOhJ12C2/vWLQsy+SLJbGNxjcOm9xZAwQowggWCs4S3ZXhdnNTR5WJHH02WlAWHJDaMKhA=="], "@electric-sql/client": ["@electric-sql/client@1.0.0-beta.1", "", { "optionalDependencies": { "@rollup/rollup-darwin-arm64": "^4.18.1" } }, "sha512-Ei9jN3pDoGzc+a/bGqnB5ajb52IvSv7/n2btuyzUlcOHIR2kM9fqtYTJXPwZYKLkGZlHWlpHgWyRtrinkP2nHg=="], @@ -2361,6 +2367,8 @@ "draco3d": ["draco3d@1.5.7", "", {}, "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ=="], + "dub": ["dub@0.63.5", "", { "peerDependencies": { "@modelcontextprotocol/sdk": ">=1.5.0 <1.10.0", "zod": ">= 3" }, "optionalPeers": ["@modelcontextprotocol/sdk"], "bin": { "mcp": "bin/mcp-server.js" } }, "sha512-p9ygOnYpZ89jV/rXJrG4yTa9E0VE8itwV/EmnydO27hFhRa9Hj3m6Ue0PLEIykYEGaROPjGIYKjXPOysShEhKQ=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "duplexer2": ["duplexer2@0.1.4", "", { "dependencies": { "readable-stream": "^2.0.2" } }, "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA=="], @@ -4171,6 +4179,8 @@ "victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="], + "vite": ["vite@5.2.9", "", { "dependencies": { "esbuild": "^0.20.1", "postcss": "^8.4.38", "rollup": "^4.13.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-uOQWfuZBlc6Y3W/DTuQ1Sr+oIXWvqljLvS881SVmAj00d5RdgShLcuXWxseWPd4HXwiYBFW/vXHfKFeqj9uQnw=="], + "w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="], "web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], @@ -4299,14 +4309,6 @@ "@commitlint/types/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], - "@comp/ui/@tiptap/extension-table": ["@tiptap/extension-table@2.14.0", "", { "peerDependencies": { "@tiptap/core": "^2.7.0", "@tiptap/pm": "^2.7.0" } }, "sha512-X/wH3XKxi5+G7cB+lHt3fPMWIJ30IBkzrJZYapJ8d4p2JxMNIU1Nyu+8K6204d0hF6SVWY8hvb/Jq/WgHtoCFA=="], - - "@comp/ui/@tiptap/extension-table-cell": ["@tiptap/extension-table-cell@2.14.0", "", { "peerDependencies": { "@tiptap/core": "^2.7.0" } }, "sha512-DkSNAAkMI/ymPgO8y8Gv0MDVcbd2gk7xrSyicIDNoDFFXp15VasInGW8mvyM+CgvlurGB2N+PkYncPtfb4XNuQ=="], - - "@comp/ui/@tiptap/extension-table-header": ["@tiptap/extension-table-header@2.14.0", "", { "peerDependencies": { "@tiptap/core": "^2.7.0" } }, "sha512-wX6/+t0iCo3KrqK2OjK0vbFeL76Pq+VpobGt+oM8lcxsENnsa6a0s3wdd1QEVLVPlj+WMFQggAG80Rf17+iDxA=="], - - "@comp/ui/@tiptap/extension-table-row": ["@tiptap/extension-table-row@2.14.0", "", { "peerDependencies": { "@tiptap/core": "^2.7.0" } }, "sha512-a1GvCIju9xETIQu664lVQNftHqpPdRmwYp+1QzY82v3zHClso+tTLPeBSlbDdUscSmv3yZXgGML20IiOoR2l2Q=="], - "@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], "@discordjs/ws/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], @@ -5089,6 +5091,8 @@ "verror/core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="], + "vite/esbuild": ["esbuild@0.20.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.20.2", "@esbuild/android-arm": "0.20.2", "@esbuild/android-arm64": "0.20.2", "@esbuild/android-x64": "0.20.2", "@esbuild/darwin-arm64": "0.20.2", "@esbuild/darwin-x64": "0.20.2", "@esbuild/freebsd-arm64": "0.20.2", "@esbuild/freebsd-x64": "0.20.2", "@esbuild/linux-arm": "0.20.2", "@esbuild/linux-arm64": "0.20.2", "@esbuild/linux-ia32": "0.20.2", "@esbuild/linux-loong64": "0.20.2", "@esbuild/linux-mips64el": "0.20.2", "@esbuild/linux-ppc64": "0.20.2", "@esbuild/linux-riscv64": "0.20.2", "@esbuild/linux-s390x": "0.20.2", "@esbuild/linux-x64": "0.20.2", "@esbuild/netbsd-x64": "0.20.2", "@esbuild/openbsd-x64": "0.20.2", "@esbuild/sunos-x64": "0.20.2", "@esbuild/win32-arm64": "0.20.2", "@esbuild/win32-ia32": "0.20.2", "@esbuild/win32-x64": "0.20.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g=="], + "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -5497,6 +5501,52 @@ "type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.20.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g=="], + + "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.20.2", "", { "os": "android", "cpu": "arm" }, "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w=="], + + "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.20.2", "", { "os": "android", "cpu": "arm64" }, "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg=="], + + "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.20.2", "", { "os": "android", "cpu": "x64" }, "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg=="], + + "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.20.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA=="], + + "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.20.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA=="], + + "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.20.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw=="], + + "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.20.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw=="], + + "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.20.2", "", { "os": "linux", "cpu": "arm" }, "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg=="], + + "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.20.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A=="], + + "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.20.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig=="], + + "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.20.2", "", { "os": "linux", "cpu": "none" }, "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ=="], + + "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.20.2", "", { "os": "linux", "cpu": "none" }, "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA=="], + + "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.20.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg=="], + + "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.20.2", "", { "os": "linux", "cpu": "none" }, "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg=="], + + "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.20.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ=="], + + "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.20.2", "", { "os": "linux", "cpu": "x64" }, "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw=="], + + "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.20.2", "", { "os": "none", "cpu": "x64" }, "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ=="], + + "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.20.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ=="], + + "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.20.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w=="], + + "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.20.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ=="], + + "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.20.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ=="], + + "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.20.2", "", { "os": "win32", "cpu": "x64" }, "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ=="], + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], diff --git a/yarn.lock b/yarn.lock index 06a7e2d7cd..c1099ce1c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1191,14 +1191,14 @@ "@types/conventional-commits-parser" "^5.0.0" chalk "^5.3.0" -"@comp/analytics@packages/analytics": +"@comp/analytics@^workspace:packages/analytics": version "workspace:packages/analytics" resolved "workspace:packages/analytics" dependencies: posthog-js "^1.236.6" posthog-node "^4.14.0" -"@comp/app@apps/app", "@comp/app@workspace:*": +"@comp/app@^workspace:apps/app", "@comp/app@workspace:*": version "workspace:apps/app" resolved "workspace:apps/app" devDependencies: @@ -1226,12 +1226,15 @@ "@browserbasehq/sdk" "^2.5.0" "@calcom/atoms" "^1.0.102-framer" "@calcom/embed-react" "^1.5.3" + dependencies: "@comp/db" "workspace:*" + dependencies: "@date-fns/tz" "^1.2.0" "@dnd-kit/core" "^6.3.1" "@dnd-kit/modifiers" "^9.0.0" "@dnd-kit/sortable" "^10.0.0" "@dnd-kit/utilities" "^3.2.2" + "@dub/embed-react" "^0.0.14" "@hookform/resolvers" "^5.1.1" "@mendable/firecrawl-js" "^1.24.0" "@nangohq/frontend" "^0.53.2" @@ -1259,6 +1262,7 @@ axios "^1.9.0" better-auth "^1.2.8" d3 "^7.9.0" + dub "^0.63.5" framer-motion "^12.18.1" geist "^1.3.1" motion "^12.9.2" @@ -1290,18 +1294,19 @@ xml2js "^0.6.2" zustand "^5.0.3" -"@comp/db@packages/db", "@comp/db@workspace:*": +"@comp/db@^workspace:packages/db", "@comp/db@workspace:*": version "workspace:packages/db" resolved "workspace:packages/db" devDependencies: "@comp/tsconfig" "workspace:*" + devDependencies: prisma "^6.9.0" ts-node "^10.9.2" typescript "^5.8.3" dependencies: "@prisma/client" "6.9.0" -"@comp/email@packages/email": +"@comp/email@^workspace:packages/email": version "workspace:packages/email" resolved "workspace:packages/email" devDependencies: @@ -1321,7 +1326,7 @@ react-email "^4.0.15" responsive-react-email "^0.0.5" -"@comp/framework-editor@apps/framework-editor": +"@comp/framework-editor@^workspace:apps/framework-editor": version "workspace:apps/framework-editor" resolved "workspace:apps/framework-editor" devDependencies: @@ -1351,7 +1356,7 @@ tippy.js "^6.3.7" zod "3.25.67" -"@comp/integrations@packages/integrations": +"@comp/integrations@^workspace:packages/integrations": version "workspace:packages/integrations" resolved "workspace:packages/integrations" devDependencies: @@ -1374,14 +1379,14 @@ stoppable "^1.1.0" zod "3.25.67" -"@comp/kv@packages/kv": +"@comp/kv@^workspace:packages/kv": version "workspace:packages/kv" resolved "workspace:packages/kv" dependencies: "@upstash/redis" "^1.34.2" server-only "0.0.1" -"@comp/portal@apps/portal": +"@comp/portal@^workspace:apps/portal": version "workspace:apps/portal" resolved "workspace:apps/portal" devDependencies: @@ -1412,7 +1417,7 @@ next "15.4.0-canary.85" react-email "^4.0.15" -"@comp/trust@apps/trust": +"@comp/trust@^workspace:apps/trust": version "workspace:apps/trust" resolved "workspace:apps/trust" devDependencies: @@ -1433,11 +1438,11 @@ lucide-react "^0.518.0" next "15.4.0-canary.85" -"@comp/tsconfig@packages/tsconfig", "@comp/tsconfig@workspace:*": +"@comp/tsconfig@^workspace:packages/tsconfig", "@comp/tsconfig@workspace:*": version "workspace:packages/tsconfig" resolved "workspace:packages/tsconfig" -"@comp/ui@packages/ui", "@comp/ui@workspace:*": +"@comp/ui@^workspace:packages/ui", "@comp/ui@workspace:*": version "workspace:packages/ui" resolved "workspace:packages/ui" devDependencies: @@ -1485,10 +1490,10 @@ "@tiptap/extension-image" "2.14.0" "@tiptap/extension-link" "2.14.0" "@tiptap/extension-placeholder" "2.14.0" - "@tiptap/extension-table" "2.14.0" - "@tiptap/extension-table-cell" "2.14.0" - "@tiptap/extension-table-header" "2.14.0" - "@tiptap/extension-table-row" "2.14.0" + "@tiptap/extension-table" "^2.22.3" + "@tiptap/extension-table-cell" "^2.22.3" + "@tiptap/extension-table-header" "^2.22.3" + "@tiptap/extension-table-row" "^2.22.3" "@tiptap/extension-task-item" "2.14.0" "@tiptap/extension-task-list" "2.14.0" "@tiptap/extension-text-align" "2.14.0" @@ -1520,7 +1525,7 @@ use-debounce "^10.0.4" vaul "^0.9.6" -"@comp/utils@packages/utils", "@comp/utils@workspace:*": +"@comp/utils@^workspace:packages/utils", "@comp/utils@workspace:*": version "workspace:packages/utils" resolved "workspace:packages/utils" devDependencies: @@ -1647,6 +1652,22 @@ dependencies: tslib "^2.0.0" +"@dub/embed-core@^0.0.14": + version "0.0.14" + resolved "https://registry.npmjs.org/@dub/embed-core/-/embed-core-0.0.14.tgz" + integrity sha512-2oD8NOlpysa4XgF70+gvJbHyysm+QboujTmD93tvQ2Dt+br7lUV+3cx51+Ho0WTZ06+DnFYQJ5fG/dtXSmyHrg== + dependencies: + "@floating-ui/dom" "^1.6.12" + +"@dub/embed-react@^0.0.14": + version "0.0.14" + resolved "https://registry.npmjs.org/@dub/embed-react/-/embed-react-0.0.14.tgz" + integrity sha512-qJg08k8GE5ElduCpWxKHlpPsDQYfWu4n+n1p+bChdTNxX2BvFnyqQl3LTxBYKqJ7RwXxSSW7GARpFgajvXVJCA== + dependencies: + "@dub/embed-core" "^0.0.14" + class-variance-authority "^0.7.0" + vite "5.2.9" + "@effect/platform@0.81.0": version "0.81.0" resolved "https://registry.npmjs.org/@effect/platform/-/platform-0.81.0.tgz" @@ -1773,86 +1794,171 @@ resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz" integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== +"@esbuild/aix-ppc64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz" + integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g== + "@esbuild/aix-ppc64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz" integrity sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA== +"@esbuild/android-arm@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz" + integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w== + "@esbuild/android-arm@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz" integrity sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA== +"@esbuild/android-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz" + integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg== + "@esbuild/android-arm64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz" integrity sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg== +"@esbuild/android-x64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz" + integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg== + "@esbuild/android-x64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz" integrity sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw== +"@esbuild/darwin-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz" + integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA== + "@esbuild/darwin-arm64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz" integrity sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ== +"@esbuild/darwin-x64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz" + integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA== + "@esbuild/darwin-x64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz" integrity sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ== +"@esbuild/freebsd-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz" + integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw== + "@esbuild/freebsd-arm64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz" integrity sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw== +"@esbuild/freebsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz" + integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw== + "@esbuild/freebsd-x64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz" integrity sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw== +"@esbuild/linux-arm@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz" + integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg== + "@esbuild/linux-arm@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz" integrity sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw== +"@esbuild/linux-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz" + integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A== + "@esbuild/linux-arm64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz" integrity sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg== +"@esbuild/linux-ia32@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz" + integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig== + "@esbuild/linux-ia32@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz" integrity sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA== +"@esbuild/linux-loong64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz" + integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ== + "@esbuild/linux-loong64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz" integrity sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg== +"@esbuild/linux-mips64el@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz" + integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA== + "@esbuild/linux-mips64el@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz" integrity sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg== +"@esbuild/linux-ppc64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz" + integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg== + "@esbuild/linux-ppc64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz" integrity sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ== +"@esbuild/linux-riscv64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz" + integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg== + "@esbuild/linux-riscv64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz" integrity sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA== +"@esbuild/linux-s390x@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz" + integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ== + "@esbuild/linux-s390x@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz" integrity sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ== +"@esbuild/linux-x64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz" + integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw== + "@esbuild/linux-x64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz" @@ -1863,6 +1969,11 @@ resolved "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz" integrity sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw== +"@esbuild/netbsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz" + integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ== + "@esbuild/netbsd-x64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz" @@ -1873,26 +1984,51 @@ resolved "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz" integrity sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw== +"@esbuild/openbsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz" + integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ== + "@esbuild/openbsd-x64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz" integrity sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg== +"@esbuild/sunos-x64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz" + integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w== + "@esbuild/sunos-x64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz" integrity sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA== +"@esbuild/win32-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz" + integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ== + "@esbuild/win32-arm64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz" integrity sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw== +"@esbuild/win32-ia32@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz" + integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ== + "@esbuild/win32-ia32@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz" integrity sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ== +"@esbuild/win32-x64@0.20.2": + version "0.20.2" + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz" + integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ== + "@esbuild/win32-x64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz" @@ -1978,7 +2114,7 @@ dependencies: "@floating-ui/utils" "^0.2.9" -"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.0.1": +"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.0.1", "@floating-ui/dom@^1.6.12": version "1.7.1" resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.1.tgz" integrity sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ== @@ -5470,41 +5606,21 @@ resolved "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.14.0.tgz" integrity sha512-rD5d/IL3XPfBOrHRHxt+b+0X1jbIbWONGiad/3sX0ZYQD3PandtCWboH40r/J5tFksebuY12dVYyYQKgLpDBOQ== -"@tiptap/extension-table@2.14.0": - version "2.14.0" - resolved "https://registry.npmjs.org/@tiptap/extension-table/-/extension-table-2.14.0.tgz" - integrity sha512-X/wH3XKxi5+G7cB+lHt3fPMWIJ30IBkzrJZYapJ8d4p2JxMNIU1Nyu+8K6204d0hF6SVWY8hvb/Jq/WgHtoCFA== - "@tiptap/extension-table@^2.22.3": version "2.22.3" resolved "https://registry.npmjs.org/@tiptap/extension-table/-/extension-table-2.22.3.tgz" integrity sha512-lYTuDo/3lJsC6g85b5OCfrKi8yID82PnZlngZo4quVHusE/YuXOwXYD4qt3xEOoqdgFoPQl0b7Ck9C5Qyb8AUg== -"@tiptap/extension-table-cell@2.14.0": - version "2.14.0" - resolved "https://registry.npmjs.org/@tiptap/extension-table-cell/-/extension-table-cell-2.14.0.tgz" - integrity sha512-DkSNAAkMI/ymPgO8y8Gv0MDVcbd2gk7xrSyicIDNoDFFXp15VasInGW8mvyM+CgvlurGB2N+PkYncPtfb4XNuQ== - "@tiptap/extension-table-cell@^2.22.3": version "2.22.3" resolved "https://registry.npmjs.org/@tiptap/extension-table-cell/-/extension-table-cell-2.22.3.tgz" integrity sha512-Yj6/bd4QpKoQpNTi/eNnWpT+VMfTBB7SfCPjlMvTK1MFVr60fmbUjJHrjt2WAfTW2JmkQlLsP8UXjR+Bda+uTA== -"@tiptap/extension-table-header@2.14.0": - version "2.14.0" - resolved "https://registry.npmjs.org/@tiptap/extension-table-header/-/extension-table-header-2.14.0.tgz" - integrity sha512-wX6/+t0iCo3KrqK2OjK0vbFeL76Pq+VpobGt+oM8lcxsENnsa6a0s3wdd1QEVLVPlj+WMFQggAG80Rf17+iDxA== - "@tiptap/extension-table-header@^2.22.3": version "2.22.3" resolved "https://registry.npmjs.org/@tiptap/extension-table-header/-/extension-table-header-2.22.3.tgz" integrity sha512-bLq/lufV95fp9gXMjOKMuuhpAa2+t0vi8dz4Zxwnrr1dsvkk4TyiKWRyuI3OV+TCNzZ3hZqOlEStS+Ie6lB/Lg== -"@tiptap/extension-table-row@2.14.0": - version "2.14.0" - resolved "https://registry.npmjs.org/@tiptap/extension-table-row/-/extension-table-row-2.14.0.tgz" - integrity sha512-a1GvCIju9xETIQu664lVQNftHqpPdRmwYp+1QzY82v3zHClso+tTLPeBSlbDdUscSmv3yZXgGML20IiOoR2l2Q== - "@tiptap/extension-table-row@^2.22.3": version "2.22.3" resolved "https://registry.npmjs.org/@tiptap/extension-table-row/-/extension-table-row-2.22.3.tgz" @@ -6139,7 +6255,7 @@ dependencies: undici-types "~5.26.4" -"@types/node@*", "@types/node@>= 12", "@types/node@>=10.0.0", "@types/node@>=12", "@types/node@>=13.7.0", "@types/node@>=18.0.0", "@types/node@^24.0.3": +"@types/node@*", "@types/node@>= 12", "@types/node@>=10.0.0", "@types/node@>=12", "@types/node@>=13.7.0", "@types/node@>=18.0.0", "@types/node@^18.0.0 || >=20.0.0", "@types/node@^24.0.3": version "24.0.3" resolved "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz" integrity sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg== @@ -8634,6 +8750,11 @@ draco3d@^1.4.1: resolved "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz" integrity sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ== +dub@^0.63.5: + version "0.63.5" + resolved "https://registry.npmjs.org/dub/-/dub-0.63.5.tgz" + integrity sha512-p9ygOnYpZ89jV/rXJrG4yTa9E0VE8itwV/EmnydO27hFhRa9Hj3m6Ue0PLEIykYEGaROPjGIYKjXPOysShEhKQ== + dunder-proto@^1.0.0, dunder-proto@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" @@ -8984,6 +9105,35 @@ es-to-primitive@^1.3.0: is-date-object "^1.0.5" is-symbol "^1.0.4" +esbuild@^0.20.1: + version "0.20.2" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz" + integrity sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g== + optionalDependencies: + "@esbuild/aix-ppc64" "0.20.2" + "@esbuild/android-arm" "0.20.2" + "@esbuild/android-arm64" "0.20.2" + "@esbuild/android-x64" "0.20.2" + "@esbuild/darwin-arm64" "0.20.2" + "@esbuild/darwin-x64" "0.20.2" + "@esbuild/freebsd-arm64" "0.20.2" + "@esbuild/freebsd-x64" "0.20.2" + "@esbuild/linux-arm" "0.20.2" + "@esbuild/linux-arm64" "0.20.2" + "@esbuild/linux-ia32" "0.20.2" + "@esbuild/linux-loong64" "0.20.2" + "@esbuild/linux-mips64el" "0.20.2" + "@esbuild/linux-ppc64" "0.20.2" + "@esbuild/linux-riscv64" "0.20.2" + "@esbuild/linux-s390x" "0.20.2" + "@esbuild/linux-x64" "0.20.2" + "@esbuild/netbsd-x64" "0.20.2" + "@esbuild/openbsd-x64" "0.20.2" + "@esbuild/sunos-x64" "0.20.2" + "@esbuild/win32-arm64" "0.20.2" + "@esbuild/win32-ia32" "0.20.2" + "@esbuild/win32-x64" "0.20.2" + esbuild@>=0.18, esbuild@^0.25.0: version "0.25.5" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz" @@ -9839,7 +9989,7 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: +fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -11431,7 +11581,7 @@ lie@^3.0.2, lie@~3.3.0: dependencies: immediate "~3.0.5" -lightningcss@1.30.1: +lightningcss@1.30.1, lightningcss@^1.21.0: version "1.30.1" resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz" integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== @@ -13734,7 +13884,7 @@ postcss@8.4.31: picocolors "^1.0.0" source-map-js "^1.0.2" -postcss@>=8.0.9, postcss@^8.0.0, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.4.12, postcss@^8.4.21, postcss@^8.4.41, postcss@^8.4.47, postcss@^8.5.4: +postcss@>=8.0.9, postcss@^8.0.0, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.4.12, postcss@^8.4.21, postcss@^8.4.38, postcss@^8.4.41, postcss@^8.4.47, postcss@^8.5.4: version "8.5.6" resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz" integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== @@ -14313,7 +14463,7 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -react@*, react@18.x, "react@>= 16.14", "react@>= 16.8 || 18.0.0", "react@>= 16.8.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0", "react@>= 18.2.0", react@>=16, react@>=16.13, react@>=16.6.0, react@>=16.8, "react@>=16.8.0 || ^17.0.0 || ^18", react@>=16.8.1, react@>=17.0, react@>=18, "react@>=18.2.0 || ^19.0.0-0", "react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc", "react@^17.0.0 || ^18.0.0 || ^19.0.0", "react@^17.0.2 || ^18.0.0 || ^19.0.0", "react@^18 || ^19", "react@^18 || ^19 || ^19.0.0-rc", "react@^18.0 || ^19.0", "react@^18.0 || ^19.0 || ^19.0.0-rc", "react@^18.0.0 || ^19.0.0", "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react@^18.2.0 || ^19.0.0", react@^19, react@^19.1.0: +react@*, react@18.x, "react@>= 16.14", "react@>= 16.8 || 18.0.0", "react@>= 16.8.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0", "react@>= 18.2.0", react@>=16, react@>=16.13, react@>=16.6.0, react@>=16.8, "react@>=16.8.0 || ^17.0.0 || ^18", react@>=16.8.1, react@>=17.0, react@>=18, "react@>=18.2.0 || ^19.0.0-0", "react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc", "react@^17.0.0 || ^18.0.0 || ^19.0.0", "react@^17.0.2 || ^18.0.0 || ^19.0.0", "react@^18 || ^19", "react@^18 || ^19 || ^19.0.0-rc", "react@^18.0 || ^19.0", "react@^18.0 || ^19.0 || ^19.0.0-rc", "react@^18.0.0 || ^19.0.0", "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^18.2.0, "react@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react@^18.2.0 || ^19.0.0", react@^19, react@^19.1.0: version "19.1.0" resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz" integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== @@ -14352,7 +14502,7 @@ react-dnd-html5-backend@^16.0.1: dependencies: dnd-core "^16.0.1" -react-dom@*, "react-dom@>= 18.2.0", react-dom@>=16.13, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.1, react-dom@>=18.0.0, "react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^18 || ^19", "react-dom@^18 || ^19 || ^19.0.0-rc", "react-dom@^18.0.0 || ^19.0.0", "react-dom@^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom@^18.2.0 || ^19.0.0", react-dom@^19, react-dom@^19.1.0: +react-dom@*, "react-dom@>= 18.2.0", react-dom@>=16.13, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=16.8.1, react-dom@>=18.0.0, "react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^18 || ^19", "react-dom@^18 || ^19 || ^19.0.0-rc", "react-dom@^18.0.0 || ^19.0.0", "react-dom@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react-dom@^18.2.0, "react-dom@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom@^18.2.0 || ^19.0.0", react-dom@^19, react-dom@^19.1.0: version "19.1.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz" integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== @@ -14915,7 +15065,7 @@ robust-predicates@^3.0.2: resolved "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz" integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== -rollup@^4.34.8: +rollup@^4.13.0, rollup@^4.34.8: version "4.43.0" resolved "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz" integrity sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg== @@ -17022,6 +17172,17 @@ victory-vendor@^36.6.8: d3-time "^3.0.0" d3-timer "^3.0.1" +vite@5.2.9: + version "5.2.9" + resolved "https://registry.npmjs.org/vite/-/vite-5.2.9.tgz" + integrity sha512-uOQWfuZBlc6Y3W/DTuQ1Sr+oIXWvqljLvS881SVmAj00d5RdgShLcuXWxseWPd4HXwiYBFW/vXHfKFeqj9uQnw== + optionalDependencies: + fsevents "~2.3.3" + dependencies: + esbuild "^0.20.1" + postcss "^8.4.38" + rollup "^4.13.0" + w3c-keyname@^2.2.0: version "2.2.8" resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz" From 8112b5bb01778c27eaade51ed2a1f1e41af3a278 Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 24 Jun 2025 15:31:43 -0400 Subject: [PATCH 02/16] chore: add env vars to turbo json --- turbo.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/turbo.json b/turbo.json index ae6d138d76..16f3c13064 100644 --- a/turbo.json +++ b/turbo.json @@ -46,7 +46,9 @@ "FLEET_DEVICE_PATH_MAC", "FLEET_AGENT_BUCKET_NAME", "FLEET_DEVICE_PATH_WINDOWS", - "LOGO_DEV" + "LOGO_DEV", + "DUB_API_KEY", + "DUB_PROGRAM_ID" ], "inputs": ["$TURBO_DEFAULT$", ".env"], "dependsOn": ["^build", "^db:generate", "^auth:build"], From 9119dd1fddc28f6ced46c8963b8d8fc014ed597a Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 15:34:59 -0400 Subject: [PATCH 03/16] refactor: simplify onboarding process by removing localStorage dependencies - Eliminated localStorage usage for onboarding step tracking in AnimatedGradientBackgroundWrapper and OrganizationSetupForm components. - Updated useOnboardingForm hook to manage state directly instead of relying on localStorage, enhancing performance and maintainability. - Adjusted event dispatching for onboarding step changes to improve background animation handling. --- .../AnimatedGradientBackgroundWrapper.tsx | 15 --------------- .../setup/components/OrganizationSetupForm.tsx | 7 +------ .../app/(app)/setup/hooks/useOnboardingForm.ts | 9 ++++----- 3 files changed, 5 insertions(+), 26 deletions(-) diff --git a/apps/app/src/app/(app)/setup/components/AnimatedGradientBackgroundWrapper.tsx b/apps/app/src/app/(app)/setup/components/AnimatedGradientBackgroundWrapper.tsx index fe92333669..ec681815ee 100644 --- a/apps/app/src/app/(app)/setup/components/AnimatedGradientBackgroundWrapper.tsx +++ b/apps/app/src/app/(app)/setup/components/AnimatedGradientBackgroundWrapper.tsx @@ -7,21 +7,6 @@ export function AnimatedGradientBackgroundWrapper() { const [scale, setScale] = useState(0.7); useEffect(() => { - // Function to calculate scale from localStorage - const updateScale = () => { - if (typeof window !== 'undefined') { - const stepIndex = parseInt(localStorage.getItem('onboarding-step-index') || '0'); - const totalSteps = parseInt(localStorage.getItem('onboarding-total-steps') || '9'); - - // Calculate scale based on step progress (0.7 to 1.5) - const progressScale = 0.7 + (stepIndex / (totalSteps - 1)) * 0.8; - setScale(progressScale); - } - }; - - // Initial load - updateScale(); - // Listen for step changes const handleStepChange = (event: Event) => { const customEvent = event as CustomEvent; diff --git a/apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx b/apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx index 9c40a454e3..08bba2ebf1 100644 --- a/apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx +++ b/apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx @@ -62,12 +62,11 @@ export function OrganizationSetupForm({ const hasExistingOrgs = existingOrganizations.length > 0; - // Save step progress to localStorage + // Dispatch custom event for background animation when step changes useEffect(() => { if (typeof window !== 'undefined') { if (isFinalizing) { // Set to max scale when finalizing - localStorage.setItem('onboarding-progress', '1'); window.dispatchEvent( new CustomEvent('onboarding-step-change', { detail: { stepIndex: steps.length - 1, totalSteps: steps.length, progress: 1 }, @@ -75,10 +74,6 @@ export function OrganizationSetupForm({ ); } else { const progress = stepIndex / (steps.length - 1); - localStorage.setItem('onboarding-step-index', stepIndex.toString()); - localStorage.setItem('onboarding-total-steps', steps.length.toString()); - localStorage.setItem('onboarding-progress', progress.toString()); - // Dispatch custom event to notify the background wrapper window.dispatchEvent( new CustomEvent('onboarding-step-change', { diff --git a/apps/app/src/app/(app)/setup/hooks/useOnboardingForm.ts b/apps/app/src/app/(app)/setup/hooks/useOnboardingForm.ts index 1259d21c53..7189a54ff7 100644 --- a/apps/app/src/app/(app)/setup/hooks/useOnboardingForm.ts +++ b/apps/app/src/app/(app)/setup/hooks/useOnboardingForm.ts @@ -11,10 +11,9 @@ import { z } from 'zod'; import { createOrganization } from '../actions/create-organization'; import { createOrganizationMinimal } from '../actions/create-organization-minimal'; import type { OnboardingFormFields } from '../components/OnboardingStepInput'; -import { STORAGE_KEY, companyDetailsSchema, steps } from '../lib/constants'; +import { companyDetailsSchema, steps } from '../lib/constants'; import { updateSetupSession } from '../lib/setup-session'; import type { CompanyDetails } from '../lib/types'; -import { useLocalStorage } from './useLocalStorage'; interface UseOnboardingFormProps { setupId?: string; @@ -29,9 +28,8 @@ export function useOnboardingForm({ }: UseOnboardingFormProps = {}) { const router = useRouter(); - // If we have a setupId, use the initialData from KV, otherwise use localStorage - const [savedAnswers, setSavedAnswers] = useLocalStorage>( - STORAGE_KEY, + // Use state instead of localStorage - initialized from KV data if setupId exists + const [savedAnswers, setSavedAnswers] = useState>( setupId && initialData ? initialData : {}, ); @@ -108,6 +106,7 @@ export function useOnboardingForm({ // Organization created, now redirect to plans page router.push(`/upgrade/${data.organizationId}`); + // Clear answers after successful creation setSavedAnswers({}); } else { toast.error('Failed to create organization'); From 32cd92e6995a095505b264eedca18ea175f7a752 Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 15:35:46 -0400 Subject: [PATCH 04/16] chore(ci): skip husky hooks in CI for semantic-release - Added configuration to skip husky hooks during CI runs in the release workflow, streamlining the release process. --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aad4de720e..4e413c601b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,4 +43,5 @@ jobs: GITHUB_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # Uncomment if publishing to npm DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + HUSKY: 0 # Skip husky hooks in CI run: npx semantic-release From 1a45ac46c2c48bed96a3571a41cb68f738c0c728 Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 15:40:24 -0400 Subject: [PATCH 05/16] feat(pricing): add '12-month minimum term' to paid features list in PricingCards component --- apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx b/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx index 7aed20e2b8..3de85a1a31 100644 --- a/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx +++ b/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx @@ -196,6 +196,7 @@ const paidFeatures = [ 'Dedicated Success Team', '24x7x365 Support & SLA', 'Slack Channel with Comp AI', + '12-month minimum term', ]; export function PricingCards({ organizationId, priceDetails }: PricingCardsProps) { From 63a68b35ef4fac2d4db71be7260633f7f521efef Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 15:47:42 -0400 Subject: [PATCH 06/16] feat(pricing): add BookingDialog component to PricingCards for scheduling calls - Closes COMP-221, COMP-223 --- .../[orgId]/components/BookingDialog.tsx | 38 +++++++++++++++++++ .../(app)/upgrade/[orgId]/pricing-cards.tsx | 11 ++++++ 2 files changed, 49 insertions(+) create mode 100644 apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx diff --git a/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx b/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx new file mode 100644 index 0000000000..39096458a8 --- /dev/null +++ b/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx @@ -0,0 +1,38 @@ +'use client'; + +import CalendarEmbed from '@/components/calendar-embed'; +import { Button } from '@comp/ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@comp/ui/dialog'; +import { Phone } from 'lucide-react'; + +export function BookingDialog() { + return ( + + + + + + + Schedule a Call with Our Compliance Experts + + Have questions about our plans? Want to learn how we can help you achieve compliance in + 14 days? Book a 15-30 minute call with our team. + + +
+ +
+
+
+ ); +} diff --git a/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx b/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx index 3de85a1a31..906f482035 100644 --- a/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx +++ b/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx @@ -19,6 +19,7 @@ import { useAction } from 'next-safe-action/hooks'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { toast } from 'sonner'; +import { BookingDialog } from './components/BookingDialog'; interface PricingCardsProps { organizationId: string; @@ -447,6 +448,16 @@ export function PricingCards({ organizationId, priceDetails }: PricingCardsProps + + {/* Help Section */} + + +

+ Have questions? We're here to help +

+ +
+
From b39c6543e283ca9d0b9974ad17c90551bc9f9500 Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 15:48:12 -0400 Subject: [PATCH 07/16] fix(booking): remove unnecessary margin from Phone icon in BookingDialog component --- .../src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx b/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx index 39096458a8..f5cf3e2001 100644 --- a/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx +++ b/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx @@ -17,7 +17,7 @@ export function BookingDialog() { From 2b667351afd813fe193c5f1fc8a727c3aff500c1 Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 24 Jun 2025 15:49:15 -0400 Subject: [PATCH 08/16] chore: add skeleton loader to be nicer --- .../referrals/components/DubReferral.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx b/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx index 17efbe348c..506c9743da 100644 --- a/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx +++ b/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx @@ -1,12 +1,15 @@ 'use client'; +import { Skeleton } from '@comp/ui/skeleton'; import { DubEmbed } from '@dub/embed-react'; +import { useTheme } from 'next-themes'; import { useEffect, useState } from 'react'; export const DubReferral = () => { const [publicToken, setPublicToken] = useState(''); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(true); + const { theme } = useTheme(); useEffect(() => { const fetchPublicToken = async () => { @@ -39,7 +42,11 @@ export const DubReferral = () => { }, []); if (isLoading) { - return
Loading...
; + return ( +
+ +
+ ); } if (error) { @@ -75,5 +82,15 @@ export const DubReferral = () => { ); } - return ; + const dubTheme = theme === 'dark' ? 'dark' : 'light'; + + return ( + + ); }; From 161087fbab0c353814f96bccdb32fe7490aa67b6 Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 15:54:49 -0400 Subject: [PATCH 09/16] refactor(booking): enhance BookingDialog layout and improve CalendarEmbed component - Updated BookingDialog to use responsive design with improved layout and spacing. - Simplified CalendarEmbed component by removing unnecessary inline styles. --- .../[orgId]/components/BookingDialog.tsx | 24 +++++++++++-------- apps/app/src/components/calendar-embed.tsx | 7 +----- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx b/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx index f5cf3e2001..d5d13963cc 100644 --- a/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx +++ b/apps/app/src/app/(app)/upgrade/[orgId]/components/BookingDialog.tsx @@ -21,16 +21,20 @@ export function BookingDialog() { Book a Call with Our Team - - - Schedule a Call with Our Compliance Experts - - Have questions about our plans? Want to learn how we can help you achieve compliance in - 14 days? Book a 15-30 minute call with our team. - - -
- + +
+ + + Schedule a Call with Our Compliance Experts + + + Have questions about our plans? Want to learn how we can help you achieve compliance + in 14 days? Book a call with our team. + + +
+ +
diff --git a/apps/app/src/components/calendar-embed.tsx b/apps/app/src/components/calendar-embed.tsx index 98e98ee331..4337b2c596 100644 --- a/apps/app/src/components/calendar-embed.tsx +++ b/apps/app/src/components/calendar-embed.tsx @@ -12,11 +12,6 @@ export default function CalendarEmbed() { }, []); return ( - + ); } From 33f5d73d6be18cb6059d984044b53c37b7d52a6a Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 24 Jun 2025 16:10:08 -0400 Subject: [PATCH 10/16] chore: try system for theme --- .../src/app/(app)/[orgId]/referrals/components/DubReferral.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx b/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx index 506c9743da..279678c874 100644 --- a/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx +++ b/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx @@ -89,7 +89,7 @@ export const DubReferral = () => { data="referrals" token={publicToken} options={{ - theme: dubTheme, + theme: 'system', }} /> ); From e5f9851f1dfa8ed2fdb4e3813751c6cbccf5a745 Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 24 Jun 2025 16:16:25 -0400 Subject: [PATCH 11/16] chore: refactor to use server actions --- .../referrals/components/DubReferral.tsx | 75 +------------------ .../app/(app)/[orgId]/referrals/lib/dub.ts | 5 ++ .../src/app/(app)/[orgId]/referrals/page.tsx | 30 +++++++- apps/app/src/app/api/dub/embed-token/route.ts | 43 ----------- 4 files changed, 35 insertions(+), 118 deletions(-) create mode 100644 apps/app/src/app/(app)/[orgId]/referrals/lib/dub.ts delete mode 100644 apps/app/src/app/api/dub/embed-token/route.ts diff --git a/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx b/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx index 279678c874..2187feefd5 100644 --- a/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx +++ b/apps/app/src/app/(app)/[orgId]/referrals/components/DubReferral.tsx @@ -1,80 +1,11 @@ 'use client'; -import { Skeleton } from '@comp/ui/skeleton'; import { DubEmbed } from '@dub/embed-react'; -import { useTheme } from 'next-themes'; -import { useEffect, useState } from 'react'; - -export const DubReferral = () => { - const [publicToken, setPublicToken] = useState(''); - const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const { theme } = useTheme(); - - useEffect(() => { - const fetchPublicToken = async () => { - try { - setIsLoading(true); - setError(null); - - const response = await fetch('/api/dub/embed-token'); - - if (!response.ok) { - throw new Error(`Failed to fetch token: ${response.status} ${response.statusText}`); - } - - const data = await response.json(); - - if (!data.publicToken) { - throw new Error('No public token received from server'); - } - - setPublicToken(data.publicToken); - } catch (err) { - console.error('Error fetching public token:', err); - setError(err instanceof Error ? err.message : 'An unexpected error occurred'); - } finally { - setIsLoading(false); - } - }; - - fetchPublicToken(); - }, []); - - if (isLoading) { - return ( -
- -
- ); - } - - if (error) { - return ( -
-
-

Oops, something went wrong

-

{error}

-

- Please refresh the page and try again. If the problem persists,{' '} - - contact us - - . -

-
-
- ); - } +export const DubReferral = ({ publicToken }: { publicToken: string | null }) => { if (!publicToken) { return ( -
+

No token available. Please try refreshing the page.

@@ -82,8 +13,6 @@ export const DubReferral = () => { ); } - const dubTheme = theme === 'dark' ? 'dark' : 'light'; - return ( ; +export default async function ReferralsPage() { + const publicToken = await createPublicToken(); + + return ; +} + +async function createPublicToken() { + const session = await auth.api.getSession({ headers: await headers() }); + + if (!session) { + redirect('/'); + } + + const { publicToken } = await dub.embedTokens.referrals({ + programId: process.env.DUB_PROGRAM_ID as string, + partner: { + tenantId: session.user.id, + name: session.user.name || '', + email: session.user.email || '', + image: session.user.image || '', + }, + }); + + return publicToken; } diff --git a/apps/app/src/app/api/dub/embed-token/route.ts b/apps/app/src/app/api/dub/embed-token/route.ts deleted file mode 100644 index c039131c42..0000000000 --- a/apps/app/src/app/api/dub/embed-token/route.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { env } from '@/env.mjs'; -import { auth } from '@/utils/auth'; -import { Dub } from 'dub'; -import { NextResponse } from 'next/server'; - -const dub = new Dub({ - token: env.DUB_API_KEY, -}); - -export async function GET(request: Request) { - const session = await auth.api.getSession({ - headers: request.headers, - }); - const user = session?.user; - - if (!user) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } - - const programId = env.DUB_PROGRAM_ID; - - if (!programId) { - return NextResponse.json({ error: 'Program ID is not set' }, { status: 500 }); - } - - try { - const { publicToken } = await dub.embedTokens.referrals({ - programId, // program ID from your Dub dashboard (in the URL) - tenantId: user.id, // the user's ID within your application - partner: { - name: user.name, // the user's name - email: user.email, // the user's email - image: user.image, // the user's image/avatar - tenantId: user.id, // the user's ID within your application - }, - }); - - return NextResponse.json({ publicToken }); - } catch (error) { - console.error('Error fetching embed token:', error); - return NextResponse.json({ error: 'Failed to fetch embed token' }, { status: 500 }); - } -} From 6e53571186a023e30c69cb7db62fbcdb7be346f8 Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 24 Jun 2025 16:18:19 -0400 Subject: [PATCH 12/16] chore: update env vars usage --- apps/app/src/app/(app)/[orgId]/referrals/lib/dub.ts | 3 ++- apps/app/src/app/(app)/[orgId]/referrals/page.tsx | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/app/src/app/(app)/[orgId]/referrals/lib/dub.ts b/apps/app/src/app/(app)/[orgId]/referrals/lib/dub.ts index b5fd2218e3..ba7c44f4f7 100644 --- a/apps/app/src/app/(app)/[orgId]/referrals/lib/dub.ts +++ b/apps/app/src/app/(app)/[orgId]/referrals/lib/dub.ts @@ -1,5 +1,6 @@ +import { env } from '@/env.mjs'; import { Dub } from 'dub'; export const dub = new Dub({ - token: process.env.DUB_API_KEY as string, + token: env.DUB_API_KEY, }); diff --git a/apps/app/src/app/(app)/[orgId]/referrals/page.tsx b/apps/app/src/app/(app)/[orgId]/referrals/page.tsx index bcdf763e6f..310874e7a3 100644 --- a/apps/app/src/app/(app)/[orgId]/referrals/page.tsx +++ b/apps/app/src/app/(app)/[orgId]/referrals/page.tsx @@ -1,3 +1,4 @@ +import { env } from '@/env.mjs'; import { auth } from '@/utils/auth'; import { headers } from 'next/headers'; import { redirect } from 'next/navigation'; @@ -17,8 +18,12 @@ async function createPublicToken() { redirect('/'); } + if (!env.DUB_PROGRAM_ID || !env.DUB_API_KEY) { + return null; + } + const { publicToken } = await dub.embedTokens.referrals({ - programId: process.env.DUB_PROGRAM_ID as string, + programId: env.DUB_PROGRAM_ID, partner: { tenantId: session.user.id, name: session.user.name || '', From 4bd6018e3e5b18ecd4fa2aac32775f5cf04c0a6a Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 16:21:42 -0400 Subject: [PATCH 13/16] feat(checkout): add CheckoutCompleteDialog component and integrate confetti animation - Introduced CheckoutCompleteDialog to display a completion message after checkout. - Integrated canvas-confetti for celebratory animations based on selected plan type. - Updated routing logic to handle new query parameters for better user experience. - Adjusted success URLs in pricing flow to reflect new plan types. - Closes COMP-226 --- apps/app/package.json | 2 + apps/app/src/app/(app)/[orgId]/layout.tsx | 5 + .../(app)/upgrade/[orgId]/pricing-cards.tsx | 4 +- apps/app/src/app/api/stripe/success/route.ts | 8 +- .../dialogs/checkout-complete-dialog.tsx | 250 ++++++++++++++++++ bun.lock | 6 + yarn.lock | 13 + 7 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 apps/app/src/components/dialogs/checkout-complete-dialog.tsx diff --git a/apps/app/package.json b/apps/app/package.json index cc07a1bffc..cd26331c3c 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -38,6 +38,7 @@ "@tiptap/extension-table-row": "^2.22.3", "@trigger.dev/react-hooks": "3.3.17", "@trigger.dev/sdk": "3.3.17", + "@types/canvas-confetti": "^1.9.0", "@types/three": "^0.177.0", "@uploadthing/react": "^7.3.0", "@upstash/ratelimit": "^2.0.5", @@ -45,6 +46,7 @@ "ai": "^4.3.16", "axios": "^1.9.0", "better-auth": "^1.2.8", + "canvas-confetti": "^1.9.3", "d3": "^7.9.0", "framer-motion": "^12.18.1", "geist": "^1.3.1", diff --git a/apps/app/src/app/(app)/[orgId]/layout.tsx b/apps/app/src/app/(app)/[orgId]/layout.tsx index 4b5fa9daf3..fdd8e2a6cc 100644 --- a/apps/app/src/app/(app)/[orgId]/layout.tsx +++ b/apps/app/src/app/(app)/[orgId]/layout.tsx @@ -1,5 +1,6 @@ import { getSubscriptionData } from '@/app/api/stripe/getSubscriptionData'; import { AnimatedLayout } from '@/components/animated-layout'; +import { CheckoutCompleteDialog } from '@/components/dialogs/checkout-complete-dialog'; import { Header } from '@/components/header'; import { AssistantSheet } from '@/components/sheets/assistant-sheet'; import { Sidebar } from '@/components/sidebar'; @@ -10,6 +11,7 @@ import { db } from '@comp/db'; import dynamic from 'next/dynamic'; import { cookies, headers } from 'next/headers'; import { redirect } from 'next/navigation'; +import { Suspense } from 'react'; import { OnboardingTracker } from './components/OnboardingTracker'; const HotKeys = dynamic(() => import('@/components/hot-keys').then((mod) => mod.HotKeys), { @@ -100,6 +102,9 @@ export default async function Layout({ {children}
+ + + diff --git a/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx b/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx index 906f482035..68e2840dc8 100644 --- a/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx +++ b/apps/app/src/app/(app)/upgrade/[orgId]/pricing-cards.tsx @@ -220,7 +220,7 @@ export function PricingCards({ organizationId, priceDetails }: PricingCardsProps chooseSelfServeAction, { onSuccess: () => { - router.push(`/${organizationId}`); + router.push(`/${organizationId}?checkoutComplete=starter`); }, onError: ({ error }) => { toast.error(error.serverError || 'Failed to set up free plan'); @@ -252,7 +252,7 @@ export function PricingCards({ organizationId, priceDetails }: PricingCardsProps organizationId, mode: 'subscription', priceId, - successUrl: `${baseUrl}/${organizationId}/settings/billing?success=true`, + successUrl: `${baseUrl}/api/stripe/success?organizationId=${organizationId}&planType=done-for-you`, cancelUrl: `${baseUrl}/upgrade/${organizationId}`, allowPromotionCodes: true, metadata: { diff --git a/apps/app/src/app/api/stripe/success/route.ts b/apps/app/src/app/api/stripe/success/route.ts index 9294d3bc34..3e3dcfd8a0 100644 --- a/apps/app/src/app/api/stripe/success/route.ts +++ b/apps/app/src/app/api/stripe/success/route.ts @@ -7,9 +7,10 @@ import { syncStripeDataToKV } from '../syncStripeDataToKv'; export async function GET(req: Request) { const { user } = await getServersideSession(req); - // Extract organizationId from query parameters + // Extract organizationId and planType from query parameters const url = new URL(req.url); const organizationId = url.searchParams.get('organizationId'); + const planType = url.searchParams.get('planType') || 'done-for-you'; // Default to done-for-you for backwards compatibility if (!organizationId) { return redirect('/'); @@ -29,9 +30,10 @@ export async function GET(req: Request) { const stripeCustomerId = await client.get(`stripe:organization:${organizationId}`); if (!stripeCustomerId) { - return redirect('/'); + return redirect(`/${organizationId}`); } await syncStripeDataToKV(stripeCustomerId as string); - return redirect('/'); + // Redirect with the plan type from query parameters + return redirect(`/${organizationId}/frameworks?checkoutComplete=${planType}`); } diff --git a/apps/app/src/components/dialogs/checkout-complete-dialog.tsx b/apps/app/src/components/dialogs/checkout-complete-dialog.tsx new file mode 100644 index 0000000000..a71c5016b4 --- /dev/null +++ b/apps/app/src/components/dialogs/checkout-complete-dialog.tsx @@ -0,0 +1,250 @@ +'use client'; + +import { Badge } from '@comp/ui/badge'; +import { Button } from '@comp/ui/button'; +import { Card } from '@comp/ui/card'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@comp/ui/dialog'; +import confetti from 'canvas-confetti'; +import { + BookOpen, + CheckCircle2, + Code2, + Headphones, + LucideIcon, + MessageSquare, + Rocket, + Shield, + Sparkles, + Users, +} from 'lucide-react'; +import { useQueryState } from 'nuqs'; +import { useEffect, useState } from 'react'; + +type PlanType = 'starter' | 'done-for-you'; + +interface Feature { + icon: LucideIcon; + title: string; + description: string; +} + +interface PlanContent { + title: string; + description: string; + badge: string; + badgeDescription: string; + badgeClass: string; + cardClass: string; + iconClass: string; + iconColor: string; + features: Feature[]; + buttonText: string; + footerText: string; +} + +export function CheckoutCompleteDialog() { + const [checkoutComplete, setCheckoutComplete] = useQueryState('checkoutComplete', { + defaultValue: '', + clearOnDefault: true, + }); + const [open, setOpen] = useState(false); + + useEffect(() => { + if (checkoutComplete === 'starter' || checkoutComplete === 'done-for-you') { + const planType = checkoutComplete as PlanType; + + // Show the dialog + setOpen(true); + + // Trigger confetti animation + const duration = 3 * 1000; + const animationEnd = Date.now() + duration; + const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 }; + + function randomInRange(min: number, max: number) { + return Math.random() * (max - min) + min; + } + + const interval: any = setInterval(function () { + const timeLeft = animationEnd - Date.now(); + + if (timeLeft <= 0) { + return clearInterval(interval); + } + + const particleCount = 50 * (timeLeft / duration); + // Use different colors based on plan type + const colors = + planType === 'done-for-you' + ? ['#10b981', '#34d399', '#6ee7b7', '#a7f3d0', '#d1fae5'] // Green for paid + : ['#3b82f6', '#60a5fa', '#93bbfc', '#bfdbfe', '#dbeafe']; // Blue for starter + + confetti({ + ...defaults, + particleCount, + origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 }, + colors, + }); + confetti({ + ...defaults, + particleCount, + origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 }, + colors, + }); + }, 250); + + // Clear the query parameter immediately so it doesn't linger in the URL + setCheckoutComplete(''); + } + }, [checkoutComplete, setCheckoutComplete]); + + const handleClose = () => { + setOpen(false); + }; + + // Different content based on plan type + const content: Record = { + 'done-for-you': { + title: 'Welcome to Done For You!', + description: 'Your subscription is active and your compliance journey begins now.', + badge: '14 Day Money Back Guarantee', + badgeDescription: "If you're not completely satisfied, we'll refund you in full", + badgeClass: 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300', + cardClass: 'bg-green-50/50 dark:bg-green-950/20 border-green-200 dark:border-green-900/50', + iconClass: 'bg-green-100 dark:bg-green-900/30', + iconColor: 'text-green-600 dark:text-green-400', + features: [ + { + icon: Shield, + title: 'SOC 2 or ISO 27001 Done For You', + description: 'Complete compliance in 14 days or less', + }, + { + icon: Users, + title: 'Dedicated Success Team', + description: 'Your compliance experts are ready to help', + }, + { + icon: Sparkles, + title: '3rd Party Audit Included', + description: 'No hidden fees or surprise costs', + }, + { + icon: Headphones, + title: '24x7x365 Support', + description: "We're here whenever you need us", + }, + ], + buttonText: 'Get Started', + footerText: 'Your success team will reach out within 24 hours', + }, + starter: { + title: 'Welcome to Comp AI!', + description: "You're all set up with the Starter plan. Let's get you compliant!", + badge: 'DIY Compliance', + badgeDescription: 'Everything you need to achieve compliance on your own', + badgeClass: 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300', + cardClass: 'bg-blue-50/50 dark:bg-blue-950/20 border-blue-200 dark:border-blue-900/50', + iconClass: 'bg-blue-100 dark:bg-blue-900/30', + iconColor: 'text-blue-600 dark:text-blue-400', + features: [ + { + icon: Rocket, + title: 'Access to all frameworks', + description: 'SOC 2, ISO 27001, HIPAA, and more', + }, + { + icon: Code2, + title: 'API access', + description: 'Integrate compliance into your workflow', + }, + { + icon: BookOpen, + title: 'Trust & Security Portal', + description: 'Share your compliance status with customers', + }, + { + icon: MessageSquare, + title: 'Community Support', + description: 'Get help from the Comp AI community', + }, + ], + buttonText: 'Explore Frameworks', + footerText: 'Upgrade anytime for Done-for-You compliance', + }, + }; + + // Get current content, default to done-for-you if the value is not a valid plan type + const validPlanType = + checkoutComplete === 'starter' || checkoutComplete === 'done-for-you' + ? checkoutComplete + : 'done-for-you'; + const currentContent = content[validPlanType]; + + return ( + + + +
+ +
+ + {currentContent.title} + + + {currentContent.description} + +
+ +
+ +
+ {currentContent.badge} +

+ {currentContent.badgeDescription} +

+
+
+ +
+

What's included:

+
+ {currentContent.features.map((feature: Feature) => { + const Icon = feature.icon; + return ( +
+
+
+ +
+
+
+

{feature.title}

+

{feature.description}

+
+
+ ); + })} +
+
+
+ + + +

{currentContent.footerText}

+
+
+
+ ); +} diff --git a/bun.lock b/bun.lock index ad3464a40e..d2cdcb5ae4 100644 --- a/bun.lock +++ b/bun.lock @@ -95,6 +95,7 @@ "@tiptap/extension-table-row": "^2.22.3", "@trigger.dev/react-hooks": "3.3.17", "@trigger.dev/sdk": "3.3.17", + "@types/canvas-confetti": "^1.9.0", "@types/three": "^0.177.0", "@uploadthing/react": "^7.3.0", "@upstash/ratelimit": "^2.0.5", @@ -102,6 +103,7 @@ "ai": "^4.3.16", "axios": "^1.9.0", "better-auth": "^1.2.8", + "canvas-confetti": "^1.9.3", "d3": "^7.9.0", "framer-motion": "^12.18.1", "geist": "^1.3.1", @@ -1607,6 +1609,8 @@ "@types/bun": ["@types/bun@1.2.16", "", { "dependencies": { "bun-types": "1.2.16" } }, "sha512-1aCZJ/6nSiViw339RsaNhkNoEloLaPzZhxMOYEa7OzRzO41IGg5n/7I43/ZIAW/c+Q6cT12Vf7fOZOoVIzb5BQ=="], + "@types/canvas-confetti": ["@types/canvas-confetti@1.9.0", "", {}, "sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg=="], + "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], "@types/conventional-commits-parser": ["@types/conventional-commits-parser@5.0.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ=="], @@ -2057,6 +2061,8 @@ "caniuse-lite": ["caniuse-lite@1.0.30001723", "", {}, "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw=="], + "canvas-confetti": ["canvas-confetti@1.9.3", "", {}, "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g=="], + "caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], diff --git a/yarn.lock b/yarn.lock index cf81eaff99..6c329026e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1251,6 +1251,7 @@ "@tiptap/extension-table-row" "^2.22.3" "@trigger.dev/react-hooks" "3.3.17" "@trigger.dev/sdk" "3.3.17" + "@types/canvas-confetti" "^1.9.0" "@types/three" "^0.177.0" "@uploadthing/react" "^7.3.0" "@upstash/ratelimit" "^2.0.5" @@ -1258,6 +1259,7 @@ ai "^4.3.16" axios "^1.9.0" better-auth "^1.2.8" + canvas-confetti "^1.9.3" d3 "^7.9.0" framer-motion "^12.18.1" geist "^1.3.1" @@ -1312,6 +1314,7 @@ dependencies: "@comp/ui" "workspace:*" "@comp/utils" "workspace:*" + dependencies: "@react-email/components" "^0.0.41" "@react-email/render" "^1.1.2" "@react-email/tailwind" "1.0.5" @@ -5728,6 +5731,11 @@ dependencies: bun-types "1.2.16" +"@types/canvas-confetti@^1.9.0": + version "1.9.0" + resolved "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.9.0.tgz" + integrity sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg== + "@types/connect@*": version "3.4.38" resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" @@ -7403,6 +7411,11 @@ caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.300017 resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz" integrity sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw== +canvas-confetti@^1.9.3: + version "1.9.3" + resolved "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz" + integrity sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g== + caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" From 19fb0b993309d4fc404a5d780b2608148502d6e5 Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 24 Jun 2025 16:22:44 -0400 Subject: [PATCH 14/16] chore: comment out referrals so claudio is unblocked --- apps/app/src/components/main-menu.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/app/src/components/main-menu.tsx b/apps/app/src/components/main-menu.tsx index 89ca2cea34..2da92edd69 100644 --- a/apps/app/src/components/main-menu.tsx +++ b/apps/app/src/components/main-menu.tsx @@ -9,7 +9,6 @@ import { Blocks, FlaskConical, Gauge, - Gift, ListCheck, NotebookText, ShieldEllipsis, @@ -127,14 +126,14 @@ export function MainMenu({ organizationId, isCollapsed = false, onItemClick }: P variant: 'secondary', }, }, - { - id: 'referrals', - path: '/:organizationId/referrals', - name: 'Referrals', - disabled: false, - icon: Gift, - protected: false, - }, + // { + // id: 'referrals', + // path: '/:organizationId/referrals', + // name: 'Referrals', + // disabled: false, + // icon: Gift, + // protected: false, + // }, { id: 'settings', path: '/:organizationId/settings', From 2182c9e1e44df54fbf951fb00d7db546aa0f7ebf Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 16:24:09 -0400 Subject: [PATCH 15/16] feat(checkout): enhance CheckoutCompleteDialog with updated features and descriptions - Updated feature titles and descriptions for clarity and impact. - Added new icons for improved visual representation of features. - Modified button text and footer to better reflect user actions and support options. - Introduced a community support message for the starter plan to encourage user engagement. --- .../dialogs/checkout-complete-dialog.tsx | 50 ++++++++++++------- yarn.lock | 27 +++++----- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/apps/app/src/components/dialogs/checkout-complete-dialog.tsx b/apps/app/src/components/dialogs/checkout-complete-dialog.tsx index a71c5016b4..649ddb6aac 100644 --- a/apps/app/src/components/dialogs/checkout-complete-dialog.tsx +++ b/apps/app/src/components/dialogs/checkout-complete-dialog.tsx @@ -23,6 +23,9 @@ import { Shield, Sparkles, Users, + Brain, + FileText, + Zap, } from 'lucide-react'; import { useQueryState } from 'nuqs'; import { useEffect, useState } from 'react'; @@ -138,18 +141,18 @@ export function CheckoutCompleteDialog() { }, { icon: Headphones, - title: '24x7x365 Support', - description: "We're here whenever you need us", + title: '24x7x365 Support & SLA', + description: 'Priority support with guaranteed response times', }, ], buttonText: 'Get Started', footerText: 'Your success team will reach out within 24 hours', }, - starter: { - title: 'Welcome to Comp AI!', - description: "You're all set up with the Starter plan. Let's get you compliant!", - badge: 'DIY Compliance', - badgeDescription: 'Everything you need to achieve compliance on your own', + 'starter': { + title: 'Welcome to Starter!', + description: "Everything you need to get compliant, fast. Let's begin your DIY compliance journey!", + badge: 'DIY (Do It Yourself) Compliance', + badgeDescription: 'Build your compliance program at your own pace', badgeClass: 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300', cardClass: 'bg-blue-50/50 dark:bg-blue-950/20 border-blue-200 dark:border-blue-900/50', iconClass: 'bg-blue-100 dark:bg-blue-900/30', @@ -158,26 +161,26 @@ export function CheckoutCompleteDialog() { { icon: Rocket, title: 'Access to all frameworks', - description: 'SOC 2, ISO 27001, HIPAA, and more', + description: 'SOC 2, ISO 27001, HIPAA, GDPR, and more', }, { - icon: Code2, - title: 'API access', - description: 'Integrate compliance into your workflow', + icon: Brain, + title: 'AI Vendor & Risk Management', + description: 'Streamline your vendor assessments and risk tracking', }, { - icon: BookOpen, + icon: FileText, title: 'Trust & Security Portal', description: 'Share your compliance status with customers', }, { - icon: MessageSquare, - title: 'Community Support', - description: 'Get help from the Comp AI community', + icon: Zap, + title: 'Unlimited team members', + description: 'Collaborate with your entire team at no extra cost', }, ], - buttonText: 'Explore Frameworks', - footerText: 'Upgrade anytime for Done-for-You compliance', + buttonText: 'Start Building', + footerText: 'Upgrade to Done For You anytime for expert assistance', }, }; @@ -216,7 +219,9 @@ export function CheckoutCompleteDialog() {
-

What's included:

+

+ {validPlanType === 'starter' ? 'What you get:' : 'What's included:'} +

{currentContent.features.map((feature: Feature) => { const Icon = feature.icon; @@ -236,6 +241,15 @@ export function CheckoutCompleteDialog() { })}
+ + {validPlanType === 'starter' && ( +
+

+ + Join our community for support • Pay for your audit when ready +

+
+ )}
diff --git a/yarn.lock b/yarn.lock index 6c329026e2..b538776c25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1191,14 +1191,14 @@ "@types/conventional-commits-parser" "^5.0.0" chalk "^5.3.0" -"@comp/analytics@packages/analytics": +"@comp/analytics@^workspace:packages/analytics": version "workspace:packages/analytics" resolved "workspace:packages/analytics" dependencies: posthog-js "^1.236.6" posthog-node "^4.14.0" -"@comp/app@apps/app", "@comp/app@workspace:*": +"@comp/app@^workspace:apps/app", "@comp/app@workspace:*": version "workspace:apps/app" resolved "workspace:apps/app" devDependencies: @@ -1226,7 +1226,9 @@ "@browserbasehq/sdk" "^2.5.0" "@calcom/atoms" "^1.0.102-framer" "@calcom/embed-react" "^1.5.3" + dependencies: "@comp/db" "workspace:*" + dependencies: "@date-fns/tz" "^1.2.0" "@dnd-kit/core" "^6.3.1" "@dnd-kit/modifiers" "^9.0.0" @@ -1292,18 +1294,19 @@ xml2js "^0.6.2" zustand "^5.0.3" -"@comp/db@packages/db", "@comp/db@workspace:*": +"@comp/db@^workspace:packages/db", "@comp/db@workspace:*": version "workspace:packages/db" resolved "workspace:packages/db" devDependencies: "@comp/tsconfig" "workspace:*" + devDependencies: prisma "^6.9.0" ts-node "^10.9.2" typescript "^5.8.3" dependencies: "@prisma/client" "6.9.0" -"@comp/email@packages/email": +"@comp/email@^workspace:packages/email": version "workspace:packages/email" resolved "workspace:packages/email" devDependencies: @@ -1323,7 +1326,7 @@ react-email "^4.0.15" responsive-react-email "^0.0.5" -"@comp/framework-editor@apps/framework-editor": +"@comp/framework-editor@^workspace:apps/framework-editor": version "workspace:apps/framework-editor" resolved "workspace:apps/framework-editor" devDependencies: @@ -1353,7 +1356,7 @@ tippy.js "^6.3.7" zod "3.25.67" -"@comp/integrations@packages/integrations": +"@comp/integrations@^workspace:packages/integrations": version "workspace:packages/integrations" resolved "workspace:packages/integrations" devDependencies: @@ -1376,14 +1379,14 @@ stoppable "^1.1.0" zod "3.25.67" -"@comp/kv@packages/kv": +"@comp/kv@^workspace:packages/kv": version "workspace:packages/kv" resolved "workspace:packages/kv" dependencies: "@upstash/redis" "^1.34.2" server-only "0.0.1" -"@comp/portal@apps/portal": +"@comp/portal@^workspace:apps/portal": version "workspace:apps/portal" resolved "workspace:apps/portal" devDependencies: @@ -1414,7 +1417,7 @@ next "15.4.0-canary.85" react-email "^4.0.15" -"@comp/trust@apps/trust": +"@comp/trust@^workspace:apps/trust": version "workspace:apps/trust" resolved "workspace:apps/trust" devDependencies: @@ -1435,11 +1438,11 @@ lucide-react "^0.518.0" next "15.4.0-canary.85" -"@comp/tsconfig@packages/tsconfig", "@comp/tsconfig@workspace:*": +"@comp/tsconfig@^workspace:packages/tsconfig", "@comp/tsconfig@workspace:*": version "workspace:packages/tsconfig" resolved "workspace:packages/tsconfig" -"@comp/ui@packages/ui", "@comp/ui@workspace:*": +"@comp/ui@^workspace:packages/ui", "@comp/ui@workspace:*": version "workspace:packages/ui" resolved "workspace:packages/ui" devDependencies: @@ -1522,7 +1525,7 @@ use-debounce "^10.0.4" vaul "^0.9.6" -"@comp/utils@packages/utils", "@comp/utils@workspace:*": +"@comp/utils@^workspace:packages/utils", "@comp/utils@workspace:*": version "workspace:packages/utils" resolved "workspace:packages/utils" devDependencies: From e91f1f045d8e02fdc6f02b7cf95441b4753e3867 Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Tue, 24 Jun 2025 16:29:34 -0400 Subject: [PATCH 16/16] fix(checkout): refactor CheckoutCompleteDialog to improve plan type handling - Replaced local variable with state management for plan type to ensure accurate rendering. - Updated logic to conditionally render content based on stored plan type. - Improved icon imports for better clarity and consistency in the UI. --- .../dialogs/checkout-complete-dialog.tsx | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/app/src/components/dialogs/checkout-complete-dialog.tsx b/apps/app/src/components/dialogs/checkout-complete-dialog.tsx index 649ddb6aac..56f1ad6010 100644 --- a/apps/app/src/components/dialogs/checkout-complete-dialog.tsx +++ b/apps/app/src/components/dialogs/checkout-complete-dialog.tsx @@ -13,9 +13,9 @@ import { } from '@comp/ui/dialog'; import confetti from 'canvas-confetti'; import { - BookOpen, + Brain, CheckCircle2, - Code2, + FileText, Headphones, LucideIcon, MessageSquare, @@ -23,8 +23,6 @@ import { Shield, Sparkles, Users, - Brain, - FileText, Zap, } from 'lucide-react'; import { useQueryState } from 'nuqs'; @@ -58,10 +56,14 @@ export function CheckoutCompleteDialog() { clearOnDefault: true, }); const [open, setOpen] = useState(false); + const [planType, setPlanType] = useState(null); useEffect(() => { if (checkoutComplete === 'starter' || checkoutComplete === 'done-for-you') { - const planType = checkoutComplete as PlanType; + const detectedPlanType = checkoutComplete as PlanType; + + // Store the plan type before clearing the query param + setPlanType(detectedPlanType); // Show the dialog setOpen(true); @@ -85,7 +87,7 @@ export function CheckoutCompleteDialog() { const particleCount = 50 * (timeLeft / duration); // Use different colors based on plan type const colors = - planType === 'done-for-you' + detectedPlanType === 'done-for-you' ? ['#10b981', '#34d399', '#6ee7b7', '#a7f3d0', '#d1fae5'] // Green for paid : ['#3b82f6', '#60a5fa', '#93bbfc', '#bfdbfe', '#dbeafe']; // Blue for starter @@ -148,9 +150,10 @@ export function CheckoutCompleteDialog() { buttonText: 'Get Started', footerText: 'Your success team will reach out within 24 hours', }, - 'starter': { + starter: { title: 'Welcome to Starter!', - description: "Everything you need to get compliant, fast. Let's begin your DIY compliance journey!", + description: + "Everything you need to get compliant, fast. Let's begin your DIY compliance journey!", badge: 'DIY (Do It Yourself) Compliance', badgeDescription: 'Build your compliance program at your own pace', badgeClass: 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300', @@ -184,12 +187,12 @@ export function CheckoutCompleteDialog() { }, }; - // Get current content, default to done-for-you if the value is not a valid plan type - const validPlanType = - checkoutComplete === 'starter' || checkoutComplete === 'done-for-you' - ? checkoutComplete - : 'done-for-you'; - const currentContent = content[validPlanType]; + // Only render content if we have a valid plan type stored + if (!planType) { + return null; + } + + const currentContent = content[planType]; return ( @@ -220,7 +223,7 @@ export function CheckoutCompleteDialog() {

- {validPlanType === 'starter' ? 'What you get:' : 'What's included:'} + {planType === 'starter' ? 'What you get:' : "What's included:"}

{currentContent.features.map((feature: Feature) => { @@ -242,7 +245,7 @@ export function CheckoutCompleteDialog() {
- {validPlanType === 'starter' && ( + {planType === 'starter' && (