diff --git a/apps/dashboard/src/@/components/ui/tooltip.tsx b/apps/dashboard/src/@/components/ui/tooltip.tsx index 392c1740796..cc07667ea2f 100644 --- a/apps/dashboard/src/@/components/ui/tooltip.tsx +++ b/apps/dashboard/src/@/components/ui/tooltip.tsx @@ -54,11 +54,11 @@ export function ToolTipLabel(props: { align={props.align} sideOffset={10} className={cn( - "max-w-[400px] whitespace-normal leading-relaxed", + "max-w-[400px] whitespace-normal p-0 leading-relaxed", props.contentClassName, )} > -
+
{props.leftIcon} {props.label} {props.rightIcon} diff --git a/apps/dashboard/src/app/(app)/components/TeamPlanBadge.tsx b/apps/dashboard/src/app/(app)/components/TeamPlanBadge.tsx index 01f947c70ef..2bd74d420e9 100644 --- a/apps/dashboard/src/app/(app)/components/TeamPlanBadge.tsx +++ b/apps/dashboard/src/app/(app)/components/TeamPlanBadge.tsx @@ -8,8 +8,8 @@ const teamPlanToBadgeVariant: Record< > = { // gray free: "secondary", - starter: "secondary", // yellow + starter: "warning", starter_legacy: "warning", growth_legacy: "warning", // green @@ -20,7 +20,7 @@ const teamPlanToBadgeVariant: Record< pro: "default", }; -function getTeamPlanBadgeLabel(plan: Team["billingPlan"]) { +export function getTeamPlanBadgeLabel(plan: Team["billingPlan"]) { if (plan === "growth_legacy") { return "Growth - Legacy"; } @@ -33,13 +33,14 @@ function getTeamPlanBadgeLabel(plan: Team["billingPlan"]) { export function TeamPlanBadge(props: { plan: Team["billingPlan"]; className?: string; + postfix?: string; }) { return ( - {getTeamPlanBadgeLabel(props.plan)} + {`${getTeamPlanBadgeLabel(props.plan)}${props.postfix || ""}`} ); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.client.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.client.tsx index ab323a27f7b..033a16eafd0 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.client.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.client.tsx @@ -7,9 +7,12 @@ import { PlanInfoCardUI } from "./PlanInfoCard"; export function PlanInfoCardClient(props: { subscriptions: TeamSubscription[]; team: Team; + openPlanSheetButtonByDefault: boolean; + highlightPlan: Team["billingPlan"] | undefined; }) { return ( { @@ -26,6 +29,7 @@ export function PlanInfoCardClient(props: { return res.data.result; }} + highlightPlan={props.highlightPlan} /> ); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.stories.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.stories.tsx index fc04bf27041..70e140ef374 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.stories.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.stories.tsx @@ -118,6 +118,8 @@ function Story(props: { team={team} subscriptions={zeroUsageOnDemandSubs} getTeam={teamTeamStub} + highlightPlan={undefined} + openPlanSheetButtonByDefault={false} /> @@ -129,6 +131,8 @@ function Story(props: { }} subscriptions={zeroUsageOnDemandSubs} getTeam={teamTeamStub} + highlightPlan={undefined} + openPlanSheetButtonByDefault={false} /> @@ -137,6 +141,8 @@ function Story(props: { team={team} subscriptions={trialPlanZeroUsageOnDemandSubs} getTeam={teamTeamStub} + highlightPlan={undefined} + openPlanSheetButtonByDefault={false} /> @@ -145,6 +151,8 @@ function Story(props: { team={team} subscriptions={subsWith1Usage} getTeam={teamTeamStub} + highlightPlan={undefined} + openPlanSheetButtonByDefault={false} /> @@ -153,6 +161,8 @@ function Story(props: { team={team} subscriptions={subsWith4Usage} getTeam={teamTeamStub} + highlightPlan={undefined} + openPlanSheetButtonByDefault={false} />
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 519b67b9022..f8ac4b413a5 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 @@ -28,11 +28,15 @@ export function PlanInfoCardUI(props: { subscriptions: TeamSubscription[]; team: Team; getTeam: () => Promise; + openPlanSheetButtonByDefault: boolean; + highlightPlan: Team["billingPlan"] | undefined; }) { - const { subscriptions, team } = props; + const { subscriptions, team, openPlanSheetButtonByDefault } = props; const validPlan = getValidTeamPlan(team); const isActualFreePlan = team.billingPlan === "free"; - const [isPlanSheetOpen, setIsPlanSheetOpen] = useState(false); + const [isPlanSheetOpen, setIsPlanSheetOpen] = useState( + openPlanSheetButtonByDefault, + ); const planSub = subscriptions.find( (subscription) => subscription.type === "PLAN", @@ -54,6 +58,7 @@ export function PlanInfoCardUI(props: { isOpen={isPlanSheetOpen} onOpenChange={setIsPlanSheetOpen} getTeam={props.getTeam} + highlightPlan={props.highlightPlan} />
@@ -298,6 +303,7 @@ function ViewPlansSheet(props: { isOpen: boolean; onOpenChange: (open: boolean) => void; getTeam: () => Promise; + highlightPlan: Team["billingPlan"] | undefined; }) { return ( @@ -309,6 +315,7 @@ function ViewPlansSheet(props: { team={props.team} trialPeriodEndedAt={props.trialPeriodEndedAt} getTeam={props.getTeam} + highlightPlan={props.highlightPlan} /> diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx index 260d7d278de..d91ceaf0cfc 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/settings/billing/page.tsx @@ -1,4 +1,4 @@ -import { getTeamBySlug } from "@/api/team"; +import { type Team, getTeamBySlug } from "@/api/team"; import { getTeamSubscriptions } from "@/api/team-subscription"; import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; import { Billing } from "components/settings/Account/Billing"; @@ -10,8 +10,13 @@ export default async function Page(props: { params: Promise<{ team_slug: string; }>; + searchParams: Promise<{ + showPlans?: string | string[]; + highlight?: string | string[]; + }>; }) { const params = await props.params; + const searchParams = await props.searchParams; const pagePath = `/team/${params.team_slug}/settings/billing`; const [account, team, authToken] = await Promise.all([ @@ -41,6 +46,12 @@ export default async function Page(props: { return ( diff --git a/apps/dashboard/src/components/settings/Account/Billing/GatedSwitch.tsx b/apps/dashboard/src/components/settings/Account/Billing/GatedSwitch.tsx index dfb688ae7fb..fbecb1f40d6 100644 --- a/apps/dashboard/src/components/settings/Account/Billing/GatedSwitch.tsx +++ b/apps/dashboard/src/components/settings/Account/Billing/GatedSwitch.tsx @@ -1,9 +1,14 @@ import type { Team } from "@/api/team"; +import { Button } from "@/components/ui/button"; import { Switch } from "@/components/ui/switch"; import { ToolTipLabel } from "@/components/ui/tooltip"; import { TrackedLinkTW } from "@/components/ui/tracked-link"; import { cn } from "@/lib/utils"; -import { TeamPlanBadge } from "../../../../app/(app)/components/TeamPlanBadge"; +import { ExternalLinkIcon } from "lucide-react"; +import { + TeamPlanBadge, + getTeamPlanBadgeLabel, +} from "../../../../app/(app)/components/TeamPlanBadge"; import { planToTierRecordForGating } from "./planToTierRecord"; type SwitchProps = React.ComponentProps; @@ -26,26 +31,40 @@ export const GatedSwitch: React.FC = ( return ( - To access this feature,
Upgrade to the{" "} - - {props.requiredPlan} plan - - +
+

+ + {getTeamPlanBadgeLabel(props.requiredPlan)}+ + {" "} + plan required +

+

+ Upgrade your plan to use this feature +

+ +
+ +
+
) : undefined } >
- {isUpgradeRequired && } + {isUpgradeRequired && ( + + )} Promise; + highlightPlan: Team["billingPlan"] | undefined; } type CtaLink = @@ -49,6 +50,7 @@ export const BillingPricing: React.FC = ({ team, trialPeriodEndedAt, getTeam, + highlightPlan, }) => { const validTeamPlan = getValidTeamPlan(team); const [isPending, startTransition] = useTransition(); @@ -65,17 +67,28 @@ export const BillingPricing: React.FC = ({ const isCurrentPlanScheduledToCancel = team.planCancellationDate !== null; const highlightGrowthPlan = - !isCurrentPlanScheduledToCancel && - (validTeamPlan === "free" || - validTeamPlan === "starter" || - validTeamPlan === "growth_legacy"); + highlightPlan === "growth" || + (!highlightPlan && + !isCurrentPlanScheduledToCancel && + (validTeamPlan === "free" || + validTeamPlan === "starter" || + validTeamPlan === "growth_legacy")); const highlightStarterPlan = - !isCurrentPlanScheduledToCancel && validTeamPlan === "starter_legacy"; + highlightPlan === "starter" || + (!highlightPlan && + !isCurrentPlanScheduledToCancel && + validTeamPlan === "starter_legacy"); const highlightAcceleratePlan = - !isCurrentPlanScheduledToCancel && validTeamPlan === "growth"; + highlightPlan === "accelerate" || + (!highlightPlan && + !isCurrentPlanScheduledToCancel && + validTeamPlan === "growth"); const highlightScalePlan = - !isCurrentPlanScheduledToCancel && validTeamPlan === "accelerate"; + highlightPlan === "scale" || + (!highlightPlan && + !isCurrentPlanScheduledToCancel && + validTeamPlan === "accelerate"); return (
diff --git a/apps/dashboard/src/components/settings/Account/Billing/index.tsx b/apps/dashboard/src/components/settings/Account/Billing/index.tsx index ed413c7cbfd..d46d3717281 100644 --- a/apps/dashboard/src/components/settings/Account/Billing/index.tsx +++ b/apps/dashboard/src/components/settings/Account/Billing/index.tsx @@ -13,6 +13,8 @@ interface BillingProps { subscriptions: TeamSubscription[]; twAccount: Account; client: ThirdwebClient; + openPlanSheetButtonByDefault: boolean; + highlightPlan: Team["billingPlan"] | undefined; } export const Billing: React.FC = ({ @@ -20,6 +22,8 @@ export const Billing: React.FC = ({ subscriptions, twAccount, client, + openPlanSheetButtonByDefault, + highlightPlan, }) => { const validPayment = team.billingStatus === "validPayment" || team.billingStatus === "pastDue"; @@ -27,7 +31,12 @@ export const Billing: React.FC = ({ return (
- +