diff --git a/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/add-members/page.tsx b/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/add-members/page.tsx index 15bdf36d4ee..2bc7960ce25 100644 --- a/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/add-members/page.tsx +++ b/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/add-members/page.tsx @@ -24,7 +24,7 @@ export default async function Page(props: { }); return ( - + ); diff --git a/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/select-plan/_components/plan-selector.tsx b/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/select-plan/_components/plan-selector.tsx new file mode 100644 index 00000000000..a677a5ad447 --- /dev/null +++ b/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/select-plan/_components/plan-selector.tsx @@ -0,0 +1,167 @@ +"use client"; + +import type { Team } from "@/api/team"; +import { PricingCard } from "@/components/blocks/pricing-card"; +import { Button } from "@/components/ui/button"; +import { Separator } from "@/components/ui/separator"; +import { useDashboardRouter } from "@/lib/DashboardRouter"; +import { useTrack } from "hooks/analytics/useTrack"; +import Link from "next/link"; +import { pollWithTimeout } from "utils/pollWithTimeout"; +import { useStripeRedirectEvent } from "../../../../../(stripe)/stripe-redirect/stripeRedirectChannel"; + +export function PlanSelector(props: { + team: Team; + getTeam: () => Promise; +}) { + const trackEvent = useTrack(); + const router = useDashboardRouter(); + + useStripeRedirectEvent(async () => { + // poll until the team has a non-free billing plan with a timeout of 5 seconds + await pollWithTimeout({ + shouldStop: async () => { + const team = await props.getTeam(); + const isNonFreePlan = team.billingPlan !== "free"; + + if (isNonFreePlan) { + trackEvent({ + category: "teamOnboarding", + action: "upgradePlan", + label: "success", + plan: team.billingPlan, + }); + router.replace(`/get-started/team/${props.team.slug}/add-members`); + } + + return isNonFreePlan; + }, + timeoutMs: 20_000, + }); + }); + + const starterPlan = ( + + ); + + const growthPlan = ( + + ); + + const scalePlan = ( + + ); + + const proPlan = ( + + ); + + return ( +
+ {starterPlan} + {growthPlan} + {scalePlan} + {proPlan} +
+
+ +
+ or +
+
+ +
+
+ ); +} diff --git a/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/select-plan/page.tsx b/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/select-plan/page.tsx new file mode 100644 index 00000000000..96c19ed44ae --- /dev/null +++ b/apps/dashboard/src/app/(app)/get-started/team/[team_slug]/select-plan/page.tsx @@ -0,0 +1,39 @@ +import { type Team, getTeamBySlug } from "@/api/team"; +import { notFound } from "next/navigation"; +import { getAuthToken } from "../../../../api/lib/getAuthToken"; +import { TeamOnboardingLayout } from "../../../../login/onboarding/onboarding-layout"; +import { PlanSelector } from "./_components/plan-selector"; + +export default async function Page(props: { + params: Promise<{ team_slug: string }>; +}) { + const params = await props.params; + const [team, authToken] = await Promise.all([ + getTeamBySlug(params.team_slug), + getAuthToken(), + ]); + + if (!team || !authToken) { + notFound(); + } + + // const client = getClientThirdwebClient({ + // jwt: authToken, + // teamId: team.id, + // }); + + async function getTeam() { + "use server"; + const resolvedTeam = await getTeamBySlug(params.team_slug); + if (!resolvedTeam) { + return team as Team; + } + return resolvedTeam; + } + + return ( + + + + ); +} diff --git a/apps/dashboard/src/app/(app)/login/onboarding/onboarding-layout.tsx b/apps/dashboard/src/app/(app)/login/onboarding/onboarding-layout.tsx index f530c772447..ca3a4b94e85 100644 --- a/apps/dashboard/src/app/(app)/login/onboarding/onboarding-layout.tsx +++ b/apps/dashboard/src/app/(app)/login/onboarding/onboarding-layout.tsx @@ -6,6 +6,7 @@ import { BoxIcon, LogOutIcon, MailIcon, + RocketIcon, UserIcon, UsersIcon, } from "lucide-react"; @@ -76,17 +77,23 @@ const teamOnboardingSteps: OnboardingStep[] = [ description: "Provide team details", number: 1, }, + { + icon: RocketIcon, + title: "Plan Selection", + description: "Choose a plan that fits your needs", + number: 2, + }, { icon: UsersIcon, title: "Team Members", description: "Invite members to your team", - number: 2, + number: 3, }, ]; export function TeamOnboardingLayout(props: { children: React.ReactNode; - currentStep: 1 | 2; + currentStep: 1 | 2 | 3; }) { return ( -
+
{/* Left */} -
- {props.children} -
+
{props.children}
{/* Right */}
diff --git a/apps/dashboard/src/app/(app)/login/onboarding/team-onboarding/team-onboarding.tsx b/apps/dashboard/src/app/(app)/login/onboarding/team-onboarding/team-onboarding.tsx index 54bb9b18093..2d2997180c0 100644 --- a/apps/dashboard/src/app/(app)/login/onboarding/team-onboarding/team-onboarding.tsx +++ b/apps/dashboard/src/app/(app)/login/onboarding/team-onboarding/team-onboarding.tsx @@ -40,7 +40,7 @@ export function TeamInfoForm(props: { teamSlug={props.teamSlug} client={props.client} onComplete={(updatedTeam) => { - router.replace(`/get-started/team/${updatedTeam.slug}/add-members`); + router.replace(`/get-started/team/${updatedTeam.slug}/select-plan`); }} updateTeam={async (data) => { const teamValue: Partial = { diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.tsx index d359b8f9e3d..0e262a9a0ba 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.tsx @@ -300,7 +300,7 @@ function BillingInfo({ -{" "} View Breakdown @@ -332,15 +332,11 @@ function SubscriptionOverview(props: { props.title ))}

- {format( - new Date(props.subscription.currentPeriodStart), - "MMMM dd yyyy", - )}{" "} - -{" "} + Your next billing period begins{" "} {format( new Date(props.subscription.currentPeriodEnd), - "MMMM dd yyyy", - )}{" "} + "MMMM dd, yyyy", + )}