diff --git a/apps/webapp/app/components/billing/PricingTiers.tsx b/apps/webapp/app/components/billing/PricingTiers.tsx
index 508198e03..d13cf6351 100644
--- a/apps/webapp/app/components/billing/PricingTiers.tsx
+++ b/apps/webapp/app/components/billing/PricingTiers.tsx
@@ -56,74 +56,119 @@ export function PricingTiers({
className
)}
>
-
+
);
}
-export function TierFree({ plan }: { plan: Plan }) {
+export function TierFree({
+ plan,
+ organizationSlug,
+ showActionText,
+}: {
+ plan: Plan;
+ organizationSlug: string;
+ showActionText: boolean;
+}) {
+ const lastSubmission = useActionData();
+ const [form] = useForm({
+ id: "subscribe",
+ // TODO: type this
+ lastSubmission: lastSubmission as any,
+ onValidate({ formData }) {
+ return parse(formData, { schema: SetPlanBodySchema });
+ },
+ });
+
+ const navigation = useNavigation();
+ const isLoading = navigation.state === "submitting" || navigation.state === "loading";
+
+ const currentPlan = useCurrentPlan();
+ const isCurrentPlan =
+ currentPlan?.subscription?.isPaying === undefined ||
+ currentPlan?.subscription?.isPaying === false;
+
+ let actionText = "Select plan";
+
+ if (showActionText) {
+ if (isCurrentPlan) {
+ actionText = "Current Plan";
+ } else {
+ actionText = "Downgrade";
+ }
+ }
+
return (
-
-
- Up to {plan.concurrentRuns?.freeAllowance}{" "}
-
+
+
+ Up to {plan.concurrentRuns?.freeAllowance}{" "}
+
+ {pricingDefinitions.concurrentRuns.title}
+
+
+
+
-
-
-
-
- Up to {plan.runs?.freeAllowance ? formatNumberCompact(plan.runs.freeAllowance) : ""}{" "}
-
- {pricingDefinitions.jobRuns.title}
-
-
-
- Unlimited{" "}
-
- Jobs
-
-
-
- Unlimited{" "}
-
- Tasks
-
-
-
- Unlimited{" "}
-
- Events
-
-
- Unlimited team members
- 24 hour log retention
- Community support
- Custom Integrations
- Role-based access control
- SSO
- On-prem option
-
+ {isLoading ? "Updating plan" : actionText}
+
+
+
+ Up to {plan.runs?.freeAllowance ? formatNumberCompact(plan.runs.freeAllowance) : ""}{" "}
+
+ {pricingDefinitions.jobRuns.title}
+
+
+
+ Unlimited{" "}
+
+ Jobs
+
+
+
+ Unlimited{" "}
+
+ Tasks
+
+
+
+ Unlimited{" "}
+
+ Events
+
+
+ Unlimited team members
+ 24 hour log retention
+ Community support
+ Custom Integrations
+ Role-based access control
+ SSO
+ On-prem option
+
+
);
}
@@ -138,7 +183,7 @@ export function TierPro({
showActionText: boolean;
}) {
const lastSubmission = useActionData();
- const [form, { path, feedbackType, message }] = useForm({
+ const [form] = useForm({
id: "subscribe",
// TODO: type this
lastSubmission: lastSubmission as any,
@@ -164,12 +209,16 @@ export function TierPro({
const isCurrentPlan = currentConcurrencyTier === concurrentBracketCode;
- let actionText = isCurrentPlan ? "Current Plan" : "Select plan";
+ let actionText = "Select plan";
- if (showActionText && !isCurrentPlan) {
- const currentTierIndex = concurrencyTiers.findIndex((c) => c.code === currentConcurrencyTier);
- const selectedTierIndex = concurrencyTiers.findIndex((c) => c.code === concurrentBracketCode);
- actionText = currentTierIndex < selectedTierIndex ? "Upgrade" : "Downgrade";
+ if (showActionText) {
+ if (isCurrentPlan) {
+ actionText = "Current Plan";
+ } else {
+ const currentTierIndex = concurrencyTiers.findIndex((c) => c.code === currentConcurrencyTier);
+ const selectedTierIndex = concurrencyTiers.findIndex((c) => c.code === concurrentBracketCode);
+ actionText = currentTierIndex < selectedTierIndex ? "Upgrade" : "Downgrade";
+ }
}
return (
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.billing/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.billing/route.tsx
index 920961408..fa0ca526c 100644
--- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.billing/route.tsx
+++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.billing/route.tsx
@@ -27,6 +27,7 @@ import { formatDurationInDays } from "~/utils";
import { Handle } from "~/utils/handle";
import { OrganizationParamsSchema, plansPath, usagePath } from "~/utils/pathBuilder";
import { useCurrentPlan } from "../_app.orgs.$organizationSlug/route";
+import { ActiveSubscription } from "@trigger.dev/billing";
export async function loader({ params, request }: LoaderFunctionArgs) {
const userId = await requireUserId(request);
@@ -51,6 +52,29 @@ export const handle: Handle = {
breadcrumb: (match) => ,
};
+function planLabel(subscription?: ActiveSubscription) {
+ if (!subscription) {
+ return "You're currently on the Free plan";
+ }
+ if (!subscription.isPaying) {
+ return `You're currently on the ${subscription.plan.title} plan`;
+ }
+ const costDescription = subscription.plan.concurrentRuns.pricing
+ ? `\$${subscription.plan.concurrentRuns.pricing?.tierCost}/mo`
+ : "";
+ if (subscription.canceledAt) {
+ return (
+ <>
+ You're on the {costDescription} {subscription.plan.title} plan until{" "}
+ when you'll be on the Free
+ plan
+ >
+ );
+ }
+
+ return `You're currently on the ${costDescription} ${subscription.plan.title} plan`;
+}
+
export default function Page() {
const { stripePortalLink } = useTypedLoaderData();
const organization = useOrganization();
@@ -93,11 +117,7 @@ export default function Page() {
{currentPlan?.subscription && (
}
- value={`You're currently on the${
- currentPlan.subscription.plan.concurrentRuns.pricing?.tierCost
- ? ` \$${currentPlan.subscription.plan.concurrentRuns.pricing?.tierCost}/mo`
- : ""
- } ${currentPlan.subscription?.plan.title} plan`}
+ value={planLabel(currentPlan.subscription)}
/>
)}
{currentPlan?.subscription?.isPaying && (