import { NextRequest, NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth'; import { db } from '@/lib/db'; import { z } from 'zod'; // Validation schema for creating a membership plan const createMembershipPlanSchema = z.object({ name: z.string().min(1, 'Name is required').max(100, 'Name too long'), description: z.string().max(500).optional(), price: z.number().nonnegative('Price must be non-negative'), durationMonths: z.number().int().min(1, 'Duration must be at least 1 month').default(1), freeHours: z.number().int().min(0, 'Free hours must be non-negative').optional(), bookingDiscount: z.number().min(0).max(100, 'Discount must be between 0 and 100').optional(), storeDiscount: z.number().min(0).max(100, 'Discount must be between 0 and 100').optional(), extraBenefits: z.array(z.string()).optional(), }); // GET /api/membership-plans - List all active plans for organization export async function GET(request: NextRequest) { try { const session = await getServerSession(authOptions); if (!session?.user) { return NextResponse.json( { error: 'Unauthorized' }, { status: 401 } ); } const { searchParams } = new URL(request.url); const includeInactive = searchParams.get('includeInactive') === 'true'; // Build where clause interface MembershipPlanWhereClause { organizationId: string; isActive?: boolean; } const whereClause: MembershipPlanWhereClause = { organizationId: session.user.organizationId, }; // Only show active plans by default if (!includeInactive) { whereClause.isActive = true; } const plans = await db.membershipPlan.findMany({ where: whereClause, include: { _count: { select: { memberships: { where: { status: 'ACTIVE', }, }, }, }, }, orderBy: { price: 'asc', }, }); // Transform response to include benefit summary const plansWithSummary = plans.map((plan) => ({ ...plan, subscriberCount: plan._count.memberships, benefitsSummary: { freeHours: plan.courtHours || 0, bookingDiscount: plan.discountPercent ? Number(plan.discountPercent) : 0, extraBenefits: plan.benefits || [], }, })); return NextResponse.json(plansWithSummary); } catch (error) { console.error('Error fetching membership plans:', error); return NextResponse.json( { error: 'Failed to fetch membership plans' }, { status: 500 } ); } } // POST /api/membership-plans - Create a new membership plan export async function POST(request: NextRequest) { try { const session = await getServerSession(authOptions); if (!session?.user) { return NextResponse.json( { error: 'Unauthorized' }, { status: 401 } ); } // Check if user has admin role const allowedRoles = ['SUPER_ADMIN', 'ORG_ADMIN']; if (!allowedRoles.includes(session.user.role)) { return NextResponse.json( { error: 'Forbidden: Insufficient permissions' }, { status: 403 } ); } const body = await request.json(); // Validate input with Zod schema const validationResult = createMembershipPlanSchema.safeParse(body); if (!validationResult.success) { return NextResponse.json( { error: 'Invalid membership plan data', details: validationResult.error.flatten().fieldErrors, }, { status: 400 } ); } const { name, description, price, durationMonths, freeHours, bookingDiscount, storeDiscount, extraBenefits, } = validationResult.data; // Create the membership plan const plan = await db.membershipPlan.create({ data: { organizationId: session.user.organizationId, name, description: description || null, price, durationMonths, courtHours: freeHours || null, discountPercent: bookingDiscount || null, benefits: [ ...(extraBenefits || []), ...(storeDiscount ? [`${storeDiscount}% store discount`] : []), ], isActive: true, }, include: { _count: { select: { memberships: { where: { status: 'ACTIVE', }, }, }, }, }, }); // Transform response const planWithSummary = { ...plan, subscriberCount: plan._count.memberships, benefitsSummary: { freeHours: plan.courtHours || 0, bookingDiscount: plan.discountPercent ? Number(plan.discountPercent) : 0, extraBenefits: plan.benefits || [], }, }; return NextResponse.json(planWithSummary, { status: 201 }); } catch (error) { console.error('Error creating membership plan:', error); return NextResponse.json( { error: 'Failed to create membership plan' }, { status: 500 } ); } }