112 lines
3.9 KiB
TypeScript
112 lines
3.9 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
||
import { eq } from "drizzle-orm";
|
||
import { randomUUID } from "crypto";
|
||
|
||
import { getStripeBilling } from "@/lib/stripe/service";
|
||
import { getUserFromSession } from "@/lib/auth/get-user";
|
||
import { db } from "@/lib/db";
|
||
import { subscriptions } from "@/lib/schema";
|
||
|
||
const stripe = getStripeBilling();
|
||
|
||
const SUBSCRIPTION_PRICE_ID = process.env.STRIPE_SUBSCRIPTION_PRICE_ID!;
|
||
const ORIGIN = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";
|
||
|
||
export async function POST(req: NextRequest) {
|
||
try {
|
||
console.log("💳 [SUBSCRIPTION CHECKOUT] Request received");
|
||
console.log("💳 [SUBSCRIPTION CHECKOUT] Using price ID:", SUBSCRIPTION_PRICE_ID);
|
||
|
||
// --------------------------------------------------
|
||
// 1️⃣ Get authenticated user
|
||
// --------------------------------------------------
|
||
const user = await getUserFromSession();
|
||
if (!user) {
|
||
console.error("❌ [SUBSCRIPTION CHECKOUT] Unauthorized");
|
||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||
}
|
||
|
||
console.log("✅ [SUBSCRIPTION CHECKOUT] User authenticated:", user.id);
|
||
|
||
// --------------------------------------------------
|
||
// 2️⃣ Check if user already has an active subscription
|
||
// --------------------------------------------------
|
||
const [existingSubscription] = await db
|
||
.select()
|
||
.from(subscriptions)
|
||
.where(eq(subscriptions.userId, user.id))
|
||
.limit(1);
|
||
|
||
if (existingSubscription?.status === "active") {
|
||
console.log("⚠️ [SUBSCRIPTION CHECKOUT] User already has active subscription");
|
||
return NextResponse.json(
|
||
{ error: "User already has an active subscription" },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
console.log("✅ [SUBSCRIPTION CHECKOUT] No active subscription found");
|
||
|
||
// --------------------------------------------------
|
||
// 3️⃣ Create or get Stripe customer
|
||
// --------------------------------------------------
|
||
let stripeCustomerId = existingSubscription?.stripeCustomerId;
|
||
|
||
if (!stripeCustomerId) {
|
||
console.log("➕ [SUBSCRIPTION CHECKOUT] Creating Stripe customer");
|
||
const customer = await stripe.customers.create({
|
||
email: user.email,
|
||
metadata: {
|
||
userId: user.id,
|
||
},
|
||
});
|
||
stripeCustomerId = customer.id;
|
||
console.log("✅ [SUBSCRIPTION CHECKOUT] Stripe customer created:", stripeCustomerId);
|
||
} else {
|
||
console.log("✅ [SUBSCRIPTION CHECKOUT] Using existing Stripe customer:", stripeCustomerId);
|
||
}
|
||
|
||
// --------------------------------------------------
|
||
// 4️⃣ Create checkout session
|
||
// --------------------------------------------------
|
||
console.log("📝 [SUBSCRIPTION CHECKOUT] Creating checkout session");
|
||
|
||
const session = await stripe.checkout.sessions.create({
|
||
customer: stripeCustomerId,
|
||
mode: "subscription",
|
||
line_items: [
|
||
{
|
||
price: SUBSCRIPTION_PRICE_ID,
|
||
quantity: 1,
|
||
},
|
||
],
|
||
success_url: `${ORIGIN}/billing?success=true`,
|
||
cancel_url: `${ORIGIN}/billing?canceled=true`,
|
||
metadata: {
|
||
userId: user.id,
|
||
},
|
||
});
|
||
|
||
console.log("✅ [SUBSCRIPTION CHECKOUT] Checkout session created:", session.id);
|
||
|
||
// --------------------------------------------------
|
||
// 5️⃣ Store Stripe customer ID if this is first time
|
||
// --------------------------------------------------
|
||
if (!existingSubscription) {
|
||
await db.insert(subscriptions).values({
|
||
userId: user.id,
|
||
stripeCustomerId,
|
||
status: "trialing",
|
||
});
|
||
console.log("✅ [SUBSCRIPTION CHECKOUT] Subscription record created");
|
||
}
|
||
|
||
return NextResponse.json({ url: session.url });
|
||
} catch (error: any) {
|
||
console.error("❌ [SUBSCRIPTION CHECKOUT] Error:", error.message);
|
||
return NextResponse.json(
|
||
{ error: error.message },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|