update from user testing payment platform
This commit is contained in:
@@ -11,11 +11,6 @@ import {
|
||||
// Dummy key placeholder — swap for a real test/live secret when the account is connected.
|
||||
const KEY: string = String(STRIPE_SECRET_KEY) || 'sk_test_dummy_famchamp_not_connected';
|
||||
|
||||
// True until a real key is wired in .env. When dummy, we don't hit the Stripe
|
||||
// API — checkout/billing actions return simulated session URLs so the flow can
|
||||
// be established end-to-end before the account is connected.
|
||||
export const isDummyStripe = !STRIPE_SECRET_KEY;
|
||||
|
||||
export const stripe = new Stripe(KEY);
|
||||
|
||||
// 3-tier plans: `trial` is not a paid Stripe price — it's app-side validated
|
||||
@@ -93,6 +88,47 @@ export async function createCheckoutSession(opts: {
|
||||
return stripe.checkout.sessions.create(params);
|
||||
}
|
||||
|
||||
// Live subscription state for the settings UI (source of truth = Stripe).
|
||||
export async function getSubscriptionStatus(
|
||||
customerId: string
|
||||
): Promise<{ active: boolean; cancelAtPeriodEnd: boolean; endsAt?: string }> {
|
||||
const subs = await stripe.subscriptions.list({
|
||||
customer: customerId,
|
||||
status: 'all',
|
||||
limit: 10
|
||||
});
|
||||
const active = subs.data.find((s) => ['active', 'trialing', 'past_due'].includes(s.status));
|
||||
if (!active) return { active: false, cancelAtPeriodEnd: false };
|
||||
const itemEnd = active.items.data[0]?.current_period_end;
|
||||
return {
|
||||
active: true,
|
||||
cancelAtPeriodEnd: !!active.cancel_at_period_end,
|
||||
endsAt: new Date((itemEnd ?? Math.floor(Date.now() / 1000)) * 1000).toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
// In-app cancellation: flags the customer's active subscription to end at the
|
||||
// close of the current paid period (no refund, access continues until then).
|
||||
// The existing webhook flips paymentMode='canceled' when it actually ends.
|
||||
export async function cancelSubscriptionAtPeriodEnd(
|
||||
customerId: string
|
||||
): Promise<{ ended: boolean; endsAt?: string }> {
|
||||
const subs = await stripe.subscriptions.list({
|
||||
customer: customerId,
|
||||
status: 'all',
|
||||
limit: 10
|
||||
});
|
||||
const active = subs.data.find((s) => ['active', 'trialing', 'past_due'].includes(s.status));
|
||||
if (!active) return { ended: false };
|
||||
if (!active.cancel_at_period_end) {
|
||||
await stripe.subscriptions.update(active.id, { cancel_at_period_end: true });
|
||||
}
|
||||
// Newer Stripe API versions carry current_period_end on the sub item.
|
||||
const itemEnd = active.items.data[0]?.current_period_end;
|
||||
const periodEnd = itemEnd ?? Math.floor(Date.now() / 1000) + 30 * 86400;
|
||||
return { ended: true, endsAt: new Date(periodEnd * 1000).toISOString() };
|
||||
}
|
||||
|
||||
// Stripe Billing portal session for managing/cancelling the subscription.
|
||||
export async function createBillingPortalSession(customerId: string, origin: string, famSlug = '') {
|
||||
return stripe.billingPortal.sessions.create({
|
||||
@@ -143,4 +179,4 @@ export async function createEmbeddedCheckoutSession(opts: {
|
||||
|
||||
const session = await stripe.checkout.sessions.create(params);
|
||||
return { clientSecret: session.client_secret, sessionId: session.id };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user