Skip to content

Commit 82a79e7

Browse files
authored
Merge pull request #1030 from trycompai/main
[comp] Production Deploy
2 parents f4a5917 + bfbbcdb commit 82a79e7

File tree

19 files changed

+704
-58
lines changed

19 files changed

+704
-58
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ jobs:
4343
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
4444
# NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # Uncomment if publishing to npm
4545
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
46+
HUSKY: 0 # Skip husky hooks in CI
4647
run: npx semantic-release

apps/app/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@dnd-kit/modifiers": "^9.0.0",
2020
"@dnd-kit/sortable": "^10.0.0",
2121
"@dnd-kit/utilities": "^3.2.2",
22+
"@dub/embed-react": "^0.0.14",
2223
"@hookform/resolvers": "^5.1.1",
2324
"@mendable/firecrawl-js": "^1.24.0",
2425
"@nangohq/frontend": "^0.53.2",
@@ -38,14 +39,17 @@
3839
"@tiptap/extension-table-row": "^2.22.3",
3940
"@trigger.dev/react-hooks": "3.3.17",
4041
"@trigger.dev/sdk": "3.3.17",
42+
"@types/canvas-confetti": "^1.9.0",
4143
"@types/three": "^0.177.0",
4244
"@uploadthing/react": "^7.3.0",
4345
"@upstash/ratelimit": "^2.0.5",
4446
"@vercel/sdk": "^1.7.1",
4547
"ai": "^4.3.16",
4648
"axios": "^1.9.0",
4749
"better-auth": "^1.2.8",
50+
"canvas-confetti": "^1.9.3",
4851
"d3": "^7.9.0",
52+
"dub": "^0.63.5",
4953
"framer-motion": "^12.18.1",
5054
"geist": "^1.3.1",
5155
"motion": "^12.9.2",

apps/app/src/app/(app)/[orgId]/layout.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getSubscriptionData } from '@/app/api/stripe/getSubscriptionData';
22
import { AnimatedLayout } from '@/components/animated-layout';
3+
import { CheckoutCompleteDialog } from '@/components/dialogs/checkout-complete-dialog';
34
import { Header } from '@/components/header';
45
import { AssistantSheet } from '@/components/sheets/assistant-sheet';
56
import { Sidebar } from '@/components/sidebar';
@@ -10,6 +11,7 @@ import { db } from '@comp/db';
1011
import dynamic from 'next/dynamic';
1112
import { cookies, headers } from 'next/headers';
1213
import { redirect } from 'next/navigation';
14+
import { Suspense } from 'react';
1315
import { OnboardingTracker } from './components/OnboardingTracker';
1416

1517
const HotKeys = dynamic(() => import('@/components/hot-keys').then((mod) => mod.HotKeys), {
@@ -100,6 +102,9 @@ export default async function Layout({
100102
<SubscriptionProvider subscription={subscriptionData}>{children}</SubscriptionProvider>
101103
</div>
102104
<AssistantSheet />
105+
<Suspense fallback={null}>
106+
<CheckoutCompleteDialog />
107+
</Suspense>
103108
</AnimatedLayout>
104109
<HotKeys />
105110
</SidebarProvider>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use client';
2+
3+
import { DubEmbed } from '@dub/embed-react';
4+
5+
export const DubReferral = ({ publicToken }: { publicToken: string | null }) => {
6+
if (!publicToken) {
7+
return (
8+
<div className="flex min-h-[400px] items-center justify-center">
9+
<p className="text-sm text-muted-foreground">
10+
No token available. Please try refreshing the page.
11+
</p>
12+
</div>
13+
);
14+
}
15+
16+
return (
17+
<DubEmbed
18+
data="referrals"
19+
token={publicToken}
20+
options={{
21+
theme: 'system',
22+
}}
23+
/>
24+
);
25+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { env } from '@/env.mjs';
2+
import { Dub } from 'dub';
3+
4+
export const dub = new Dub({
5+
token: env.DUB_API_KEY,
6+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { env } from '@/env.mjs';
2+
import { auth } from '@/utils/auth';
3+
import { headers } from 'next/headers';
4+
import { redirect } from 'next/navigation';
5+
import { DubReferral } from './components/DubReferral';
6+
import { dub } from './lib/dub';
7+
8+
export default async function ReferralsPage() {
9+
const publicToken = await createPublicToken();
10+
11+
return <DubReferral publicToken={publicToken} />;
12+
}
13+
14+
async function createPublicToken() {
15+
const session = await auth.api.getSession({ headers: await headers() });
16+
17+
if (!session) {
18+
redirect('/');
19+
}
20+
21+
if (!env.DUB_PROGRAM_ID || !env.DUB_API_KEY) {
22+
return null;
23+
}
24+
25+
const { publicToken } = await dub.embedTokens.referrals({
26+
programId: env.DUB_PROGRAM_ID,
27+
partner: {
28+
tenantId: session.user.id,
29+
name: session.user.name || '',
30+
email: session.user.email || '',
31+
image: session.user.image || '',
32+
},
33+
});
34+
35+
return publicToken;
36+
}

apps/app/src/app/(app)/setup/components/AnimatedGradientBackgroundWrapper.tsx

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,6 @@ export function AnimatedGradientBackgroundWrapper() {
77
const [scale, setScale] = useState(0.7);
88

99
useEffect(() => {
10-
// Function to calculate scale from localStorage
11-
const updateScale = () => {
12-
if (typeof window !== 'undefined') {
13-
const stepIndex = parseInt(localStorage.getItem('onboarding-step-index') || '0');
14-
const totalSteps = parseInt(localStorage.getItem('onboarding-total-steps') || '9');
15-
16-
// Calculate scale based on step progress (0.7 to 1.5)
17-
const progressScale = 0.7 + (stepIndex / (totalSteps - 1)) * 0.8;
18-
setScale(progressScale);
19-
}
20-
};
21-
22-
// Initial load
23-
updateScale();
24-
2510
// Listen for step changes
2611
const handleStepChange = (event: Event) => {
2712
const customEvent = event as CustomEvent;

apps/app/src/app/(app)/setup/components/OrganizationSetupForm.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,23 +62,18 @@ export function OrganizationSetupForm({
6262

6363
const hasExistingOrgs = existingOrganizations.length > 0;
6464

65-
// Save step progress to localStorage
65+
// Dispatch custom event for background animation when step changes
6666
useEffect(() => {
6767
if (typeof window !== 'undefined') {
6868
if (isFinalizing) {
6969
// Set to max scale when finalizing
70-
localStorage.setItem('onboarding-progress', '1');
7170
window.dispatchEvent(
7271
new CustomEvent('onboarding-step-change', {
7372
detail: { stepIndex: steps.length - 1, totalSteps: steps.length, progress: 1 },
7473
}),
7574
);
7675
} else {
7776
const progress = stepIndex / (steps.length - 1);
78-
localStorage.setItem('onboarding-step-index', stepIndex.toString());
79-
localStorage.setItem('onboarding-total-steps', steps.length.toString());
80-
localStorage.setItem('onboarding-progress', progress.toString());
81-
8277
// Dispatch custom event to notify the background wrapper
8378
window.dispatchEvent(
8479
new CustomEvent('onboarding-step-change', {

apps/app/src/app/(app)/setup/hooks/useOnboardingForm.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ import { z } from 'zod';
1111
import { createOrganization } from '../actions/create-organization';
1212
import { createOrganizationMinimal } from '../actions/create-organization-minimal';
1313
import type { OnboardingFormFields } from '../components/OnboardingStepInput';
14-
import { STORAGE_KEY, companyDetailsSchema, steps } from '../lib/constants';
14+
import { companyDetailsSchema, steps } from '../lib/constants';
1515
import { updateSetupSession } from '../lib/setup-session';
1616
import type { CompanyDetails } from '../lib/types';
17-
import { useLocalStorage } from './useLocalStorage';
1817

1918
interface UseOnboardingFormProps {
2019
setupId?: string;
@@ -29,9 +28,8 @@ export function useOnboardingForm({
2928
}: UseOnboardingFormProps = {}) {
3029
const router = useRouter();
3130

32-
// If we have a setupId, use the initialData from KV, otherwise use localStorage
33-
const [savedAnswers, setSavedAnswers] = useLocalStorage<Partial<CompanyDetails>>(
34-
STORAGE_KEY,
31+
// Use state instead of localStorage - initialized from KV data if setupId exists
32+
const [savedAnswers, setSavedAnswers] = useState<Partial<CompanyDetails>>(
3533
setupId && initialData ? initialData : {},
3634
);
3735

@@ -108,6 +106,7 @@ export function useOnboardingForm({
108106
// Organization created, now redirect to plans page
109107
router.push(`/upgrade/${data.organizationId}`);
110108

109+
// Clear answers after successful creation
111110
setSavedAnswers({});
112111
} else {
113112
toast.error('Failed to create organization');
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use client';
2+
3+
import CalendarEmbed from '@/components/calendar-embed';
4+
import { Button } from '@comp/ui/button';
5+
import {
6+
Dialog,
7+
DialogContent,
8+
DialogDescription,
9+
DialogHeader,
10+
DialogTitle,
11+
DialogTrigger,
12+
} from '@comp/ui/dialog';
13+
import { Phone } from 'lucide-react';
14+
15+
export function BookingDialog() {
16+
return (
17+
<Dialog>
18+
<DialogTrigger asChild>
19+
<Button variant="outline" size="sm" className="w-full">
20+
<Phone className="h-4 w-4" />
21+
Book a Call with Our Team
22+
</Button>
23+
</DialogTrigger>
24+
<DialogContent className="sm:max-w-4xl md:max-w-5xl lg:max-w-6xl w-[95vw] h-[70vh] p-0 overflow-y-auto">
25+
<div className="flex flex-col h-full">
26+
<DialogHeader className="px-8 py-6 border-b">
27+
<DialogTitle className="text-xl font-semibold">
28+
Schedule a Call with Our Compliance Experts
29+
</DialogTitle>
30+
<DialogDescription className="mt-2">
31+
Have questions about our plans? Want to learn how we can help you achieve compliance
32+
in 14 days? Book a call with our team.
33+
</DialogDescription>
34+
</DialogHeader>
35+
<div className="flex-1 mx-auto w-full">
36+
<CalendarEmbed />
37+
</div>
38+
</div>
39+
</DialogContent>
40+
</Dialog>
41+
);
42+
}

0 commit comments

Comments
 (0)