src/app/api/auth/client/profil/route.ts
Annotation non disponible
Lance npm run annotate (nécessite ANTHROPIC_API_KEY dans .env.local) pour générer une annotation française par Claude Haiku 4.5.
Concepts détectés — comprends la théorie
ORM Prisma
5 occurrencesCe fichier accède à la base de données via Prisma. Prisma est l'ORM utilisé côté backend pour les requêtes typées sur PostgreSQL.
Voir l'article général
Route API Next.js
5 occurrencesCe fichier est une route API Next.js (App Router). Voir le contrat API complet pour les conventions de réponse et d'auth.
Voir l'article général
JWT / Auth backend
1 occurrenceCe fichier touche au système d'authentification (JWT, session, getSessionFromRequest). Voir le contrat API pour la logique complète.
Voir l'article général
3 exports
GETPOSTPATCH
Code source· typescript
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma/client";
import { getSession, getSessionFromRequest } from "@/lib/auth/session";
import bcrypt from "bcryptjs";
export async function GET(req: NextRequest) {
try {
const session = await getSession();
if (!session || session.role !== "CLIENT") {
return NextResponse.json({ error: "Non autorise" }, { status: 401 });
}
const client = await prisma.clientAccount.findUnique({
where: { id: session.userId },
select: {
id: true, name: true, prenom: true, email: true, phone: true,
dateNaissance: true, pays: true, langue: true, devise: true,
adresse: true, profilComplet: true, createdAt: true,
motDePasseHash: true,
},
});
if (!client) return NextResponse.json({ error: "Client introuvable" }, { status: 404 });
return NextResponse.json({
...client,
dateNaissance: client.dateNaissance?.toISOString().split("T")[0] ?? null,
aMotDePasse: !!client.motDePasseHash,
motDePasseHash: undefined,
});
} catch (error) {
console.error("profil GET error:", error);
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
}
}
export async function POST(req: NextRequest) {
try {
const session = await getSession();
if (!session || session.role !== "CLIENT") {
return NextResponse.json({ error: "Non autorise" }, { status: 401 });
}
const { nom, prenom, dateNaissance, pays, langue, devise, adresse, motDePasse, motDePasseActuel } = await req.json();
if (!nom || !prenom) {
return NextResponse.json({ error: "Nom et prenom requis" }, { status: 400 });
}
const updateData: Record<string, unknown> = {
name: nom,
prenom,
dateNaissance: dateNaissance ? new Date(dateNaissance) : null,
pays: pays || null,
langue: langue || "fr",
devise: devise || "FCFA",
adresse: adresse || null,
profilComplet: true,
};
// Gestion mot de passe
if (motDePasse) {
if (motDePasse.length < 8) {
return NextResponse.json({ error: "Mot de passe trop court (8 caractères min)" }, { status: 400 });
}
// Vérifier l'ancien mot de passe si existant
const client = await prisma.clientAccount.findUnique({
where: { id: session.userId },
select: { motDePasseHash: true },
});
if (client?.motDePasseHash && motDePasseActuel) {
const valide = await bcrypt.compare(motDePasseActuel, client.motDePasseHash);
if (!valide) {
return NextResponse.json({ error: "Mot de passe actuel incorrect" }, { status: 400 });
}
}
updateData.motDePasseHash = await bcrypt.hash(motDePasse, 10);
}
await prisma.clientAccount.update({
where: { id: session.userId },
data: updateData,
});
return NextResponse.json({ success: true });
} catch (error) {
console.error("profil error:", error);
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
}
}
// PATCH — mobile Bearer token, mise à jour profil après inscription OTP
export async function PATCH(req: NextRequest) {
try {
const session = await getSessionFromRequest(req);
if (!session || session.role !== "CLIENT") {
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
}
const { nom, prenom, dateNaissance, sexe, adresse, ville, pays, devise, langue } = await req.json();
if (!nom?.trim() || !prenom?.trim()) {
return NextResponse.json({ error: "Nom et prénom requis" }, { status: 400 });
}
const client = await prisma.clientAccount.update({
where: { id: session.userId },
data: {
nom: nom.trim(),
prenom: prenom.trim(),
dateNaissance: dateNaissance ? new Date(dateNaissance) : undefined,
sexe: sexe ?? undefined,
adresse: adresse?.trim() || undefined,
ville: ville?.trim() || undefined,
pays: pays?.trim() || undefined,
devise: devise || undefined,
langue: langue || undefined,
profilComplet: true,
lastSeenAt: new Date(),
},
select: { id: true, email: true, phone: true, nom: true, prenom: true, profilComplet: true },
});
return NextResponse.json({ success: true, user: client });
} catch (error) {
console.error("profil PATCH error:", error);
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
}
}
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma/client";
import { getSession, getSessionFromRequest } from "@/lib/auth/session";
import bcrypt from "bcryptjs";
export async function GET(req: NextRequest) {
try {
const session = await getSession();
if (!session || session.role !== "CLIENT") {
return NextResponse.json({ error: "Non autorise" }, { status: 401 });
}
const client = await prisma.clientAccount.findUnique({
where: { id: session.userId },
select: {
id: true, name: true, prenom: true, email: true, phone: true,
dateNaissance: true, pays: true, langue: true, devise: true,
adresse: true, profilComplet: true, createdAt: true,
motDePasseHash: true,
},
});
if (!client) return NextResponse.json({ error: "Client introuvable" }, { status: 404 });
return NextResponse.json({
...client,
dateNaissance: client.dateNaissance?.toISOString().split("T")[0] ?? null,
aMotDePasse: !!client.motDePasseHash,
motDePasseHash: undefined,
});
} catch (error) {
console.error("profil GET error:", error);
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
}
}
export async function POST(req: NextRequest) {
try {
const session = await getSession();
if (!session || session.role !== "CLIENT") {
return NextResponse.json({ error: "Non autorise" }, { status: 401 });
}
const { nom, prenom, dateNaissance, pays, langue, devise, adresse, motDePasse, motDePasseActuel } = await req.json();
if (!nom || !prenom) {
return NextResponse.json({ error: "Nom et prenom requis" }, { status: 400 });
}
const updateData: Record<string, unknown> = {
name: nom,
prenom,
dateNaissance: dateNaissance ? new Date(dateNaissance) : null,
pays: pays || null,
langue: langue || "fr",
devise: devise || "FCFA",
adresse: adresse || null,
profilComplet: true,
};
// Gestion mot de passe
if (motDePasse) {
if (motDePasse.length < 8) {
return NextResponse.json({ error: "Mot de passe trop court (8 caractères min)" }, { status: 400 });
}
// Vérifier l'ancien mot de passe si existant
const client = await prisma.clientAccount.findUnique({
where: { id: session.userId },
select: { motDePasseHash: true },
});
if (client?.motDePasseHash && motDePasseActuel) {
const valide = await bcrypt.compare(motDePasseActuel, client.motDePasseHash);
if (!valide) {
return NextResponse.json({ error: "Mot de passe actuel incorrect" }, { status: 400 });
}
}
updateData.motDePasseHash = await bcrypt.hash(motDePasse, 10);
}
await prisma.clientAccount.update({
where: { id: session.userId },
data: updateData,
});
return NextResponse.json({ success: true });
} catch (error) {
console.error("profil error:", error);
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
}
}
// PATCH — mobile Bearer token, mise à jour profil après inscription OTP
export async function PATCH(req: NextRequest) {
try {
const session = await getSessionFromRequest(req);
if (!session || session.role !== "CLIENT") {
return NextResponse.json({ error: "Non autorisé" }, { status: 401 });
}
const { nom, prenom, dateNaissance, sexe, adresse, ville, pays, devise, langue } = await req.json();
if (!nom?.trim() || !prenom?.trim()) {
return NextResponse.json({ error: "Nom et prénom requis" }, { status: 400 });
}
const client = await prisma.clientAccount.update({
where: { id: session.userId },
data: {
nom: nom.trim(),
prenom: prenom.trim(),
dateNaissance: dateNaissance ? new Date(dateNaissance) : undefined,
sexe: sexe ?? undefined,
adresse: adresse?.trim() || undefined,
ville: ville?.trim() || undefined,
pays: pays?.trim() || undefined,
devise: devise || undefined,
langue: langue || undefined,
profilComplet: true,
lastSeenAt: new Date(),
},
select: { id: true, email: true, phone: true, nom: true, prenom: true, profilComplet: true },
});
return NextResponse.json({ success: true, user: client });
} catch (error) {
console.error("profil PATCH error:", error);
return NextResponse.json({ error: "Erreur serveur" }, { status: 500 });
}
}