juntekim.com/stripe_to_invoice/lib/subscription/check-status.ts
2026-02-21 11:19:06 +00:00

101 lines
2.5 KiB
TypeScript

import { eq } from "drizzle-orm";
import { db } from "@/lib/db";
import { subscriptions, users } from "@/lib/schema";
const TRIAL_DAYS = 14;
export interface SubscriptionStatus {
isActive: boolean;
status: "trialing" | "active" | "expired" | "canceled" | "canceling";
daysRemainingInTrial: number | null;
trialEndsAt: Date | null;
subscriptionEndsAt: Date | null;
}
/**
* Check if a user has an active subscription or valid trial
*/
export async function checkSubscriptionStatus(userId: string): Promise<SubscriptionStatus> {
// Get user creation date
const [user] = await db
.select({ createdAt: users.createdAt })
.from(users)
.where(eq(users.id, userId))
.limit(1);
if (!user) {
return {
isActive: false,
status: "expired",
daysRemainingInTrial: null,
trialEndsAt: null,
subscriptionEndsAt: null,
};
}
// Get subscription record
const [subscription] = await db
.select()
.from(subscriptions)
.where(eq(subscriptions.userId, userId))
.limit(1);
const now = new Date();
const trialEndsAt = new Date(user.createdAt);
trialEndsAt.setDate(trialEndsAt.getDate() + TRIAL_DAYS);
// If user has active or canceling subscription, they can use the service
if (subscription?.status === "active" || subscription?.status === "canceling") {
// If subscription is marked as canceling, return canceling status
if (subscription.status === "canceling") {
return {
isActive: true,
status: "canceling",
daysRemainingInTrial: null,
trialEndsAt: null,
subscriptionEndsAt: subscription.currentPeriodEnd || null,
};
}
return {
isActive: true,
status: "active",
daysRemainingInTrial: null,
trialEndsAt: null,
subscriptionEndsAt: subscription.currentPeriodEnd || null,
};
}
// If still in trial period
if (now < trialEndsAt) {
const daysRemaining = Math.ceil(
(trialEndsAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
);
return {
isActive: true,
status: "trialing",
daysRemainingInTrial: daysRemaining,
trialEndsAt,
subscriptionEndsAt: null,
};
}
// Trial expired and no paid subscription
if (subscription?.status === "canceled") {
return {
isActive: false,
status: "canceled",
daysRemainingInTrial: null,
trialEndsAt,
subscriptionEndsAt: null,
};
}
return {
isActive: false,
status: "expired",
daysRemainingInTrial: null,
trialEndsAt,
subscriptionEndsAt: null,
};
}