// Plans use Shopify managed pricing (brief §18): Shopify hosts the plan page, trials and proration. import type { HeadersFunction, LoaderFunctionArgs } from "react-router"; import { useLoaderData } from "react-router"; import { boundary } from "@shopify/shopify-app-react-router/server"; import { authenticate } from "../shopify.server"; import { syncShop } from "../lib/shop.server"; import { PLANS, planOf } from "../lib/plans"; export const loader = async ({ request }: LoaderFunctionArgs) => { const { admin, session } = await authenticate.admin(request); const shop = await syncShop(admin, session.shop); // refresh the plan from activeSubscriptions const store = session.shop.replace(".myshopify.com", ""); const handle = process.env.SHOPIFY_APP_HANDLE || "bundle-offers"; return { current: shop.planCode, pricingUrl: `https://admin.shopify.com/store/${store}/charges/${handle}/pricing_plans`, plans: Object.entries(PLANS).map(([code, p]) => ({ code, ...p, runningOffers: p.runningOffers === Infinity ? "Unlimited" : String(p.runningOffers) })), currentName: planOf(shop.planCode).name, }; }; export default function Plans() { const d = useLoaderData(); return ( Change plan You're on the {d.currentName} plan. Paid plans include a 14-day free trial; development stores are free. Plan Price Running offers Includes {d.plans.map((p) => ( {p.name}{p.code === d.current ? " (current)" : ""} {p.price} {p.runningOffers} {[ p.types.length === 3 ? "All bundle types" : "Fixed bundles", p.scheduling && "scheduling", p.homepage && "homepage strip", p.cartHints && "cart hints", p.templates && "festival templates", p.analytics && "analytics", p.markets && "market targeting", p.translations && "translations", p.monthlyOrders !== Infinity && `${p.monthlyOrders} bundle orders/month`, p.branding && "“Powered by” link", ].filter(Boolean).join(", ")} ))} ); } export const headers: HeadersFunction = (headersArgs) => boundary.headers(headersArgs);