feat: dashboard Second Brain, essai 7 jours et vérification e-mail
Rendre le dashboard actionnable (inbox, peek, carte mentale), aligner la facturation sur l’essai 7 jours, et bloquer le login e-mail tant que l’adresse n’est pas confirmée. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,6 +2,10 @@ import { NextRequest, NextResponse } from 'next/server';
|
||||
import { auth } from '@/auth';
|
||||
import { stripe } from '@/lib/stripe';
|
||||
import { isBillingEnabled, resolvePriceId } from '@/lib/billing/stripe-prices';
|
||||
import {
|
||||
shouldOfferSubscriptionTrial,
|
||||
SUBSCRIPTION_TRIAL_DAYS,
|
||||
} from '@/lib/billing/trial';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -91,6 +95,17 @@ export async function POST(req: NextRequest) {
|
||||
const proto = req.headers.get('x-forwarded-proto') ?? 'http';
|
||||
const origin = `${proto}://${host}`;
|
||||
|
||||
const offerTrial = await shouldOfferSubscriptionTrial(userId);
|
||||
const subscriptionData: {
|
||||
metadata: { userId: string; tier: string };
|
||||
trial_period_days?: number;
|
||||
} = {
|
||||
metadata: { userId, tier },
|
||||
};
|
||||
if (offerTrial) {
|
||||
subscriptionData.trial_period_days = SUBSCRIPTION_TRIAL_DAYS;
|
||||
}
|
||||
|
||||
// Hosted Checkout is the most reliable path (redirect). Embedded is optional.
|
||||
if (preferredMode === 'embedded') {
|
||||
try {
|
||||
@@ -100,8 +115,8 @@ export async function POST(req: NextRequest) {
|
||||
line_items: [{ price: priceId, quantity: 1 }],
|
||||
ui_mode: 'embedded' as any,
|
||||
return_url: `${origin}/settings/billing?session_id={CHECKOUT_SESSION_ID}`,
|
||||
metadata: { userId, tier },
|
||||
subscription_data: { metadata: { userId, tier } },
|
||||
metadata: { userId, tier, trial: offerTrial ? '1' : '0' },
|
||||
subscription_data: subscriptionData,
|
||||
customer_update: { address: 'auto' },
|
||||
allow_promotion_codes: true,
|
||||
} as any);
|
||||
@@ -109,6 +124,7 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({
|
||||
clientSecret: embedded.client_secret,
|
||||
sessionId: embedded.id,
|
||||
trialDays: offerTrial ? SUBSCRIPTION_TRIAL_DAYS : 0,
|
||||
});
|
||||
}
|
||||
} catch (embeddedErr) {
|
||||
@@ -122,8 +138,8 @@ export async function POST(req: NextRequest) {
|
||||
line_items: [{ price: priceId, quantity: 1 }],
|
||||
success_url: `${origin}/settings/billing?session_id={CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${origin}/settings/billing?canceled=1`,
|
||||
metadata: { userId, tier },
|
||||
subscription_data: { metadata: { userId, tier } },
|
||||
metadata: { userId, tier, trial: offerTrial ? '1' : '0' },
|
||||
subscription_data: subscriptionData,
|
||||
customer_update: { address: 'auto' },
|
||||
allow_promotion_codes: true,
|
||||
});
|
||||
@@ -132,7 +148,11 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ error: 'Checkout session has no URL' }, { status: 500 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ url: checkoutSession.url, sessionId: checkoutSession.id });
|
||||
return NextResponse.json({
|
||||
url: checkoutSession.url,
|
||||
sessionId: checkoutSession.id,
|
||||
trialDays: offerTrial ? SUBSCRIPTION_TRIAL_DAYS : 0,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[billing/create-checkout]', error);
|
||||
const msg = error instanceof Error ? error.message : 'Failed to create checkout session';
|
||||
|
||||
Reference in New Issue
Block a user