correction affichage dashboard chapitre mot par jour + nombre livre max
This commit is contained in:
@@ -1,10 +1,43 @@
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { auth } from '@/lib/auth';
|
||||
import getDB from '@/lib/prisma';
|
||||
import { generateStoryContent } from '@/lib/gemini';
|
||||
|
||||
const PLAN_AI_LIMITS: Record<string, number> = {
|
||||
free: 100,
|
||||
pro: 5000,
|
||||
master: 999999,
|
||||
};
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Non autorisé' }, { status: 401 });
|
||||
}
|
||||
|
||||
const prisma = getDB();
|
||||
|
||||
// Check AI usage limit from DB
|
||||
const dbUser = await prisma.user.findUnique({
|
||||
where: { id: session.user.id },
|
||||
select: { plan: true, aiActionsUsed: true },
|
||||
});
|
||||
|
||||
if (!dbUser) {
|
||||
return NextResponse.json({ error: 'Utilisateur non trouvé' }, { status: 404 });
|
||||
}
|
||||
|
||||
const limit = PLAN_AI_LIMITS[dbUser.plan] || PLAN_AI_LIMITS.free;
|
||||
if (dbUser.aiActionsUsed >= limit) {
|
||||
return NextResponse.json(
|
||||
{ error: `Limite de ${limit} actions IA atteinte pour le plan ${dbUser.plan}. Passez au plan supérieur !` },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { project, chapterId, prompt, user } = body;
|
||||
|
||||
@@ -15,9 +48,17 @@ export async function POST(request: NextRequest) {
|
||||
);
|
||||
}
|
||||
|
||||
const result = await generateStoryContent(project, chapterId || '', prompt, user);
|
||||
// Pass real plan from DB to gemini for model selection
|
||||
const userWithPlan = { ...user, subscription: { ...user.subscription, plan: dbUser.plan } };
|
||||
const result = await generateStoryContent(project, chapterId || '', prompt, userWithPlan);
|
||||
|
||||
return NextResponse.json(result);
|
||||
// Increment usage in DB
|
||||
await prisma.user.update({
|
||||
where: { id: session.user.id },
|
||||
data: { aiActionsUsed: { increment: 1 } },
|
||||
});
|
||||
|
||||
return NextResponse.json({ ...result, aiActionsUsed: dbUser.aiActionsUsed + 1 });
|
||||
} catch (error) {
|
||||
console.error('AI generate error:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -1,10 +1,43 @@
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { auth } from '@/lib/auth';
|
||||
import getDB from '@/lib/prisma';
|
||||
import { transformTextServer } from '@/lib/gemini';
|
||||
|
||||
const PLAN_AI_LIMITS: Record<string, number> = {
|
||||
free: 100,
|
||||
pro: 5000,
|
||||
master: 999999,
|
||||
};
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Non autorisé' }, { status: 401 });
|
||||
}
|
||||
|
||||
const prisma = getDB();
|
||||
|
||||
// Check AI usage limit from DB
|
||||
const dbUser = await prisma.user.findUnique({
|
||||
where: { id: session.user.id },
|
||||
select: { plan: true, aiActionsUsed: true },
|
||||
});
|
||||
|
||||
if (!dbUser) {
|
||||
return NextResponse.json({ error: 'Utilisateur non trouvé' }, { status: 404 });
|
||||
}
|
||||
|
||||
const limit = PLAN_AI_LIMITS[dbUser.plan] || PLAN_AI_LIMITS.free;
|
||||
if (dbUser.aiActionsUsed >= limit) {
|
||||
return NextResponse.json(
|
||||
{ error: `Limite de ${limit} actions IA atteinte pour le plan ${dbUser.plan}. Passez au plan supérieur !` },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { text, mode, context, user } = body;
|
||||
|
||||
@@ -17,7 +50,13 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
const result = await transformTextServer(text, mode, context || '', user);
|
||||
|
||||
return NextResponse.json({ text: result });
|
||||
// Increment usage in DB
|
||||
await prisma.user.update({
|
||||
where: { id: session.user.id },
|
||||
data: { aiActionsUsed: { increment: 1 } },
|
||||
});
|
||||
|
||||
return NextResponse.json({ text: result, aiActionsUsed: dbUser.aiActionsUsed + 1 });
|
||||
} catch (error) {
|
||||
console.error('AI transform error:', error);
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -22,6 +22,13 @@ export async function GET() {
|
||||
return NextResponse.json(projects);
|
||||
}
|
||||
|
||||
// Plan limits for project creation
|
||||
const PLAN_PROJECT_LIMITS: Record<string, number> = {
|
||||
free: 3,
|
||||
pro: 20,
|
||||
master: 999,
|
||||
};
|
||||
|
||||
// POST /api/projects — Create a new project
|
||||
export async function POST(request: NextRequest) {
|
||||
const session = await auth();
|
||||
@@ -29,9 +36,24 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Non autorisé' }, { status: 401 });
|
||||
}
|
||||
|
||||
const prisma = getDB();
|
||||
|
||||
// Check plan limit
|
||||
const user = await prisma.user.findUnique({ where: { id: session.user.id }, select: { plan: true } });
|
||||
const plan = user?.plan || 'free';
|
||||
const limit = PLAN_PROJECT_LIMITS[plan] || PLAN_PROJECT_LIMITS.free;
|
||||
const currentCount = await prisma.project.count({ where: { userId: session.user.id } });
|
||||
|
||||
if (currentCount >= limit) {
|
||||
return NextResponse.json(
|
||||
{ error: `Limite de ${limit} projets atteinte pour le plan ${plan}. Passez au plan supérieur !` },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
|
||||
const project = await getDB().project.create({
|
||||
const project = await prisma.project.create({
|
||||
data: {
|
||||
title: body.title || 'Nouveau Roman',
|
||||
author: body.author || session.user.name || 'Auteur',
|
||||
|
||||
74
src/app/api/user/profile/route.ts
Normal file
74
src/app/api/user/profile/route.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { auth } from '@/lib/auth';
|
||||
import getDB from '@/lib/prisma';
|
||||
|
||||
// GET /api/user/profile — Get current user profile with stats
|
||||
export async function GET() {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Non autorisé' }, { status: 401 });
|
||||
}
|
||||
|
||||
const prisma = getDB();
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: session.user.id },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'Utilisateur non trouvé' }, { status: 404 });
|
||||
}
|
||||
|
||||
// Compute total word count from all chapters content
|
||||
const chapters = await prisma.chapter.findMany({
|
||||
where: { project: { userId: session.user.id } },
|
||||
select: { content: true },
|
||||
});
|
||||
|
||||
const totalWords = chapters.reduce((total, chapter) => {
|
||||
const text = (chapter.content || '').replace(/<[^>]*>/g, ' ').trim();
|
||||
return total + (text ? text.split(/\s+/).length : 0);
|
||||
}, 0);
|
||||
|
||||
return NextResponse.json({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
avatar: user.avatar,
|
||||
bio: user.bio,
|
||||
plan: user.plan,
|
||||
aiActionsUsed: user.aiActionsUsed,
|
||||
dailyWordGoal: user.dailyWordGoal,
|
||||
writingStreak: user.writingStreak,
|
||||
lastWriteDate: user.lastWriteDate,
|
||||
createdAt: user.createdAt,
|
||||
totalWords,
|
||||
});
|
||||
}
|
||||
|
||||
// PUT /api/user/profile — Update user profile
|
||||
export async function PUT(request: NextRequest) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Non autorisé' }, { status: 401 });
|
||||
}
|
||||
|
||||
const prisma = getDB();
|
||||
const body = await request.json();
|
||||
|
||||
const data: Record<string, unknown> = {};
|
||||
if (body.name !== undefined) data.name = body.name;
|
||||
if (body.avatar !== undefined) data.avatar = body.avatar;
|
||||
if (body.bio !== undefined) data.bio = body.bio;
|
||||
if (body.dailyWordGoal !== undefined) data.dailyWordGoal = body.dailyWordGoal;
|
||||
if (body.writingStreak !== undefined) data.writingStreak = body.writingStreak;
|
||||
if (body.lastWriteDate !== undefined) data.lastWriteDate = body.lastWriteDate ? new Date(body.lastWriteDate) : null;
|
||||
|
||||
const updated = await prisma.user.update({
|
||||
where: { id: session.user.id },
|
||||
data,
|
||||
});
|
||||
|
||||
return NextResponse.json(updated);
|
||||
}
|
||||
@@ -39,10 +39,19 @@ export default function DashboardPage() {
|
||||
router.push(`/project/${id}`);
|
||||
}}
|
||||
onCreate={async () => {
|
||||
const id = await createProject();
|
||||
if (id) {
|
||||
setCurrentProjectId(id);
|
||||
router.push(`/project/${id}`);
|
||||
try {
|
||||
const id = await createProject();
|
||||
if (id) {
|
||||
setCurrentProjectId(id);
|
||||
router.push(`/project/${id}`);
|
||||
}
|
||||
} catch (err: any) {
|
||||
if (err?.message?.includes('Limite')) {
|
||||
alert(err.message);
|
||||
router.push('/pricing');
|
||||
} else {
|
||||
alert('Erreur lors de la création du projet');
|
||||
}
|
||||
}
|
||||
}}
|
||||
onLogout={() => {
|
||||
|
||||
Reference in New Issue
Block a user