← back to Dear Bubbe Nextjs
app/api/pricing/route.ts
148 lines
/**
* Pricing API Endpoint
*
* Provides pricing information and plan recommendations
* GET /api/pricing - Get all plans
* POST /api/pricing/recommend - Get plan recommendation based on features
* POST /api/pricing/upgrade - Upgrade user plan
*/
import { NextRequest, NextResponse } from 'next/server';
import {
getAllPlansWithComparison,
getRequiredPlanForFeatures,
getPlanSummary,
generateUpsellMessage,
FeatureKey,
PlanId
} from '@/lib/bubbe-pricing';
import {
getUserSession,
updateUserPlan,
getUserIdFromRequest
} from '@/lib/user-session';
export async function GET(req: NextRequest) {
try {
// Get user's current plan if they're logged in
const userId = req.cookies.get('userId')?.value ||
req.headers.get('x-user-id');
const currentPlan = userId ? getUserSession(userId).plan : 'basic';
// Get all plans with comparison
const plans = getAllPlansWithComparison();
return NextResponse.json({
currentPlan,
plans,
recommendation: "Oy vey, looking to spend some money? Good, I need a new kitchen!"
});
} catch (error) {
console.error('Pricing API error:', error);
return NextResponse.json(
{ error: 'Failed to fetch pricing information' },
{ status: 500 }
);
}
}
export async function POST(req: NextRequest) {
try {
const body = await req.json();
const { action } = body;
// Get user ID
const userId = req.cookies.get('userId')?.value ||
req.headers.get('x-user-id') ||
`user_${Date.now()}`;
if (action === 'recommend') {
// Recommend a plan based on requested features
const { features } = body as { features: FeatureKey[] };
if (!features || !Array.isArray(features)) {
return NextResponse.json(
{ error: 'Features array required' },
{ status: 400 }
);
}
const recommendedPlan = getRequiredPlanForFeatures(features);
const planDetails = getPlanSummary(recommendedPlan);
const currentPlan = getUserSession(userId).plan;
const response = {
recommendedPlan: planDetails,
currentPlan,
needsUpgrade: currentPlan !== recommendedPlan &&
['basic', 'plus'].indexOf(currentPlan) <
['basic', 'plus', 'max'].indexOf(recommendedPlan),
upsellMessage: generateUpsellMessage(currentPlan, recommendedPlan),
requestedFeatures: features
};
return NextResponse.json(response);
}
if (action === 'upgrade') {
// Upgrade user to a new plan
const { plan } = body as { plan: PlanId };
if (!plan || !['basic', 'plus', 'max'].includes(plan)) {
return NextResponse.json(
{ error: 'Valid plan required (basic, plus, or max)' },
{ status: 400 }
);
}
const session = updateUserPlan(userId, plan);
const planDetails = getPlanSummary(plan);
// Set cookie to persist user ID
const response = NextResponse.json({
success: true,
message: `Mazel tov! You're now on ${planDetails.name}. Your mother would be proud... maybe.`,
plan: planDetails,
session: {
userId: session.userId,
plan: session.plan,
subscribedAt: session.subscribedAt
}
});
response.cookies.set('userId', userId, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 365 // 1 year
});
return response;
}
if (action === 'check') {
// Check user's current plan and features
const session = getUserSession(userId);
const planDetails = getPlanSummary(session.plan);
return NextResponse.json({
userId,
...planDetails,
subscribedAt: session.subscribedAt
});
}
return NextResponse.json(
{ error: 'Invalid action. Use: recommend, upgrade, or check' },
{ status: 400 }
);
} catch (error) {
console.error('Pricing API error:', error);
return NextResponse.json(
{ error: 'Failed to process pricing request' },
{ status: 500 }
);
}
}