datewise/app/services/plans.ts
metatroncubeswdev 54734e8938 feat(billing): switch to Shopify managed pricing; show chosen time on thank-you page
App Store review 1.2.2 ("fails to register the plan"): follow Offerlyst's approved
managed-pricing setup. The plan is read from the Partner API on every app load,
shops without a plan (new install or reinstall) go to Shopify's plan selection
page, and app_subscriptions/update keeps it in sync. Billing API code removed.

Reviewer's checkout video: Shopify's checkout shows pickup by location name, so
the delivery label rename never reached the shopper. New checkout-time extension
shows the chosen date and time on the thank-you page (all plans) and next to
pickup/shipping options (Plus). Checkout display copy now matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:52:00 -05:00

41 lines
2.0 KiB
TypeScript

/**
* Feature gates per billing plan. "free" = Starter or no active subscription.
* Prices live in the Partner Dashboard (managed pricing); keep plan handles and copy in sync with it.
*/
export interface Features {
maxLocations: number;
monthlyBookings: number | null;
productRules: boolean;
inventoryAware: boolean;
peakDays: boolean;
waitlist: boolean;
freshness: boolean;
smsWhatsapp: boolean;
runSheets: boolean;
drivingDistance: boolean;
}
const PLANS: Record<string, Features> = {
free: { maxLocations: 1, monthlyBookings: 50, productRules: true, inventoryAware: false, peakDays: false, waitlist: false, freshness: false, smsWhatsapp: false, runSheets: false, drivingDistance: false },
Growth: { maxLocations: 3, monthlyBookings: null, productRules: true, inventoryAware: true, peakDays: true, waitlist: true, freshness: true, smsWhatsapp: false, runSheets: true, drivingDistance: false },
Pro: { maxLocations: 50, monthlyBookings: null, productRules: true, inventoryAware: true, peakDays: true, waitlist: true, freshness: true, smsWhatsapp: true, runSheets: true, drivingDistance: true },
};
export function features(plan: string): Features {
return PLANS[plan] ?? PLANS.free;
}
/** Maps managed-pricing plan handles or names (Partner Dashboard: starter / growth / pro) to a plan key. */
export function planFromSubscription(text: string | null | undefined): string {
const n = (text || "").toLowerCase();
if (n.includes("pro")) return "Pro";
if (n.includes("growth")) return "Growth";
return "free";
}
export const PLAN_COPY = [
{ id: "free", name: "Starter", price: "Free", points: ["1 location", "50 scheduled orders a month", "Capacity holds and cutoffs", "Email reminders"] },
{ id: "Growth", name: "Growth", price: "$19/month", points: ["Up to 3 locations", "Unlimited orders", "Festival rush control and waitlist", "Fresh-stock windows", "Driver run sheets"] },
{ id: "Pro", name: "Pro", price: "$49/month", points: ["Up to 50 locations", "SMS and WhatsApp reminders", "Driving-distance zones", "Everything in Growth"] },
];