@stackframe/react 2.8.67 → 2.8.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components-page/account-settings/payments/payments-panel.js +10 -10
- package/dist/components-page/account-settings/payments/payments-panel.js.map +1 -1
- package/dist/esm/components-page/account-settings/payments/payments-panel.js +10 -10
- package/dist/esm/components-page/account-settings/payments/payments-panel.js.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +127 -1
- package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +84 -7
- package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/common.js +7 -1
- package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/event-tracker.js +221 -0
- package/dist/esm/lib/stack-app/apps/implementations/event-tracker.js.map +1 -0
- package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +33 -4
- package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/session-replay.js +221 -0
- package/dist/esm/lib/stack-app/apps/implementations/session-replay.js.map +1 -0
- package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/esm/lib/stack-app/index.js.map +1 -1
- package/dist/esm/lib/stack-app/projects/index.js.map +1 -1
- package/dist/esm/lib/stack-app/session-replays/index.js +1 -0
- package/dist/esm/lib/stack-app/session-replays/index.js.map +1 -0
- package/dist/esm/lib/stack-app/teams/index.js.map +1 -1
- package/dist/esm/lib/stack-app/users/index.js.map +1 -1
- package/dist/index.d.mts +240 -17
- package/dist/index.d.ts +240 -17
- package/dist/index.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +127 -1
- package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/client-app-impl.js +83 -6
- package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/common.js +9 -1
- package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/event-tracker.js +246 -0
- package/dist/lib/stack-app/apps/implementations/event-tracker.js.map +1 -0
- package/dist/lib/stack-app/apps/implementations/server-app-impl.js +33 -4
- package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/session-replay.js +262 -0
- package/dist/lib/stack-app/apps/implementations/session-replay.js.map +1 -0
- package/dist/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/lib/stack-app/customers/index.js.map +1 -1
- package/dist/lib/stack-app/email/index.js.map +1 -1
- package/dist/lib/stack-app/index.js.map +1 -1
- package/dist/lib/stack-app/projects/index.js.map +1 -1
- package/dist/lib/stack-app/session-replays/index.js +19 -0
- package/dist/lib/stack-app/session-replays/index.js.map +1 -0
- package/dist/lib/stack-app/teams/index.js.map +1 -1
- package/dist/lib/stack-app/users/index.js.map +1 -1
- package/package.json +4 -3
|
@@ -192,7 +192,7 @@ function RealPaymentsPanel(props) {
|
|
|
192
192
|
const [paymentDialogOpen, setPaymentDialogOpen] = (0, import_react.useState)(false);
|
|
193
193
|
const [setupIntentClientSecret, setSetupIntentClientSecret] = (0, import_react.useState)(null);
|
|
194
194
|
const [setupIntentStripeAccountId, setSetupIntentStripeAccountId] = (0, import_react.useState)(null);
|
|
195
|
-
const [
|
|
195
|
+
const [cancelTarget, setCancelTarget] = (0, import_react.useState)(null);
|
|
196
196
|
const [switchFromProductId, setSwitchFromProductId] = (0, import_react.useState)(null);
|
|
197
197
|
const [switchToProductId, setSwitchToProductId] = (0, import_react.useState)(null);
|
|
198
198
|
const stripePromise = (0, import_react.useMemo)(() => {
|
|
@@ -294,7 +294,7 @@ ${error}`);
|
|
|
294
294
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-3", children: productsForCustomerType.map((product, index) => {
|
|
295
295
|
const quantitySuffix = product.quantity !== 1 ? ` \xD7${product.quantity}` : "";
|
|
296
296
|
const isSubscription = product.type === "subscription";
|
|
297
|
-
const isCancelable = isSubscription && !!product.
|
|
297
|
+
const isCancelable = isSubscription && !!product.subscription?.isCancelable;
|
|
298
298
|
const canSwitchPlans = isSubscription && defaultPaymentMethod && !!product.id && (product.switchOptions?.length ?? 0) > 0;
|
|
299
299
|
const renewsAt = isSubscription ? product.subscription?.currentPeriodEnd ?? null : null;
|
|
300
300
|
const subtitle = product.type === "one_time" ? t("One-time purchase") : renewsAt ? `${t("Renews on")} ${new Intl.DateTimeFormat(void 0, { year: "numeric", month: "short", day: "numeric" }).format(renewsAt)}` : t("Subscription");
|
|
@@ -321,7 +321,7 @@ ${error}`);
|
|
|
321
321
|
{
|
|
322
322
|
variant: "secondary",
|
|
323
323
|
color: "neutral",
|
|
324
|
-
onClick: () =>
|
|
324
|
+
onClick: () => setCancelTarget({ productId: product.id ?? "_inline", subscriptionId: product.subscription?.subscriptionId ?? void 0 }),
|
|
325
325
|
children: t("Cancel subscription")
|
|
326
326
|
}
|
|
327
327
|
)
|
|
@@ -331,9 +331,9 @@ ${error}`);
|
|
|
331
331
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
332
332
|
import_stack_ui.ActionDialog,
|
|
333
333
|
{
|
|
334
|
-
open:
|
|
334
|
+
open: cancelTarget !== null,
|
|
335
335
|
onOpenChange: (open) => {
|
|
336
|
-
if (!open)
|
|
336
|
+
if (!open) setCancelTarget(null);
|
|
337
337
|
},
|
|
338
338
|
title: t("Cancel subscription"),
|
|
339
339
|
description: t("Canceling will stop future renewals for this subscription."),
|
|
@@ -342,14 +342,14 @@ ${error}`);
|
|
|
342
342
|
okButton: {
|
|
343
343
|
label: t("Cancel subscription"),
|
|
344
344
|
onClick: async () => {
|
|
345
|
-
|
|
346
|
-
|
|
345
|
+
if (!cancelTarget) return;
|
|
346
|
+
const { productId, subscriptionId } = cancelTarget;
|
|
347
347
|
if (props.customerType === "team") {
|
|
348
|
-
await stackApp.cancelSubscription({ teamId: props.customer.id, productId });
|
|
348
|
+
await stackApp.cancelSubscription({ teamId: props.customer.id, productId, subscriptionId });
|
|
349
349
|
} else {
|
|
350
|
-
await stackApp.cancelSubscription({ productId });
|
|
350
|
+
await stackApp.cancelSubscription({ productId, subscriptionId });
|
|
351
351
|
}
|
|
352
|
-
|
|
352
|
+
setCancelTarget(null);
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
355
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components-page/account-settings/payments/payments-panel.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { runAsynchronously } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { ActionDialog, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, toast, Typography } from \"@stackframe/stack-ui\";\nimport { CardElement, Elements, useElements, useStripe } from \"@stripe/react-stripe-js\";\nimport { loadStripe } from \"@stripe/stripe-js\";\nimport { useMemo, useState } from \"react\";\nimport { useStackApp } from \"../../..\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { Section } from \"../section\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport type { CustomerInvoiceStatus, CustomerInvoicesList, CustomerInvoicesListOptions } from \"../../../lib/stack-app/customers\";\n\ntype PaymentMethodSummary = {\n id: string,\n brand: string | null,\n last4: string | null,\n exp_month: number | null,\n exp_year: number | null,\n} | null;\n\nfunction formatPaymentMethod(pm: NonNullable<PaymentMethodSummary>) {\n const details = [\n pm.brand ? pm.brand.toUpperCase() : null,\n pm.last4 ? `•••• ${pm.last4}` : null,\n pm.exp_month && pm.exp_year ? `exp ${pm.exp_month}/${pm.exp_year}` : null,\n ].filter(Boolean);\n return details.join(\" · \");\n}\n\nconst formatInvoiceStatus = (status: CustomerInvoiceStatus, t: (value: string) => string) => {\n if (!status) {\n return t(\"Unknown\");\n }\n switch (status) {\n case \"draft\": {\n return t(\"Draft\");\n }\n case \"open\": {\n return t(\"Open\");\n }\n case \"paid\": {\n return t(\"Paid\");\n }\n case \"uncollectible\": {\n return t(\"Uncollectible\");\n }\n case \"void\": {\n return t(\"Void\");\n }\n default: {\n return t(\"Unknown\");\n }\n }\n};\n\nconst formatInvoiceAmount = (amountTotal: number | null | undefined, t: (value: string) => string) => {\n if (typeof amountTotal !== \"number\" || Number.isNaN(amountTotal)) {\n return t(\"Unknown\");\n }\n const normalized = amountTotal / 100;\n const formatted = new Intl.NumberFormat(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(normalized);\n return `$${formatted}`;\n};\n\nconst formatInvoiceDate = (date: Date | null | undefined, t: (value: string) => string) => {\n if (!date || Number.isNaN(date.getTime())) {\n return t(\"Unknown\");\n }\n return new Intl.DateTimeFormat(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" }).format(date);\n};\n\ntype CustomerBilling = {\n hasCustomer: boolean,\n defaultPaymentMethod: PaymentMethodSummary,\n};\n\ntype CustomerPaymentMethodSetupIntent = {\n clientSecret: string,\n stripeAccountId: string,\n};\n\ntype CustomerLike = {\n id: string,\n useBilling: () => CustomerBilling,\n useProducts: () => Array<{\n id: string | null,\n quantity: number,\n displayName: string,\n customerType: \"user\" | \"team\" | \"custom\",\n type: \"one_time\" | \"subscription\",\n switchOptions?: Array<{\n productId: string,\n displayName: string,\n prices: Record<string, { interval?: [number, \"day\" | \"week\" | \"month\" | \"year\"] }>,\n }>,\n subscription: null | {\n currentPeriodEnd: Date | null,\n cancelAtPeriodEnd: boolean,\n isCancelable: boolean,\n },\n }>,\n useInvoices: (options?: CustomerInvoicesListOptions) => CustomerInvoicesList,\n createPaymentMethodSetupIntent: () => Promise<CustomerPaymentMethodSetupIntent>,\n setDefaultPaymentMethodFromSetupIntent: (setupIntentId: string) => Promise<PaymentMethodSummary>,\n switchSubscription: (options: { fromProductId: string, toProductId: string, priceId?: string, quantity?: number }) => Promise<void>,\n};\n\nfunction SetDefaultPaymentMethodForm(props: {\n clientSecret: string,\n onSetupIntentSucceeded: (setupIntentId: string) => Promise<void>,\n}) {\n const stripe = useStripe();\n const elements = useElements();\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const darkMode = \"color-scheme\" in document.documentElement.style && document.documentElement.style[\"color-scheme\"] === \"dark\";\n\n return (\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Typography className=\"font-medium\">Card details</Typography>\n <div className=\"rounded-md border border-input p-3\">\n <CardElement options={{ hidePostalCode: true, style: { base: { color: darkMode ? \"white\" : \"black\" } } }} />\n </div>\n </div>\n {errorMessage && (\n <Typography variant=\"secondary\" type=\"footnote\">\n {errorMessage}\n </Typography>\n )}\n <Button\n onClick={async () => {\n if (!stripe || !elements) {\n setErrorMessage(\"Stripe is still loading. Please try again.\");\n return;\n }\n const card = elements.getElement(CardElement);\n if (!card) {\n setErrorMessage(\"Card element not found.\");\n return;\n }\n\n const result = await stripe.confirmCardSetup(props.clientSecret, {\n payment_method: { card },\n });\n if (result.error) {\n setErrorMessage(result.error.message ?? \"Failed to save payment method.\");\n return;\n }\n if (!result.setupIntent.id) {\n setErrorMessage(\"No setup intent returned from Stripe.\");\n return;\n }\n await props.onSetupIntentSucceeded(result.setupIntent.id);\n }}\n >\n Save payment method\n </Button>\n </div>\n );\n}\n\nexport function PaymentsPanel(props: {\n title?: string,\n customer?: CustomerLike,\n customerType?: \"user\" | \"team\",\n mockMode?: boolean,\n}) {\n if (props.mockMode) {\n return <MockPaymentsPanel title={props.title} />;\n }\n if (!props.customer) {\n return null;\n }\n return <RealPaymentsPanel title={props.title} customer={props.customer} customerType={props.customerType ?? \"user\"} />;\n}\n\nfunction MockPaymentsPanel(props: { title?: string }) {\n const { t } = useTranslation();\n const defaultPaymentMethod: PaymentMethodSummary = {\n id: \"pm_mock\",\n brand: \"visa\",\n last4: \"4242\",\n exp_month: 12,\n exp_year: 2030,\n };\n\n return (\n <div className=\"space-y-4\">\n {props.title && <Typography className=\"font-medium\">{props.title}</Typography>}\n <Section\n title={t(\"Payment method\")}\n description={t(\"Manage the default payment method used for subscriptions and invoices.\")}\n >\n <Typography>{formatPaymentMethod(defaultPaymentMethod)}</Typography>\n <Button disabled>\n {t(\"Update payment method\")}\n </Button>\n </Section>\n\n <Section\n title={t(\"Active plans\")}\n description={t(\"View your active plans and purchases.\")}\n >\n <div className=\"space-y-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{t(\"Pro\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"Renews on\")} Jan 1, 2030</Typography>\n </div>\n <Button disabled variant=\"secondary\" color=\"neutral\">\n {t(\"Cancel subscription\")}\n </Button>\n </div>\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{t(\"Credits pack\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"One-time purchase\")}</Typography>\n </div>\n </div>\n </div>\n </Section>\n </div>\n );\n}\n\nfunction RealPaymentsPanel(props: { title?: string, customer: CustomerLike, customerType: \"user\" | \"team\" }) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const billing = props.customer.useBilling();\n const defaultPaymentMethod = billing.defaultPaymentMethod;\n const products = props.customer.useProducts();\n const invoices = props.customer.useInvoices({ limit: 10 });\n const productsForCustomerType = products.filter(product => product.customerType === props.customerType);\n\n const [paymentDialogOpen, setPaymentDialogOpen] = useState(false);\n const [setupIntentClientSecret, setSetupIntentClientSecret] = useState<string | null>(null);\n const [setupIntentStripeAccountId, setSetupIntentStripeAccountId] = useState<string | null>(null);\n const [cancelProductId, setCancelProductId] = useState<string | null>(null);\n const [switchFromProductId, setSwitchFromProductId] = useState<string | null>(null);\n const [switchToProductId, setSwitchToProductId] = useState<string | null>(null);\n\n const stripePromise = useMemo(() => {\n if (!setupIntentStripeAccountId) return null;\n const publishableKey = process.env.NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY;\n if (!publishableKey) return null;\n return loadStripe(publishableKey, { stripeAccount: setupIntentStripeAccountId });\n }, [setupIntentStripeAccountId]);\n\n const handleAsyncError = (error: unknown) => {\n if (error instanceof KnownErrors.DefaultPaymentMethodRequired) {\n toast({\n title: t(\"No default payment method\"),\n description: t(\"Add a payment method before switching plans.\"),\n variant: \"destructive\",\n });\n return;\n }\n alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === \"development\" ? \"check the browser console for the full error.\" : \"report this to the developer.\"}\\n\\n${error}`);\n };\n\n const openPaymentDialog = () => {\n runAsynchronously(async () => {\n setPaymentDialogOpen(true);\n const res = await props.customer.createPaymentMethodSetupIntent();\n setSetupIntentClientSecret(res.clientSecret);\n setSetupIntentStripeAccountId(res.stripeAccountId);\n }, { onError: handleAsyncError });\n };\n\n const closePaymentDialog = () => {\n setPaymentDialogOpen(false);\n setSetupIntentClientSecret(null);\n setSetupIntentStripeAccountId(null);\n };\n\n const openSwitchDialog = (productId: string, firstOptionId: string | null) => {\n setSwitchFromProductId(productId);\n setSwitchToProductId(firstOptionId);\n };\n\n const closeSwitchDialog = () => {\n setSwitchFromProductId(null);\n setSwitchToProductId(null);\n };\n\n const switchSourceProduct = switchFromProductId\n ? productsForCustomerType.find((product) => product.id === switchFromProductId) ?? null\n : null;\n const switchOptions = switchSourceProduct?.switchOptions ?? [];\n const selectedSwitchOption = switchOptions.find((option) => option.productId === switchToProductId) ?? null;\n const selectedPriceId = selectedSwitchOption ? (Object.keys(selectedSwitchOption.prices)[0] ?? null) : null;\n\n return (\n <div className=\"space-y-4\">\n {props.title && <Typography className=\"font-medium\">{props.title}</Typography>}\n\n {defaultPaymentMethod && (\n <Section\n title={t(\"Payment method\")}\n description={t(\"Manage the default payment method used for subscriptions and invoices.\")}\n >\n <Typography>{formatPaymentMethod(defaultPaymentMethod)}</Typography>\n\n <Button onClick={openPaymentDialog}>\n {t(\"Update payment method\")}\n </Button>\n\n <ActionDialog\n open={paymentDialogOpen}\n onOpenChange={(open) => {\n if (!open) {\n closePaymentDialog();\n } else {\n setPaymentDialogOpen(true);\n }\n }}\n title={t(\"Update payment method\")}\n >\n {!setupIntentClientSecret || !setupIntentStripeAccountId || !stripePromise ? (\n <Skeleton className=\"h-10 w-full\" />\n ) : (\n <Elements\n stripe={stripePromise}\n options={{\n clientSecret: setupIntentClientSecret,\n }}\n >\n <SetDefaultPaymentMethodForm\n clientSecret={setupIntentClientSecret}\n onSetupIntentSucceeded={async (setupIntentId) => {\n await props.customer.setDefaultPaymentMethodFromSetupIntent(setupIntentId);\n closePaymentDialog();\n }}\n />\n </Elements>\n )}\n </ActionDialog>\n </Section>\n )}\n\n {productsForCustomerType.length > 0 && (\n <Section\n title={t(\"Active plans\")}\n description={t(\"View your active plans and purchases.\")}\n >\n <div className=\"space-y-3\">\n {productsForCustomerType.map((product, index) => {\n const quantitySuffix = product.quantity !== 1 ? ` ×${product.quantity}` : \"\";\n const isSubscription = product.type === \"subscription\";\n const isCancelable = isSubscription && !!product.id && !!product.subscription?.isCancelable;\n const canSwitchPlans = isSubscription && defaultPaymentMethod && !!product.id && (product.switchOptions?.length ?? 0) > 0;\n const renewsAt = isSubscription ? (product.subscription?.currentPeriodEnd ?? null) : null;\n\n const subtitle =\n product.type === \"one_time\"\n ? t(\"One-time purchase\")\n : renewsAt\n ? `${t(\"Renews on\")} ${new Intl.DateTimeFormat(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" }).format(renewsAt)}`\n : t(\"Subscription\");\n\n return (\n <div key={product.id ?? `${product.displayName}-${index}`} className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{product.displayName}{quantitySuffix}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{subtitle}</Typography>\n </div>\n\n <div className=\"flex flex-col items-end gap-2\">\n {canSwitchPlans && (\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n onClick={() => openSwitchDialog(product.id!, product.switchOptions?.[0]?.productId ?? null)}\n >\n {t(\"Change plan\")}\n </Button>\n )}\n {isCancelable && (\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n onClick={() => setCancelProductId(product.id)}\n >\n {t(\"Cancel subscription\")}\n </Button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n\n <ActionDialog\n open={cancelProductId !== null}\n onOpenChange={(open) => {\n if (!open) setCancelProductId(null);\n }}\n title={t(\"Cancel subscription\")}\n description={t(\"Canceling will stop future renewals for this subscription.\")}\n danger\n cancelButton\n okButton={{\n label: t(\"Cancel subscription\"),\n onClick: async () => {\n const productId = cancelProductId;\n if (!productId) return;\n if (props.customerType === \"team\") {\n await stackApp.cancelSubscription({ teamId: props.customer.id, productId });\n } else {\n await stackApp.cancelSubscription({ productId });\n }\n setCancelProductId(null);\n },\n }}\n />\n\n <ActionDialog\n open={switchFromProductId !== null}\n onOpenChange={(open) => {\n if (!open) closeSwitchDialog();\n }}\n title={t(\"Change plan\")}\n description={t(\"Select a new plan from the same product line.\")}\n cancelButton\n okButton={{\n label: t(\"Switch plan\"),\n onClick: async () => {\n const fromProductId = switchFromProductId;\n const toProductId = switchToProductId;\n if (!fromProductId || !toProductId) return;\n if (!selectedPriceId) return;\n const result = await Result.fromThrowingAsync(() => props.customer.switchSubscription({\n fromProductId,\n toProductId,\n priceId: selectedPriceId,\n }));\n if (result.status === \"error\") {\n handleAsyncError(result.error);\n return \"prevent-close\";\n }\n closeSwitchDialog();\n },\n props: {\n disabled: !switchFromProductId || !switchToProductId || !selectedPriceId,\n },\n }}\n >\n <div className=\"space-y-2\">\n {switchOptions.length === 0 ? (\n <Typography variant=\"secondary\" type=\"footnote\">\n {t(\"No other plans available for this subscription.\")}\n </Typography>\n ) : (\n <>\n <Typography type=\"footnote\">{t(\"Choose a plan\")}</Typography>\n <Select\n value={switchToProductId ?? undefined}\n onValueChange={(value) => setSwitchToProductId(value || null)}\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder={t(\"Choose a plan\")} />\n </SelectTrigger>\n <SelectContent>\n {switchOptions.map((option: NonNullable<typeof switchOptions>[number]) => (\n <SelectItem key={option.productId} value={option.productId}>\n {option.displayName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )}\n </div>\n </ActionDialog>\n </Section>\n )\n }\n {invoices.length > 0 && (\n <>\n <Separator />\n <div className=\"space-y-2\">\n <div className=\"space-y-1\">\n <Typography className=\"font-medium\">{t(\"Invoices\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"Review past invoices and receipts.\")}</Typography>\n </div>\n <div className=\"border rounded-md\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[140px]\">{t(\"Date\")}</TableHead>\n <TableHead className=\"w-[120px]\">{t(\"Status\")}</TableHead>\n <TableHead className=\"w-[120px]\">{t(\"Amount\")}</TableHead>\n <TableHead className=\"w-[120px] text-right\">{t(\"Invoice\")}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {invoices.map((invoice, index) => {\n const createdAtTime = invoice.createdAt.getTime();\n const invoiceKey = Number.isNaN(createdAtTime) ? `invoice-${index}` : `invoice-${createdAtTime}-${index}`;\n return (\n <TableRow key={invoiceKey}>\n <TableCell>\n <Typography>{formatInvoiceDate(invoice.createdAt, t)}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{formatInvoiceStatus(invoice.status, t)}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{formatInvoiceAmount(invoice.amountTotal, t)}</Typography>\n </TableCell>\n <TableCell align=\"right\">\n {invoice.hostedInvoiceUrl ? (\n <Button asChild variant=\"secondary\" color=\"neutral\" size=\"sm\">\n <a href={invoice.hostedInvoiceUrl} target=\"_blank\" rel=\"noreferrer\">\n {t(\"View\")}\n </a>\n </Button>\n ) : (\n <Typography variant=\"secondary\" type=\"footnote\">\n {t(\"Unavailable\")}\n </Typography>\n )}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n </div>\n </>\n )}\n </div >\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components-page/account-settings/payments/payments-panel.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { runAsynchronously } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { ActionDialog, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, toast, Typography } from \"@stackframe/stack-ui\";\nimport { CardElement, Elements, useElements, useStripe } from \"@stripe/react-stripe-js\";\nimport { loadStripe } from \"@stripe/stripe-js\";\nimport { useMemo, useState } from \"react\";\nimport { useStackApp } from \"../../..\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { Section } from \"../section\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport type { CustomerInvoiceStatus, CustomerInvoicesList, CustomerInvoicesListOptions } from \"../../../lib/stack-app/customers\";\n\ntype PaymentMethodSummary = {\n id: string,\n brand: string | null,\n last4: string | null,\n exp_month: number | null,\n exp_year: number | null,\n} | null;\n\nfunction formatPaymentMethod(pm: NonNullable<PaymentMethodSummary>) {\n const details = [\n pm.brand ? pm.brand.toUpperCase() : null,\n pm.last4 ? `•••• ${pm.last4}` : null,\n pm.exp_month && pm.exp_year ? `exp ${pm.exp_month}/${pm.exp_year}` : null,\n ].filter(Boolean);\n return details.join(\" · \");\n}\n\nconst formatInvoiceStatus = (status: CustomerInvoiceStatus, t: (value: string) => string) => {\n if (!status) {\n return t(\"Unknown\");\n }\n switch (status) {\n case \"draft\": {\n return t(\"Draft\");\n }\n case \"open\": {\n return t(\"Open\");\n }\n case \"paid\": {\n return t(\"Paid\");\n }\n case \"uncollectible\": {\n return t(\"Uncollectible\");\n }\n case \"void\": {\n return t(\"Void\");\n }\n default: {\n return t(\"Unknown\");\n }\n }\n};\n\nconst formatInvoiceAmount = (amountTotal: number | null | undefined, t: (value: string) => string) => {\n if (typeof amountTotal !== \"number\" || Number.isNaN(amountTotal)) {\n return t(\"Unknown\");\n }\n const normalized = amountTotal / 100;\n const formatted = new Intl.NumberFormat(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(normalized);\n return `$${formatted}`;\n};\n\nconst formatInvoiceDate = (date: Date | null | undefined, t: (value: string) => string) => {\n if (!date || Number.isNaN(date.getTime())) {\n return t(\"Unknown\");\n }\n return new Intl.DateTimeFormat(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" }).format(date);\n};\n\ntype CustomerBilling = {\n hasCustomer: boolean,\n defaultPaymentMethod: PaymentMethodSummary,\n};\n\ntype CustomerPaymentMethodSetupIntent = {\n clientSecret: string,\n stripeAccountId: string,\n};\n\ntype CustomerLike = {\n id: string,\n useBilling: () => CustomerBilling,\n useProducts: () => Array<{\n id: string | null,\n quantity: number,\n displayName: string,\n customerType: \"user\" | \"team\" | \"custom\",\n type: \"one_time\" | \"subscription\",\n switchOptions?: Array<{\n productId: string,\n displayName: string,\n prices: Record<string, { interval?: [number, \"day\" | \"week\" | \"month\" | \"year\"] }>,\n }>,\n subscription: null | {\n subscriptionId: string | null,\n currentPeriodEnd: Date | null,\n cancelAtPeriodEnd: boolean,\n isCancelable: boolean,\n },\n }>,\n useInvoices: (options?: CustomerInvoicesListOptions) => CustomerInvoicesList,\n createPaymentMethodSetupIntent: () => Promise<CustomerPaymentMethodSetupIntent>,\n setDefaultPaymentMethodFromSetupIntent: (setupIntentId: string) => Promise<PaymentMethodSummary>,\n switchSubscription: (options: { fromProductId: string, toProductId: string, priceId?: string, quantity?: number }) => Promise<void>,\n};\n\nfunction SetDefaultPaymentMethodForm(props: {\n clientSecret: string,\n onSetupIntentSucceeded: (setupIntentId: string) => Promise<void>,\n}) {\n const stripe = useStripe();\n const elements = useElements();\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const darkMode = \"color-scheme\" in document.documentElement.style && document.documentElement.style[\"color-scheme\"] === \"dark\";\n\n return (\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Typography className=\"font-medium\">Card details</Typography>\n <div className=\"rounded-md border border-input p-3\">\n <CardElement options={{ hidePostalCode: true, style: { base: { color: darkMode ? \"white\" : \"black\" } } }} />\n </div>\n </div>\n {errorMessage && (\n <Typography variant=\"secondary\" type=\"footnote\">\n {errorMessage}\n </Typography>\n )}\n <Button\n onClick={async () => {\n if (!stripe || !elements) {\n setErrorMessage(\"Stripe is still loading. Please try again.\");\n return;\n }\n const card = elements.getElement(CardElement);\n if (!card) {\n setErrorMessage(\"Card element not found.\");\n return;\n }\n\n const result = await stripe.confirmCardSetup(props.clientSecret, {\n payment_method: { card },\n });\n if (result.error) {\n setErrorMessage(result.error.message ?? \"Failed to save payment method.\");\n return;\n }\n if (!result.setupIntent.id) {\n setErrorMessage(\"No setup intent returned from Stripe.\");\n return;\n }\n await props.onSetupIntentSucceeded(result.setupIntent.id);\n }}\n >\n Save payment method\n </Button>\n </div>\n );\n}\n\nexport function PaymentsPanel(props: {\n title?: string,\n customer?: CustomerLike,\n customerType?: \"user\" | \"team\",\n mockMode?: boolean,\n}) {\n if (props.mockMode) {\n return <MockPaymentsPanel title={props.title} />;\n }\n if (!props.customer) {\n return null;\n }\n return <RealPaymentsPanel title={props.title} customer={props.customer} customerType={props.customerType ?? \"user\"} />;\n}\n\nfunction MockPaymentsPanel(props: { title?: string }) {\n const { t } = useTranslation();\n const defaultPaymentMethod: PaymentMethodSummary = {\n id: \"pm_mock\",\n brand: \"visa\",\n last4: \"4242\",\n exp_month: 12,\n exp_year: 2030,\n };\n\n return (\n <div className=\"space-y-4\">\n {props.title && <Typography className=\"font-medium\">{props.title}</Typography>}\n <Section\n title={t(\"Payment method\")}\n description={t(\"Manage the default payment method used for subscriptions and invoices.\")}\n >\n <Typography>{formatPaymentMethod(defaultPaymentMethod)}</Typography>\n <Button disabled>\n {t(\"Update payment method\")}\n </Button>\n </Section>\n\n <Section\n title={t(\"Active plans\")}\n description={t(\"View your active plans and purchases.\")}\n >\n <div className=\"space-y-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{t(\"Pro\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"Renews on\")} Jan 1, 2030</Typography>\n </div>\n <Button disabled variant=\"secondary\" color=\"neutral\">\n {t(\"Cancel subscription\")}\n </Button>\n </div>\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{t(\"Credits pack\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"One-time purchase\")}</Typography>\n </div>\n </div>\n </div>\n </Section>\n </div>\n );\n}\n\nfunction RealPaymentsPanel(props: { title?: string, customer: CustomerLike, customerType: \"user\" | \"team\" }) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const billing = props.customer.useBilling();\n const defaultPaymentMethod = billing.defaultPaymentMethod;\n const products = props.customer.useProducts();\n const invoices = props.customer.useInvoices({ limit: 10 });\n const productsForCustomerType = products.filter(product => product.customerType === props.customerType);\n\n const [paymentDialogOpen, setPaymentDialogOpen] = useState(false);\n const [setupIntentClientSecret, setSetupIntentClientSecret] = useState<string | null>(null);\n const [setupIntentStripeAccountId, setSetupIntentStripeAccountId] = useState<string | null>(null);\n const [cancelTarget, setCancelTarget] = useState<{ productId: string, subscriptionId?: string } | null>(null);\n const [switchFromProductId, setSwitchFromProductId] = useState<string | null>(null);\n const [switchToProductId, setSwitchToProductId] = useState<string | null>(null);\n\n const stripePromise = useMemo(() => {\n if (!setupIntentStripeAccountId) return null;\n const publishableKey = process.env.NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY;\n if (!publishableKey) return null;\n return loadStripe(publishableKey, { stripeAccount: setupIntentStripeAccountId });\n }, [setupIntentStripeAccountId]);\n\n const handleAsyncError = (error: unknown) => {\n if (error instanceof KnownErrors.DefaultPaymentMethodRequired) {\n toast({\n title: t(\"No default payment method\"),\n description: t(\"Add a payment method before switching plans.\"),\n variant: \"destructive\",\n });\n return;\n }\n alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === \"development\" ? \"check the browser console for the full error.\" : \"report this to the developer.\"}\\n\\n${error}`);\n };\n\n const openPaymentDialog = () => {\n runAsynchronously(async () => {\n setPaymentDialogOpen(true);\n const res = await props.customer.createPaymentMethodSetupIntent();\n setSetupIntentClientSecret(res.clientSecret);\n setSetupIntentStripeAccountId(res.stripeAccountId);\n }, { onError: handleAsyncError });\n };\n\n const closePaymentDialog = () => {\n setPaymentDialogOpen(false);\n setSetupIntentClientSecret(null);\n setSetupIntentStripeAccountId(null);\n };\n\n const openSwitchDialog = (productId: string, firstOptionId: string | null) => {\n setSwitchFromProductId(productId);\n setSwitchToProductId(firstOptionId);\n };\n\n const closeSwitchDialog = () => {\n setSwitchFromProductId(null);\n setSwitchToProductId(null);\n };\n\n const switchSourceProduct = switchFromProductId\n ? productsForCustomerType.find((product) => product.id === switchFromProductId) ?? null\n : null;\n const switchOptions = switchSourceProduct?.switchOptions ?? [];\n const selectedSwitchOption = switchOptions.find((option) => option.productId === switchToProductId) ?? null;\n const selectedPriceId = selectedSwitchOption ? (Object.keys(selectedSwitchOption.prices)[0] ?? null) : null;\n\n return (\n <div className=\"space-y-4\">\n {props.title && <Typography className=\"font-medium\">{props.title}</Typography>}\n\n {defaultPaymentMethod && (\n <Section\n title={t(\"Payment method\")}\n description={t(\"Manage the default payment method used for subscriptions and invoices.\")}\n >\n <Typography>{formatPaymentMethod(defaultPaymentMethod)}</Typography>\n\n <Button onClick={openPaymentDialog}>\n {t(\"Update payment method\")}\n </Button>\n\n <ActionDialog\n open={paymentDialogOpen}\n onOpenChange={(open) => {\n if (!open) {\n closePaymentDialog();\n } else {\n setPaymentDialogOpen(true);\n }\n }}\n title={t(\"Update payment method\")}\n >\n {!setupIntentClientSecret || !setupIntentStripeAccountId || !stripePromise ? (\n <Skeleton className=\"h-10 w-full\" />\n ) : (\n <Elements\n stripe={stripePromise}\n options={{\n clientSecret: setupIntentClientSecret,\n }}\n >\n <SetDefaultPaymentMethodForm\n clientSecret={setupIntentClientSecret}\n onSetupIntentSucceeded={async (setupIntentId) => {\n await props.customer.setDefaultPaymentMethodFromSetupIntent(setupIntentId);\n closePaymentDialog();\n }}\n />\n </Elements>\n )}\n </ActionDialog>\n </Section>\n )}\n\n {productsForCustomerType.length > 0 && (\n <Section\n title={t(\"Active plans\")}\n description={t(\"View your active plans and purchases.\")}\n >\n <div className=\"space-y-3\">\n {productsForCustomerType.map((product, index) => {\n const quantitySuffix = product.quantity !== 1 ? ` ×${product.quantity}` : \"\";\n const isSubscription = product.type === \"subscription\";\n const isCancelable = isSubscription && !!product.subscription?.isCancelable;\n const canSwitchPlans = isSubscription && defaultPaymentMethod && !!product.id && (product.switchOptions?.length ?? 0) > 0;\n const renewsAt = isSubscription ? (product.subscription?.currentPeriodEnd ?? null) : null;\n const subtitle =\n product.type === \"one_time\"\n ? t(\"One-time purchase\")\n : renewsAt\n ? `${t(\"Renews on\")} ${new Intl.DateTimeFormat(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" }).format(renewsAt)}`\n : t(\"Subscription\");\n\n return (\n <div key={product.id ?? `${product.displayName}-${index}`} className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{product.displayName}{quantitySuffix}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{subtitle}</Typography>\n </div>\n\n <div className=\"flex flex-col items-end gap-2\">\n {canSwitchPlans && (\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n onClick={() => openSwitchDialog(product.id!, product.switchOptions?.[0]?.productId ?? null)}\n >\n {t(\"Change plan\")}\n </Button>\n )}\n {isCancelable && (\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n onClick={() => setCancelTarget({ productId: product.id ?? \"_inline\", subscriptionId: product.subscription?.subscriptionId ?? undefined })}\n >\n {t(\"Cancel subscription\")}\n </Button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n\n <ActionDialog\n open={cancelTarget !== null}\n onOpenChange={(open) => {\n if (!open) setCancelTarget(null);\n }}\n title={t(\"Cancel subscription\")}\n description={t(\"Canceling will stop future renewals for this subscription.\")}\n danger\n cancelButton\n okButton={{\n label: t(\"Cancel subscription\"),\n onClick: async () => {\n if (!cancelTarget) return;\n const { productId, subscriptionId } = cancelTarget;\n if (props.customerType === \"team\") {\n await stackApp.cancelSubscription({ teamId: props.customer.id, productId, subscriptionId });\n } else {\n await stackApp.cancelSubscription({ productId, subscriptionId });\n }\n setCancelTarget(null);\n },\n }}\n />\n\n <ActionDialog\n open={switchFromProductId !== null}\n onOpenChange={(open) => {\n if (!open) closeSwitchDialog();\n }}\n title={t(\"Change plan\")}\n description={t(\"Select a new plan from the same product line.\")}\n cancelButton\n okButton={{\n label: t(\"Switch plan\"),\n onClick: async () => {\n const fromProductId = switchFromProductId;\n const toProductId = switchToProductId;\n if (!fromProductId || !toProductId) return;\n if (!selectedPriceId) return;\n const result = await Result.fromThrowingAsync(() => props.customer.switchSubscription({\n fromProductId,\n toProductId,\n priceId: selectedPriceId,\n }));\n if (result.status === \"error\") {\n handleAsyncError(result.error);\n return \"prevent-close\";\n }\n closeSwitchDialog();\n },\n props: {\n disabled: !switchFromProductId || !switchToProductId || !selectedPriceId,\n },\n }}\n >\n <div className=\"space-y-2\">\n {switchOptions.length === 0 ? (\n <Typography variant=\"secondary\" type=\"footnote\">\n {t(\"No other plans available for this subscription.\")}\n </Typography>\n ) : (\n <>\n <Typography type=\"footnote\">{t(\"Choose a plan\")}</Typography>\n <Select\n value={switchToProductId ?? undefined}\n onValueChange={(value) => setSwitchToProductId(value || null)}\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder={t(\"Choose a plan\")} />\n </SelectTrigger>\n <SelectContent>\n {switchOptions.map((option: NonNullable<typeof switchOptions>[number]) => (\n <SelectItem key={option.productId} value={option.productId}>\n {option.displayName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )}\n </div>\n </ActionDialog>\n </Section>\n )\n }\n {invoices.length > 0 && (\n <>\n <Separator />\n <div className=\"space-y-2\">\n <div className=\"space-y-1\">\n <Typography className=\"font-medium\">{t(\"Invoices\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"Review past invoices and receipts.\")}</Typography>\n </div>\n <div className=\"border rounded-md\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[140px]\">{t(\"Date\")}</TableHead>\n <TableHead className=\"w-[120px]\">{t(\"Status\")}</TableHead>\n <TableHead className=\"w-[120px]\">{t(\"Amount\")}</TableHead>\n <TableHead className=\"w-[120px] text-right\">{t(\"Invoice\")}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {invoices.map((invoice, index) => {\n const createdAtTime = invoice.createdAt.getTime();\n const invoiceKey = Number.isNaN(createdAtTime) ? `invoice-${index}` : `invoice-${createdAtTime}-${index}`;\n return (\n <TableRow key={invoiceKey}>\n <TableCell>\n <Typography>{formatInvoiceDate(invoice.createdAt, t)}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{formatInvoiceStatus(invoice.status, t)}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{formatInvoiceAmount(invoice.amountTotal, t)}</Typography>\n </TableCell>\n <TableCell align=\"right\">\n {invoice.hostedInvoiceUrl ? (\n <Button asChild variant=\"secondary\" color=\"neutral\" size=\"sm\">\n <a href={invoice.hostedInvoiceUrl} target=\"_blank\" rel=\"noreferrer\">\n {t(\"View\")}\n </a>\n </Button>\n ) : (\n <Typography variant=\"secondary\" type=\"footnote\">\n {t(\"Unavailable\")}\n </Typography>\n )}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n </div>\n </>\n )}\n </div >\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -169,7 +169,7 @@ function RealPaymentsPanel(props) {
|
|
|
169
169
|
const [paymentDialogOpen, setPaymentDialogOpen] = useState(false);
|
|
170
170
|
const [setupIntentClientSecret, setSetupIntentClientSecret] = useState(null);
|
|
171
171
|
const [setupIntentStripeAccountId, setSetupIntentStripeAccountId] = useState(null);
|
|
172
|
-
const [
|
|
172
|
+
const [cancelTarget, setCancelTarget] = useState(null);
|
|
173
173
|
const [switchFromProductId, setSwitchFromProductId] = useState(null);
|
|
174
174
|
const [switchToProductId, setSwitchToProductId] = useState(null);
|
|
175
175
|
const stripePromise = useMemo(() => {
|
|
@@ -271,7 +271,7 @@ ${error}`);
|
|
|
271
271
|
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: productsForCustomerType.map((product, index) => {
|
|
272
272
|
const quantitySuffix = product.quantity !== 1 ? ` \xD7${product.quantity}` : "";
|
|
273
273
|
const isSubscription = product.type === "subscription";
|
|
274
|
-
const isCancelable = isSubscription && !!product.
|
|
274
|
+
const isCancelable = isSubscription && !!product.subscription?.isCancelable;
|
|
275
275
|
const canSwitchPlans = isSubscription && defaultPaymentMethod && !!product.id && (product.switchOptions?.length ?? 0) > 0;
|
|
276
276
|
const renewsAt = isSubscription ? product.subscription?.currentPeriodEnd ?? null : null;
|
|
277
277
|
const subtitle = product.type === "one_time" ? t("One-time purchase") : renewsAt ? `${t("Renews on")} ${new Intl.DateTimeFormat(void 0, { year: "numeric", month: "short", day: "numeric" }).format(renewsAt)}` : t("Subscription");
|
|
@@ -298,7 +298,7 @@ ${error}`);
|
|
|
298
298
|
{
|
|
299
299
|
variant: "secondary",
|
|
300
300
|
color: "neutral",
|
|
301
|
-
onClick: () =>
|
|
301
|
+
onClick: () => setCancelTarget({ productId: product.id ?? "_inline", subscriptionId: product.subscription?.subscriptionId ?? void 0 }),
|
|
302
302
|
children: t("Cancel subscription")
|
|
303
303
|
}
|
|
304
304
|
)
|
|
@@ -308,9 +308,9 @@ ${error}`);
|
|
|
308
308
|
/* @__PURE__ */ jsx(
|
|
309
309
|
ActionDialog,
|
|
310
310
|
{
|
|
311
|
-
open:
|
|
311
|
+
open: cancelTarget !== null,
|
|
312
312
|
onOpenChange: (open) => {
|
|
313
|
-
if (!open)
|
|
313
|
+
if (!open) setCancelTarget(null);
|
|
314
314
|
},
|
|
315
315
|
title: t("Cancel subscription"),
|
|
316
316
|
description: t("Canceling will stop future renewals for this subscription."),
|
|
@@ -319,14 +319,14 @@ ${error}`);
|
|
|
319
319
|
okButton: {
|
|
320
320
|
label: t("Cancel subscription"),
|
|
321
321
|
onClick: async () => {
|
|
322
|
-
|
|
323
|
-
|
|
322
|
+
if (!cancelTarget) return;
|
|
323
|
+
const { productId, subscriptionId } = cancelTarget;
|
|
324
324
|
if (props.customerType === "team") {
|
|
325
|
-
await stackApp.cancelSubscription({ teamId: props.customer.id, productId });
|
|
325
|
+
await stackApp.cancelSubscription({ teamId: props.customer.id, productId, subscriptionId });
|
|
326
326
|
} else {
|
|
327
|
-
await stackApp.cancelSubscription({ productId });
|
|
327
|
+
await stackApp.cancelSubscription({ productId, subscriptionId });
|
|
328
328
|
}
|
|
329
|
-
|
|
329
|
+
setCancelTarget(null);
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
332
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components-page/account-settings/payments/payments-panel.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { runAsynchronously } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { ActionDialog, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, toast, Typography } from \"@stackframe/stack-ui\";\nimport { CardElement, Elements, useElements, useStripe } from \"@stripe/react-stripe-js\";\nimport { loadStripe } from \"@stripe/stripe-js\";\nimport { useMemo, useState } from \"react\";\nimport { useStackApp } from \"../../..\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { Section } from \"../section\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport type { CustomerInvoiceStatus, CustomerInvoicesList, CustomerInvoicesListOptions } from \"../../../lib/stack-app/customers\";\n\ntype PaymentMethodSummary = {\n id: string,\n brand: string | null,\n last4: string | null,\n exp_month: number | null,\n exp_year: number | null,\n} | null;\n\nfunction formatPaymentMethod(pm: NonNullable<PaymentMethodSummary>) {\n const details = [\n pm.brand ? pm.brand.toUpperCase() : null,\n pm.last4 ? `•••• ${pm.last4}` : null,\n pm.exp_month && pm.exp_year ? `exp ${pm.exp_month}/${pm.exp_year}` : null,\n ].filter(Boolean);\n return details.join(\" · \");\n}\n\nconst formatInvoiceStatus = (status: CustomerInvoiceStatus, t: (value: string) => string) => {\n if (!status) {\n return t(\"Unknown\");\n }\n switch (status) {\n case \"draft\": {\n return t(\"Draft\");\n }\n case \"open\": {\n return t(\"Open\");\n }\n case \"paid\": {\n return t(\"Paid\");\n }\n case \"uncollectible\": {\n return t(\"Uncollectible\");\n }\n case \"void\": {\n return t(\"Void\");\n }\n default: {\n return t(\"Unknown\");\n }\n }\n};\n\nconst formatInvoiceAmount = (amountTotal: number | null | undefined, t: (value: string) => string) => {\n if (typeof amountTotal !== \"number\" || Number.isNaN(amountTotal)) {\n return t(\"Unknown\");\n }\n const normalized = amountTotal / 100;\n const formatted = new Intl.NumberFormat(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(normalized);\n return `$${formatted}`;\n};\n\nconst formatInvoiceDate = (date: Date | null | undefined, t: (value: string) => string) => {\n if (!date || Number.isNaN(date.getTime())) {\n return t(\"Unknown\");\n }\n return new Intl.DateTimeFormat(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" }).format(date);\n};\n\ntype CustomerBilling = {\n hasCustomer: boolean,\n defaultPaymentMethod: PaymentMethodSummary,\n};\n\ntype CustomerPaymentMethodSetupIntent = {\n clientSecret: string,\n stripeAccountId: string,\n};\n\ntype CustomerLike = {\n id: string,\n useBilling: () => CustomerBilling,\n useProducts: () => Array<{\n id: string | null,\n quantity: number,\n displayName: string,\n customerType: \"user\" | \"team\" | \"custom\",\n type: \"one_time\" | \"subscription\",\n switchOptions?: Array<{\n productId: string,\n displayName: string,\n prices: Record<string, { interval?: [number, \"day\" | \"week\" | \"month\" | \"year\"] }>,\n }>,\n subscription: null | {\n currentPeriodEnd: Date | null,\n cancelAtPeriodEnd: boolean,\n isCancelable: boolean,\n },\n }>,\n useInvoices: (options?: CustomerInvoicesListOptions) => CustomerInvoicesList,\n createPaymentMethodSetupIntent: () => Promise<CustomerPaymentMethodSetupIntent>,\n setDefaultPaymentMethodFromSetupIntent: (setupIntentId: string) => Promise<PaymentMethodSummary>,\n switchSubscription: (options: { fromProductId: string, toProductId: string, priceId?: string, quantity?: number }) => Promise<void>,\n};\n\nfunction SetDefaultPaymentMethodForm(props: {\n clientSecret: string,\n onSetupIntentSucceeded: (setupIntentId: string) => Promise<void>,\n}) {\n const stripe = useStripe();\n const elements = useElements();\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const darkMode = \"color-scheme\" in document.documentElement.style && document.documentElement.style[\"color-scheme\"] === \"dark\";\n\n return (\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Typography className=\"font-medium\">Card details</Typography>\n <div className=\"rounded-md border border-input p-3\">\n <CardElement options={{ hidePostalCode: true, style: { base: { color: darkMode ? \"white\" : \"black\" } } }} />\n </div>\n </div>\n {errorMessage && (\n <Typography variant=\"secondary\" type=\"footnote\">\n {errorMessage}\n </Typography>\n )}\n <Button\n onClick={async () => {\n if (!stripe || !elements) {\n setErrorMessage(\"Stripe is still loading. Please try again.\");\n return;\n }\n const card = elements.getElement(CardElement);\n if (!card) {\n setErrorMessage(\"Card element not found.\");\n return;\n }\n\n const result = await stripe.confirmCardSetup(props.clientSecret, {\n payment_method: { card },\n });\n if (result.error) {\n setErrorMessage(result.error.message ?? \"Failed to save payment method.\");\n return;\n }\n if (!result.setupIntent.id) {\n setErrorMessage(\"No setup intent returned from Stripe.\");\n return;\n }\n await props.onSetupIntentSucceeded(result.setupIntent.id);\n }}\n >\n Save payment method\n </Button>\n </div>\n );\n}\n\nexport function PaymentsPanel(props: {\n title?: string,\n customer?: CustomerLike,\n customerType?: \"user\" | \"team\",\n mockMode?: boolean,\n}) {\n if (props.mockMode) {\n return <MockPaymentsPanel title={props.title} />;\n }\n if (!props.customer) {\n return null;\n }\n return <RealPaymentsPanel title={props.title} customer={props.customer} customerType={props.customerType ?? \"user\"} />;\n}\n\nfunction MockPaymentsPanel(props: { title?: string }) {\n const { t } = useTranslation();\n const defaultPaymentMethod: PaymentMethodSummary = {\n id: \"pm_mock\",\n brand: \"visa\",\n last4: \"4242\",\n exp_month: 12,\n exp_year: 2030,\n };\n\n return (\n <div className=\"space-y-4\">\n {props.title && <Typography className=\"font-medium\">{props.title}</Typography>}\n <Section\n title={t(\"Payment method\")}\n description={t(\"Manage the default payment method used for subscriptions and invoices.\")}\n >\n <Typography>{formatPaymentMethod(defaultPaymentMethod)}</Typography>\n <Button disabled>\n {t(\"Update payment method\")}\n </Button>\n </Section>\n\n <Section\n title={t(\"Active plans\")}\n description={t(\"View your active plans and purchases.\")}\n >\n <div className=\"space-y-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{t(\"Pro\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"Renews on\")} Jan 1, 2030</Typography>\n </div>\n <Button disabled variant=\"secondary\" color=\"neutral\">\n {t(\"Cancel subscription\")}\n </Button>\n </div>\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{t(\"Credits pack\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"One-time purchase\")}</Typography>\n </div>\n </div>\n </div>\n </Section>\n </div>\n );\n}\n\nfunction RealPaymentsPanel(props: { title?: string, customer: CustomerLike, customerType: \"user\" | \"team\" }) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const billing = props.customer.useBilling();\n const defaultPaymentMethod = billing.defaultPaymentMethod;\n const products = props.customer.useProducts();\n const invoices = props.customer.useInvoices({ limit: 10 });\n const productsForCustomerType = products.filter(product => product.customerType === props.customerType);\n\n const [paymentDialogOpen, setPaymentDialogOpen] = useState(false);\n const [setupIntentClientSecret, setSetupIntentClientSecret] = useState<string | null>(null);\n const [setupIntentStripeAccountId, setSetupIntentStripeAccountId] = useState<string | null>(null);\n const [cancelProductId, setCancelProductId] = useState<string | null>(null);\n const [switchFromProductId, setSwitchFromProductId] = useState<string | null>(null);\n const [switchToProductId, setSwitchToProductId] = useState<string | null>(null);\n\n const stripePromise = useMemo(() => {\n if (!setupIntentStripeAccountId) return null;\n const publishableKey = process.env.NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY;\n if (!publishableKey) return null;\n return loadStripe(publishableKey, { stripeAccount: setupIntentStripeAccountId });\n }, [setupIntentStripeAccountId]);\n\n const handleAsyncError = (error: unknown) => {\n if (error instanceof KnownErrors.DefaultPaymentMethodRequired) {\n toast({\n title: t(\"No default payment method\"),\n description: t(\"Add a payment method before switching plans.\"),\n variant: \"destructive\",\n });\n return;\n }\n alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === \"development\" ? \"check the browser console for the full error.\" : \"report this to the developer.\"}\\n\\n${error}`);\n };\n\n const openPaymentDialog = () => {\n runAsynchronously(async () => {\n setPaymentDialogOpen(true);\n const res = await props.customer.createPaymentMethodSetupIntent();\n setSetupIntentClientSecret(res.clientSecret);\n setSetupIntentStripeAccountId(res.stripeAccountId);\n }, { onError: handleAsyncError });\n };\n\n const closePaymentDialog = () => {\n setPaymentDialogOpen(false);\n setSetupIntentClientSecret(null);\n setSetupIntentStripeAccountId(null);\n };\n\n const openSwitchDialog = (productId: string, firstOptionId: string | null) => {\n setSwitchFromProductId(productId);\n setSwitchToProductId(firstOptionId);\n };\n\n const closeSwitchDialog = () => {\n setSwitchFromProductId(null);\n setSwitchToProductId(null);\n };\n\n const switchSourceProduct = switchFromProductId\n ? productsForCustomerType.find((product) => product.id === switchFromProductId) ?? null\n : null;\n const switchOptions = switchSourceProduct?.switchOptions ?? [];\n const selectedSwitchOption = switchOptions.find((option) => option.productId === switchToProductId) ?? null;\n const selectedPriceId = selectedSwitchOption ? (Object.keys(selectedSwitchOption.prices)[0] ?? null) : null;\n\n return (\n <div className=\"space-y-4\">\n {props.title && <Typography className=\"font-medium\">{props.title}</Typography>}\n\n {defaultPaymentMethod && (\n <Section\n title={t(\"Payment method\")}\n description={t(\"Manage the default payment method used for subscriptions and invoices.\")}\n >\n <Typography>{formatPaymentMethod(defaultPaymentMethod)}</Typography>\n\n <Button onClick={openPaymentDialog}>\n {t(\"Update payment method\")}\n </Button>\n\n <ActionDialog\n open={paymentDialogOpen}\n onOpenChange={(open) => {\n if (!open) {\n closePaymentDialog();\n } else {\n setPaymentDialogOpen(true);\n }\n }}\n title={t(\"Update payment method\")}\n >\n {!setupIntentClientSecret || !setupIntentStripeAccountId || !stripePromise ? (\n <Skeleton className=\"h-10 w-full\" />\n ) : (\n <Elements\n stripe={stripePromise}\n options={{\n clientSecret: setupIntentClientSecret,\n }}\n >\n <SetDefaultPaymentMethodForm\n clientSecret={setupIntentClientSecret}\n onSetupIntentSucceeded={async (setupIntentId) => {\n await props.customer.setDefaultPaymentMethodFromSetupIntent(setupIntentId);\n closePaymentDialog();\n }}\n />\n </Elements>\n )}\n </ActionDialog>\n </Section>\n )}\n\n {productsForCustomerType.length > 0 && (\n <Section\n title={t(\"Active plans\")}\n description={t(\"View your active plans and purchases.\")}\n >\n <div className=\"space-y-3\">\n {productsForCustomerType.map((product, index) => {\n const quantitySuffix = product.quantity !== 1 ? ` ×${product.quantity}` : \"\";\n const isSubscription = product.type === \"subscription\";\n const isCancelable = isSubscription && !!product.id && !!product.subscription?.isCancelable;\n const canSwitchPlans = isSubscription && defaultPaymentMethod && !!product.id && (product.switchOptions?.length ?? 0) > 0;\n const renewsAt = isSubscription ? (product.subscription?.currentPeriodEnd ?? null) : null;\n\n const subtitle =\n product.type === \"one_time\"\n ? t(\"One-time purchase\")\n : renewsAt\n ? `${t(\"Renews on\")} ${new Intl.DateTimeFormat(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" }).format(renewsAt)}`\n : t(\"Subscription\");\n\n return (\n <div key={product.id ?? `${product.displayName}-${index}`} className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{product.displayName}{quantitySuffix}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{subtitle}</Typography>\n </div>\n\n <div className=\"flex flex-col items-end gap-2\">\n {canSwitchPlans && (\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n onClick={() => openSwitchDialog(product.id!, product.switchOptions?.[0]?.productId ?? null)}\n >\n {t(\"Change plan\")}\n </Button>\n )}\n {isCancelable && (\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n onClick={() => setCancelProductId(product.id)}\n >\n {t(\"Cancel subscription\")}\n </Button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n\n <ActionDialog\n open={cancelProductId !== null}\n onOpenChange={(open) => {\n if (!open) setCancelProductId(null);\n }}\n title={t(\"Cancel subscription\")}\n description={t(\"Canceling will stop future renewals for this subscription.\")}\n danger\n cancelButton\n okButton={{\n label: t(\"Cancel subscription\"),\n onClick: async () => {\n const productId = cancelProductId;\n if (!productId) return;\n if (props.customerType === \"team\") {\n await stackApp.cancelSubscription({ teamId: props.customer.id, productId });\n } else {\n await stackApp.cancelSubscription({ productId });\n }\n setCancelProductId(null);\n },\n }}\n />\n\n <ActionDialog\n open={switchFromProductId !== null}\n onOpenChange={(open) => {\n if (!open) closeSwitchDialog();\n }}\n title={t(\"Change plan\")}\n description={t(\"Select a new plan from the same product line.\")}\n cancelButton\n okButton={{\n label: t(\"Switch plan\"),\n onClick: async () => {\n const fromProductId = switchFromProductId;\n const toProductId = switchToProductId;\n if (!fromProductId || !toProductId) return;\n if (!selectedPriceId) return;\n const result = await Result.fromThrowingAsync(() => props.customer.switchSubscription({\n fromProductId,\n toProductId,\n priceId: selectedPriceId,\n }));\n if (result.status === \"error\") {\n handleAsyncError(result.error);\n return \"prevent-close\";\n }\n closeSwitchDialog();\n },\n props: {\n disabled: !switchFromProductId || !switchToProductId || !selectedPriceId,\n },\n }}\n >\n <div className=\"space-y-2\">\n {switchOptions.length === 0 ? (\n <Typography variant=\"secondary\" type=\"footnote\">\n {t(\"No other plans available for this subscription.\")}\n </Typography>\n ) : (\n <>\n <Typography type=\"footnote\">{t(\"Choose a plan\")}</Typography>\n <Select\n value={switchToProductId ?? undefined}\n onValueChange={(value) => setSwitchToProductId(value || null)}\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder={t(\"Choose a plan\")} />\n </SelectTrigger>\n <SelectContent>\n {switchOptions.map((option: NonNullable<typeof switchOptions>[number]) => (\n <SelectItem key={option.productId} value={option.productId}>\n {option.displayName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )}\n </div>\n </ActionDialog>\n </Section>\n )\n }\n {invoices.length > 0 && (\n <>\n <Separator />\n <div className=\"space-y-2\">\n <div className=\"space-y-1\">\n <Typography className=\"font-medium\">{t(\"Invoices\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"Review past invoices and receipts.\")}</Typography>\n </div>\n <div className=\"border rounded-md\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[140px]\">{t(\"Date\")}</TableHead>\n <TableHead className=\"w-[120px]\">{t(\"Status\")}</TableHead>\n <TableHead className=\"w-[120px]\">{t(\"Amount\")}</TableHead>\n <TableHead className=\"w-[120px] text-right\">{t(\"Invoice\")}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {invoices.map((invoice, index) => {\n const createdAtTime = invoice.createdAt.getTime();\n const invoiceKey = Number.isNaN(createdAtTime) ? `invoice-${index}` : `invoice-${createdAtTime}-${index}`;\n return (\n <TableRow key={invoiceKey}>\n <TableCell>\n <Typography>{formatInvoiceDate(invoice.createdAt, t)}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{formatInvoiceStatus(invoice.status, t)}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{formatInvoiceAmount(invoice.amountTotal, t)}</Typography>\n </TableCell>\n <TableCell align=\"right\">\n {invoice.hostedInvoiceUrl ? (\n <Button asChild variant=\"secondary\" color=\"neutral\" size=\"sm\">\n <a href={invoice.hostedInvoiceUrl} target=\"_blank\" rel=\"noreferrer\">\n {t(\"View\")}\n </a>\n </Button>\n ) : (\n <Typography variant=\"secondary\" type=\"footnote\">\n {t(\"Unavailable\")}\n </Typography>\n )}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n </div>\n </>\n )}\n </div >\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components-page/account-settings/payments/payments-panel.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { runAsynchronously } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { ActionDialog, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, toast, Typography } from \"@stackframe/stack-ui\";\nimport { CardElement, Elements, useElements, useStripe } from \"@stripe/react-stripe-js\";\nimport { loadStripe } from \"@stripe/stripe-js\";\nimport { useMemo, useState } from \"react\";\nimport { useStackApp } from \"../../..\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { Section } from \"../section\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport type { CustomerInvoiceStatus, CustomerInvoicesList, CustomerInvoicesListOptions } from \"../../../lib/stack-app/customers\";\n\ntype PaymentMethodSummary = {\n id: string,\n brand: string | null,\n last4: string | null,\n exp_month: number | null,\n exp_year: number | null,\n} | null;\n\nfunction formatPaymentMethod(pm: NonNullable<PaymentMethodSummary>) {\n const details = [\n pm.brand ? pm.brand.toUpperCase() : null,\n pm.last4 ? `•••• ${pm.last4}` : null,\n pm.exp_month && pm.exp_year ? `exp ${pm.exp_month}/${pm.exp_year}` : null,\n ].filter(Boolean);\n return details.join(\" · \");\n}\n\nconst formatInvoiceStatus = (status: CustomerInvoiceStatus, t: (value: string) => string) => {\n if (!status) {\n return t(\"Unknown\");\n }\n switch (status) {\n case \"draft\": {\n return t(\"Draft\");\n }\n case \"open\": {\n return t(\"Open\");\n }\n case \"paid\": {\n return t(\"Paid\");\n }\n case \"uncollectible\": {\n return t(\"Uncollectible\");\n }\n case \"void\": {\n return t(\"Void\");\n }\n default: {\n return t(\"Unknown\");\n }\n }\n};\n\nconst formatInvoiceAmount = (amountTotal: number | null | undefined, t: (value: string) => string) => {\n if (typeof amountTotal !== \"number\" || Number.isNaN(amountTotal)) {\n return t(\"Unknown\");\n }\n const normalized = amountTotal / 100;\n const formatted = new Intl.NumberFormat(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(normalized);\n return `$${formatted}`;\n};\n\nconst formatInvoiceDate = (date: Date | null | undefined, t: (value: string) => string) => {\n if (!date || Number.isNaN(date.getTime())) {\n return t(\"Unknown\");\n }\n return new Intl.DateTimeFormat(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" }).format(date);\n};\n\ntype CustomerBilling = {\n hasCustomer: boolean,\n defaultPaymentMethod: PaymentMethodSummary,\n};\n\ntype CustomerPaymentMethodSetupIntent = {\n clientSecret: string,\n stripeAccountId: string,\n};\n\ntype CustomerLike = {\n id: string,\n useBilling: () => CustomerBilling,\n useProducts: () => Array<{\n id: string | null,\n quantity: number,\n displayName: string,\n customerType: \"user\" | \"team\" | \"custom\",\n type: \"one_time\" | \"subscription\",\n switchOptions?: Array<{\n productId: string,\n displayName: string,\n prices: Record<string, { interval?: [number, \"day\" | \"week\" | \"month\" | \"year\"] }>,\n }>,\n subscription: null | {\n subscriptionId: string | null,\n currentPeriodEnd: Date | null,\n cancelAtPeriodEnd: boolean,\n isCancelable: boolean,\n },\n }>,\n useInvoices: (options?: CustomerInvoicesListOptions) => CustomerInvoicesList,\n createPaymentMethodSetupIntent: () => Promise<CustomerPaymentMethodSetupIntent>,\n setDefaultPaymentMethodFromSetupIntent: (setupIntentId: string) => Promise<PaymentMethodSummary>,\n switchSubscription: (options: { fromProductId: string, toProductId: string, priceId?: string, quantity?: number }) => Promise<void>,\n};\n\nfunction SetDefaultPaymentMethodForm(props: {\n clientSecret: string,\n onSetupIntentSucceeded: (setupIntentId: string) => Promise<void>,\n}) {\n const stripe = useStripe();\n const elements = useElements();\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n const darkMode = \"color-scheme\" in document.documentElement.style && document.documentElement.style[\"color-scheme\"] === \"dark\";\n\n return (\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Typography className=\"font-medium\">Card details</Typography>\n <div className=\"rounded-md border border-input p-3\">\n <CardElement options={{ hidePostalCode: true, style: { base: { color: darkMode ? \"white\" : \"black\" } } }} />\n </div>\n </div>\n {errorMessage && (\n <Typography variant=\"secondary\" type=\"footnote\">\n {errorMessage}\n </Typography>\n )}\n <Button\n onClick={async () => {\n if (!stripe || !elements) {\n setErrorMessage(\"Stripe is still loading. Please try again.\");\n return;\n }\n const card = elements.getElement(CardElement);\n if (!card) {\n setErrorMessage(\"Card element not found.\");\n return;\n }\n\n const result = await stripe.confirmCardSetup(props.clientSecret, {\n payment_method: { card },\n });\n if (result.error) {\n setErrorMessage(result.error.message ?? \"Failed to save payment method.\");\n return;\n }\n if (!result.setupIntent.id) {\n setErrorMessage(\"No setup intent returned from Stripe.\");\n return;\n }\n await props.onSetupIntentSucceeded(result.setupIntent.id);\n }}\n >\n Save payment method\n </Button>\n </div>\n );\n}\n\nexport function PaymentsPanel(props: {\n title?: string,\n customer?: CustomerLike,\n customerType?: \"user\" | \"team\",\n mockMode?: boolean,\n}) {\n if (props.mockMode) {\n return <MockPaymentsPanel title={props.title} />;\n }\n if (!props.customer) {\n return null;\n }\n return <RealPaymentsPanel title={props.title} customer={props.customer} customerType={props.customerType ?? \"user\"} />;\n}\n\nfunction MockPaymentsPanel(props: { title?: string }) {\n const { t } = useTranslation();\n const defaultPaymentMethod: PaymentMethodSummary = {\n id: \"pm_mock\",\n brand: \"visa\",\n last4: \"4242\",\n exp_month: 12,\n exp_year: 2030,\n };\n\n return (\n <div className=\"space-y-4\">\n {props.title && <Typography className=\"font-medium\">{props.title}</Typography>}\n <Section\n title={t(\"Payment method\")}\n description={t(\"Manage the default payment method used for subscriptions and invoices.\")}\n >\n <Typography>{formatPaymentMethod(defaultPaymentMethod)}</Typography>\n <Button disabled>\n {t(\"Update payment method\")}\n </Button>\n </Section>\n\n <Section\n title={t(\"Active plans\")}\n description={t(\"View your active plans and purchases.\")}\n >\n <div className=\"space-y-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{t(\"Pro\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"Renews on\")} Jan 1, 2030</Typography>\n </div>\n <Button disabled variant=\"secondary\" color=\"neutral\">\n {t(\"Cancel subscription\")}\n </Button>\n </div>\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{t(\"Credits pack\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"One-time purchase\")}</Typography>\n </div>\n </div>\n </div>\n </Section>\n </div>\n );\n}\n\nfunction RealPaymentsPanel(props: { title?: string, customer: CustomerLike, customerType: \"user\" | \"team\" }) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const billing = props.customer.useBilling();\n const defaultPaymentMethod = billing.defaultPaymentMethod;\n const products = props.customer.useProducts();\n const invoices = props.customer.useInvoices({ limit: 10 });\n const productsForCustomerType = products.filter(product => product.customerType === props.customerType);\n\n const [paymentDialogOpen, setPaymentDialogOpen] = useState(false);\n const [setupIntentClientSecret, setSetupIntentClientSecret] = useState<string | null>(null);\n const [setupIntentStripeAccountId, setSetupIntentStripeAccountId] = useState<string | null>(null);\n const [cancelTarget, setCancelTarget] = useState<{ productId: string, subscriptionId?: string } | null>(null);\n const [switchFromProductId, setSwitchFromProductId] = useState<string | null>(null);\n const [switchToProductId, setSwitchToProductId] = useState<string | null>(null);\n\n const stripePromise = useMemo(() => {\n if (!setupIntentStripeAccountId) return null;\n const publishableKey = process.env.NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY;\n if (!publishableKey) return null;\n return loadStripe(publishableKey, { stripeAccount: setupIntentStripeAccountId });\n }, [setupIntentStripeAccountId]);\n\n const handleAsyncError = (error: unknown) => {\n if (error instanceof KnownErrors.DefaultPaymentMethodRequired) {\n toast({\n title: t(\"No default payment method\"),\n description: t(\"Add a payment method before switching plans.\"),\n variant: \"destructive\",\n });\n return;\n }\n alert(`An unhandled error occurred. Please ${process.env.NODE_ENV === \"development\" ? \"check the browser console for the full error.\" : \"report this to the developer.\"}\\n\\n${error}`);\n };\n\n const openPaymentDialog = () => {\n runAsynchronously(async () => {\n setPaymentDialogOpen(true);\n const res = await props.customer.createPaymentMethodSetupIntent();\n setSetupIntentClientSecret(res.clientSecret);\n setSetupIntentStripeAccountId(res.stripeAccountId);\n }, { onError: handleAsyncError });\n };\n\n const closePaymentDialog = () => {\n setPaymentDialogOpen(false);\n setSetupIntentClientSecret(null);\n setSetupIntentStripeAccountId(null);\n };\n\n const openSwitchDialog = (productId: string, firstOptionId: string | null) => {\n setSwitchFromProductId(productId);\n setSwitchToProductId(firstOptionId);\n };\n\n const closeSwitchDialog = () => {\n setSwitchFromProductId(null);\n setSwitchToProductId(null);\n };\n\n const switchSourceProduct = switchFromProductId\n ? productsForCustomerType.find((product) => product.id === switchFromProductId) ?? null\n : null;\n const switchOptions = switchSourceProduct?.switchOptions ?? [];\n const selectedSwitchOption = switchOptions.find((option) => option.productId === switchToProductId) ?? null;\n const selectedPriceId = selectedSwitchOption ? (Object.keys(selectedSwitchOption.prices)[0] ?? null) : null;\n\n return (\n <div className=\"space-y-4\">\n {props.title && <Typography className=\"font-medium\">{props.title}</Typography>}\n\n {defaultPaymentMethod && (\n <Section\n title={t(\"Payment method\")}\n description={t(\"Manage the default payment method used for subscriptions and invoices.\")}\n >\n <Typography>{formatPaymentMethod(defaultPaymentMethod)}</Typography>\n\n <Button onClick={openPaymentDialog}>\n {t(\"Update payment method\")}\n </Button>\n\n <ActionDialog\n open={paymentDialogOpen}\n onOpenChange={(open) => {\n if (!open) {\n closePaymentDialog();\n } else {\n setPaymentDialogOpen(true);\n }\n }}\n title={t(\"Update payment method\")}\n >\n {!setupIntentClientSecret || !setupIntentStripeAccountId || !stripePromise ? (\n <Skeleton className=\"h-10 w-full\" />\n ) : (\n <Elements\n stripe={stripePromise}\n options={{\n clientSecret: setupIntentClientSecret,\n }}\n >\n <SetDefaultPaymentMethodForm\n clientSecret={setupIntentClientSecret}\n onSetupIntentSucceeded={async (setupIntentId) => {\n await props.customer.setDefaultPaymentMethodFromSetupIntent(setupIntentId);\n closePaymentDialog();\n }}\n />\n </Elements>\n )}\n </ActionDialog>\n </Section>\n )}\n\n {productsForCustomerType.length > 0 && (\n <Section\n title={t(\"Active plans\")}\n description={t(\"View your active plans and purchases.\")}\n >\n <div className=\"space-y-3\">\n {productsForCustomerType.map((product, index) => {\n const quantitySuffix = product.quantity !== 1 ? ` ×${product.quantity}` : \"\";\n const isSubscription = product.type === \"subscription\";\n const isCancelable = isSubscription && !!product.subscription?.isCancelable;\n const canSwitchPlans = isSubscription && defaultPaymentMethod && !!product.id && (product.switchOptions?.length ?? 0) > 0;\n const renewsAt = isSubscription ? (product.subscription?.currentPeriodEnd ?? null) : null;\n const subtitle =\n product.type === \"one_time\"\n ? t(\"One-time purchase\")\n : renewsAt\n ? `${t(\"Renews on\")} ${new Intl.DateTimeFormat(undefined, { year: \"numeric\", month: \"short\", day: \"numeric\" }).format(renewsAt)}`\n : t(\"Subscription\");\n\n return (\n <div key={product.id ?? `${product.displayName}-${index}`} className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <Typography className=\"truncate\">{product.displayName}{quantitySuffix}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{subtitle}</Typography>\n </div>\n\n <div className=\"flex flex-col items-end gap-2\">\n {canSwitchPlans && (\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n onClick={() => openSwitchDialog(product.id!, product.switchOptions?.[0]?.productId ?? null)}\n >\n {t(\"Change plan\")}\n </Button>\n )}\n {isCancelable && (\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n onClick={() => setCancelTarget({ productId: product.id ?? \"_inline\", subscriptionId: product.subscription?.subscriptionId ?? undefined })}\n >\n {t(\"Cancel subscription\")}\n </Button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n\n <ActionDialog\n open={cancelTarget !== null}\n onOpenChange={(open) => {\n if (!open) setCancelTarget(null);\n }}\n title={t(\"Cancel subscription\")}\n description={t(\"Canceling will stop future renewals for this subscription.\")}\n danger\n cancelButton\n okButton={{\n label: t(\"Cancel subscription\"),\n onClick: async () => {\n if (!cancelTarget) return;\n const { productId, subscriptionId } = cancelTarget;\n if (props.customerType === \"team\") {\n await stackApp.cancelSubscription({ teamId: props.customer.id, productId, subscriptionId });\n } else {\n await stackApp.cancelSubscription({ productId, subscriptionId });\n }\n setCancelTarget(null);\n },\n }}\n />\n\n <ActionDialog\n open={switchFromProductId !== null}\n onOpenChange={(open) => {\n if (!open) closeSwitchDialog();\n }}\n title={t(\"Change plan\")}\n description={t(\"Select a new plan from the same product line.\")}\n cancelButton\n okButton={{\n label: t(\"Switch plan\"),\n onClick: async () => {\n const fromProductId = switchFromProductId;\n const toProductId = switchToProductId;\n if (!fromProductId || !toProductId) return;\n if (!selectedPriceId) return;\n const result = await Result.fromThrowingAsync(() => props.customer.switchSubscription({\n fromProductId,\n toProductId,\n priceId: selectedPriceId,\n }));\n if (result.status === \"error\") {\n handleAsyncError(result.error);\n return \"prevent-close\";\n }\n closeSwitchDialog();\n },\n props: {\n disabled: !switchFromProductId || !switchToProductId || !selectedPriceId,\n },\n }}\n >\n <div className=\"space-y-2\">\n {switchOptions.length === 0 ? (\n <Typography variant=\"secondary\" type=\"footnote\">\n {t(\"No other plans available for this subscription.\")}\n </Typography>\n ) : (\n <>\n <Typography type=\"footnote\">{t(\"Choose a plan\")}</Typography>\n <Select\n value={switchToProductId ?? undefined}\n onValueChange={(value) => setSwitchToProductId(value || null)}\n >\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder={t(\"Choose a plan\")} />\n </SelectTrigger>\n <SelectContent>\n {switchOptions.map((option: NonNullable<typeof switchOptions>[number]) => (\n <SelectItem key={option.productId} value={option.productId}>\n {option.displayName}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )}\n </div>\n </ActionDialog>\n </Section>\n )\n }\n {invoices.length > 0 && (\n <>\n <Separator />\n <div className=\"space-y-2\">\n <div className=\"space-y-1\">\n <Typography className=\"font-medium\">{t(\"Invoices\")}</Typography>\n <Typography variant=\"secondary\" type=\"footnote\">{t(\"Review past invoices and receipts.\")}</Typography>\n </div>\n <div className=\"border rounded-md\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[140px]\">{t(\"Date\")}</TableHead>\n <TableHead className=\"w-[120px]\">{t(\"Status\")}</TableHead>\n <TableHead className=\"w-[120px]\">{t(\"Amount\")}</TableHead>\n <TableHead className=\"w-[120px] text-right\">{t(\"Invoice\")}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {invoices.map((invoice, index) => {\n const createdAtTime = invoice.createdAt.getTime();\n const invoiceKey = Number.isNaN(createdAtTime) ? `invoice-${index}` : `invoice-${createdAtTime}-${index}`;\n return (\n <TableRow key={invoiceKey}>\n <TableCell>\n <Typography>{formatInvoiceDate(invoice.createdAt, t)}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{formatInvoiceStatus(invoice.status, t)}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{formatInvoiceAmount(invoice.amountTotal, t)}</Typography>\n </TableCell>\n <TableCell align=\"right\">\n {invoice.hostedInvoiceUrl ? (\n <Button asChild variant=\"secondary\" color=\"neutral\" size=\"sm\">\n <a href={invoice.hostedInvoiceUrl} target=\"_blank\" rel=\"noreferrer\">\n {t(\"View\")}\n </a>\n </Button>\n ) : (\n <Typography variant=\"secondary\" type=\"footnote\">\n {t(\"Unavailable\")}\n </Typography>\n )}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n </div>\n </>\n )}\n </div >\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nexport * from './lib/stack-app';\
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nexport * from './lib/stack-app';\nexport { getConvexProvidersConfig } from \"./integrations/convex\";\n\nexport type { AnalyticsOptions, AnalyticsReplayOptions } from \"./lib/stack-app/apps/implementations/session-replay\";\nexport { default as StackHandler } from \"./components-page/stack-handler\";\nexport { useStackApp, useUser } from \"./lib/hooks\";\nexport { default as StackProvider } from \"./providers/stack-provider\";\nexport { StackTheme } from './providers/theme-provider';\n\nexport { AccountSettings } from \"./components-page/account-settings\";\nexport { AuthPage } from \"./components-page/auth-page\";\nexport { CliAuthConfirmation } from \"./components-page/cli-auth-confirm\";\nexport { EmailVerification } from \"./components-page/email-verification\";\nexport { ForgotPassword } from \"./components-page/forgot-password\";\nexport { PasswordReset } from \"./components-page/password-reset\";\nexport { SignIn } from \"./components-page/sign-in\";\nexport { SignUp } from \"./components-page/sign-up\";\nexport { CredentialSignIn as CredentialSignIn } from \"./components/credential-sign-in\";\nexport { CredentialSignUp as CredentialSignUp } from \"./components/credential-sign-up\";\nexport { UserAvatar } from \"./components/elements/user-avatar\";\nexport { MagicLinkSignIn as MagicLinkSignIn } from \"./components/magic-link-sign-in\";\nexport { MessageCard } from \"./components/message-cards/message-card\";\nexport { OAuthButton } from \"./components/oauth-button\";\nexport { OAuthButtonGroup } from \"./components/oauth-button-group\";\nexport { SelectedTeamSwitcher } from \"./components/selected-team-switcher\";\nexport { TeamSwitcher } from \"./components/team-switcher\";\nexport { UserButton } from \"./components/user-button\";\n"],"mappings":";AAIA,cAAc;AACd,SAAS,gCAAgC;AAGzC,SAAoB,WAAXA,gBAA+B;AACxC,SAAS,aAAa,eAAe;AACrC,SAAoB,WAAXA,gBAAgC;AACzC,SAAS,kBAAkB;AAE3B,SAAS,uBAAuB;AAChC,SAAS,gBAAgB;AACzB,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAA6B,wBAAwB;AACrD,SAA6B,wBAAwB;AACrD,SAAS,kBAAkB;AAC3B,SAA4B,uBAAuB;AACnD,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B,SAAS,wBAAwB;AACjC,SAAS,4BAA4B;AACrC,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;","names":["default"]}
|