Skip to content

Commit 2cb781e

Browse files
thomasballingerConvex, Inc.
authored and
Convex, Inc.
committed
Chef-specific Referral path (#37271)
GitOrigin-RevId: 87b556eafcad3a350e5e0571b1be2286b69e5916
1 parent dcbec23 commit 2cb781e

File tree

8 files changed

+79
-18
lines changed

8 files changed

+79
-18
lines changed

npm-packages/dashboard/next.config.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ const nextConfig = {
5656
swcMinify: true,
5757
transpilePackages: [],
5858
reactStrictMode: true,
59+
async rewrites() {
60+
return [
61+
{
62+
source: "/try-chef/:code",
63+
destination: "/referral/:code",
64+
},
65+
{
66+
source: "/try-chef/:code/apply",
67+
destination: "/referral/:code/apply",
68+
},
69+
];
70+
},
5971
async headers() {
6072
return [
6173
{

npm-packages/dashboard/src/components/referral/RedeemReferralForm.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const meta = {
4848
teamEligibility: { eligible: true },
4949
onShowTeamSelector: () => {},
5050
isTeamSelectorShown: false,
51+
isChef: false,
5152
},
5253
} satisfies Meta<typeof RedeemReferralForm>;
5354

npm-packages/dashboard/src/components/referral/RedeemReferralForm.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export function RedeemReferralForm({
2323
isTeamSelectorShown,
2424
onShowTeamSelector,
2525
teamEligibility,
26+
isChef,
2627
}: {
2728
referralCode:
2829
| {
@@ -44,6 +45,7 @@ export function RedeemReferralForm({
4445
| undefined
4546
| { eligible: true }
4647
| { eligible: false; reason: TeamEligibilityError };
48+
isChef: boolean;
4749
}) {
4850
const [isSubmitting, setIsSubmitting] = useState(false);
4951

@@ -59,6 +61,7 @@ export function RedeemReferralForm({
5961
<CodeError
6062
title="Invalid referral code"
6163
description="Oh no, the code you used is invalid."
64+
isChef={isChef}
6265
/>
6366
) : referralCode.exhausted ? (
6467
<CodeError
@@ -70,6 +73,7 @@ export function RedeemReferralForm({
7073
longer valid.
7174
</>
7275
}
76+
isChef={isChef}
7377
/>
7478
) : (
7579
<>
@@ -155,7 +159,9 @@ export function RedeemReferralForm({
155159
disabled={!selectedTeam || !teamEligibility?.eligible}
156160
loading={isSubmitting || teamEligibility === undefined}
157161
>
158-
Get my free resources
162+
{isChef
163+
? "Get my free Chef tokens and Convex resources"
164+
: "Get my free resources"}
159165
</Button>
160166
</div>
161167
</form>
@@ -185,9 +191,11 @@ function teamEligibilityErrorMessage(error: TeamEligibilityError) {
185191
function CodeError({
186192
title,
187193
description,
194+
isChef,
188195
}: {
189196
title: string;
190197
description: React.ReactNode;
198+
isChef: boolean;
191199
}) {
192200
return (
193201
<>
@@ -207,7 +215,11 @@ function CodeError({
207215
</p>
208216

209217
<div>
210-
<Button href="/">Start Building</Button>
218+
{isChef ? (
219+
<Button href="https://chef.convex.dev">Start Building</Button>
220+
) : (
221+
<Button href="/">Start Building</Button>
222+
)}
211223
</div>
212224
</>
213225
);

npm-packages/dashboard/src/components/referral/RedeemReferralLanding.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const meta = {
66
args: {
77
title: "Someone thinks you’d like Convex!",
88
code: "CONVEX123",
9+
isChef: false,
910
},
1011
} satisfies Meta<typeof RedeemReferralLanding>;
1112

npm-packages/dashboard/src/components/referral/RedeemReferralLanding.test.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ describe("RedeemReferralLanding", () => {
1111
// button to ensure there is no regression on the click behavior.
1212
it("has a link that becomes disabled when clicked", async () => {
1313
const code = "TEST123";
14-
render(<RedeemReferralLanding title="Test Title" code={code} />);
14+
render(
15+
<RedeemReferralLanding title="Test Title" code={code} isChef={false} />,
16+
);
1517

1618
const link = screen.getByRole("link", { name: "Sign up with GitHub" });
1719
expect(link).toHaveAttribute(

npm-packages/dashboard/src/components/referral/RedeemReferralLanding.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,28 @@ import { useState } from "react";
88
export function RedeemReferralLanding({
99
title,
1010
code,
11+
isChef,
1112
}: {
1213
title: string;
1314
code: string;
15+
isChef: boolean;
1416
}) {
1517
return (
1618
<div className="relative mt-10 max-w-lg">
1719
<Sheet>
1820
<DisplayH1>{title}</DisplayH1>
1921

2022
<DisplayP>
21-
Convex is the open-source reactive database for app developers.
23+
{isChef
24+
? "Chef is an app builder powered by Convex, the open-source reactive database for app developers."
25+
: "Convex is the open-source reactive database for app developers."}
2226
</DisplayP>
2327

2428
<DisplayP>
2529
Accept this referral to double your free account quota.
2630
</DisplayP>
2731

28-
<LogInButton code={code} />
32+
<LogInButton code={code} isChef={isChef} />
2933
</Sheet>
3034
</div>
3135
);
@@ -53,7 +57,7 @@ function DisplayP({ children }: React.PropsWithChildren) {
5357
);
5458
}
5559

56-
function LogInButton({ code }: { code: string }) {
60+
function LogInButton({ code, isChef }: { code: string; isChef: boolean }) {
5761
const [clicked, setClicked] = useState(false);
5862

5963
return (
@@ -65,9 +69,11 @@ function LogInButton({ code }: { code: string }) {
6569
!clicked && "hover:shadow-[rgba(111,0,255,0.5)]",
6670
clicked && "opacity-80 cursor-progress",
6771
)}
68-
href={`/api/auth/login?returnTo=${encodeURIComponent(`/referral/${code}/apply`)}`}
72+
href={`/api/auth/login?returnTo=${encodeURIComponent(isChef ? `/try-chef/${code}/apply` : `/referral/${code}/apply`)}`}
6973
onClick={() => {
70-
logEvent("clicked “Sign up with GitHub” through referral landing");
74+
logEvent(
75+
`clicked “Sign up with GitHub” through ${isChef ? "Chef " : ""}referral landing`,
76+
);
7177
setClicked(true);
7278
}}
7379
aria-disabled={clicked}

npm-packages/dashboard/src/pages/referral/[code].tsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,23 @@ import { GetServerSideProps } from "next";
22
import { auth0 } from "server/auth0";
33
import { Flourish } from "layouts/LoginLayout";
44
import Head from "next/head";
5-
import { useParams } from "next/navigation";
5+
import { useParams, usePathname } from "next/navigation";
66
import Background from "components/login/images/background.svg";
77
import { ConvexLogo } from "@common/elements/ConvexLogo";
88
import { RedeemReferralLanding } from "components/referral/RedeemReferralLanding";
99

10+
/**
11+
* This page powers two routes via Next.js rewrites in next.config.js:
12+
* - /referral/THOMAS898
13+
* - /try-chef/THOMAS898
14+
* */
15+
1016
export const getServerSideProps: GetServerSideProps = async ({
1117
req,
1218
res,
1319
query,
1420
}) => {
21+
const isChef = req.url?.includes("try-chef");
1522
try {
1623
// Check if user is authenticated without forcing login
1724
const session = await auth0().getSession(req, res);
@@ -20,7 +27,9 @@ export const getServerSideProps: GetServerSideProps = async ({
2027
if (session?.user) {
2128
return {
2229
redirect: {
23-
destination: `/referral/${query.code}/apply`,
30+
destination: isChef
31+
? `/try-chef/${query.code}/apply`
32+
: `/referral/${query.code}/apply`,
2433
permanent: false,
2534
},
2635
};
@@ -35,12 +44,17 @@ export const getServerSideProps: GetServerSideProps = async ({
3544
}
3645
};
3746

38-
const title = "Someone thinks you’d like Convex!";
39-
const description = "Get Convex resources for free with this referral code.";
40-
const ogImage = `https://www.convex.dev/api/og?title=${encodeURIComponent(title)}`;
41-
4247
export default function ReferralLandingPage() {
4348
const { code } = useParams<{ code: string }>();
49+
const isChef = usePathname().includes("try-chef");
50+
51+
const title = isChef
52+
? "Someone thinks you'd like Chef!"
53+
: "Someone thinks you’d like Convex!";
54+
const description = isChef
55+
? "Get additional Chef tokens and Convex resources for free with this referral code."
56+
: "Get Convex resources for free with this referral code.";
57+
const ogImage = `https://www.convex.dev/api/og?title=${encodeURIComponent(title)}`;
4458

4559
return (
4660
<div className="flex h-screen w-full flex-col items-center bg-background-brand">
@@ -56,7 +70,7 @@ export default function ReferralLandingPage() {
5670
<meta property="og:site_name" content="Convex" />
5771
<meta
5872
property="og:url"
59-
content={`https://dashboard.convex.dev/referral/${code}`}
73+
content={`https://dashboard.convex.dev/${isChef ? "try-chef" : "referral"}/${code}`}
6074
/>
6175
<meta property="og:image" content={ogImage} />
6276

@@ -76,7 +90,7 @@ export default function ReferralLandingPage() {
7690
<Background className="stroke-[#D7D7D7] dark:hidden" />
7791
</div>
7892

79-
<RedeemReferralLanding title={title} code={code} />
93+
<RedeemReferralLanding title={title} code={code} isChef={isChef} />
8094
</div>
8195
);
8296
}

npm-packages/dashboard/src/pages/referral/[code]/apply.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,24 @@ import { LoginLayout } from "layouts/LoginLayout";
55
import { useTeamOrbSubscription } from "api/billing";
66
import { RedeemReferralForm } from "components/referral/RedeemReferralForm";
77
import { withAuthenticatedPage } from "lib/withAuthenticatedPage";
8-
import { useParams } from "next/navigation";
8+
import { useParams, usePathname } from "next/navigation";
99
import { useState } from "react";
1010
import { Team } from "generatedApi";
1111
import { useApplyReferralCode, useReferralCode } from "api/referrals";
1212
import { useProfile } from "api/profile";
1313
import { logEvent } from "convex-analytics";
1414

15+
/**
16+
* This page powers two routes via Next.js rewrites in next.config.js:
17+
* - /referral/THOMAS898/apply
18+
* - /try-chef/THOMAS898/apply
19+
* */
20+
1521
export { getServerSideProps } from "lib/ssr";
1622

1723
function RedeemReferralCodePage() {
24+
const isChef = usePathname().includes("try-chef");
25+
1826
const { code } = useParams<{ code: string }>();
1927

2028
const { selectedTeamSlug: defaultTeamSlug, teams } = useTeams();
@@ -50,9 +58,14 @@ function RedeemReferralCodePage() {
5058

5159
logEvent("redeemed referral code");
5260

53-
void router.push(`/t/${selectedTeam.slug}`);
61+
if (isChef) {
62+
window.location.href = "https://chef.convex.dev";
63+
} else {
64+
void router.push(`/t/${selectedTeam.slug}`);
65+
}
5466
}}
5567
teamEligibility={teamEligibility}
68+
isChef={isChef}
5669
/>
5770
</LoginLayout>
5871
</div>

0 commit comments

Comments
 (0)