Add name change functionality to user settings. Update SettingsPasswordForm to handle name updates, including validation and error handling. Fetch current user name for display in settings page.
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 2m44s

This commit is contained in:
Julien Froidefond
2026-02-20 14:47:32 +01:00
parent 8073321b0f
commit 160e90fbde
5 changed files with 170 additions and 6 deletions

View File

@@ -6,6 +6,26 @@ import { prisma } from "@/lib/db";
export type ActionResult = { success: true } | { success: false; error: string };
export async function changeName(newName: string): Promise<ActionResult> {
const session = await auth();
if (!session?.user?.id) return { success: false, error: "Non authentifié" };
const trimmed = newName.trim();
if (!trimmed) return { success: false, error: "Le nom ne peut pas être vide" };
if (trimmed.length > 64) return { success: false, error: "Le nom est trop long (64 caractères max)" };
try {
await prisma.user.update({
where: { id: session.user.id },
data: { name: trimmed },
});
return { success: true };
} catch (e) {
console.error("Name change error:", e);
return { success: false, error: "Erreur lors du changement de nom" };
}
}
export async function changePassword(
currentPassword: string,
newPassword: string

View File

@@ -1,13 +1,19 @@
import { redirect } from "next/navigation";
import { auth } from "@/auth";
import { prisma } from "@/lib/db";
import { getTemplates } from "@/lib/server-data";
import { NewEvaluationForm } from "@/components/NewEvaluationForm";
export default async function NewEvaluationPage() {
const [session, templates] = await Promise.all([auth(), getTemplates()]);
if (!session?.user) redirect("/auth/login");
if (!session?.user?.id) redirect("/auth/login");
const initialEvaluatorName = session.user.name || session.user.email || "";
const user = await prisma.user.findUnique({
where: { id: session.user.id },
select: { name: true, email: true },
});
const initialEvaluatorName = user?.name || user?.email || "";
return (
<NewEvaluationForm

View File

@@ -1,10 +1,16 @@
import { redirect } from "next/navigation";
import { auth } from "@/auth";
import { prisma } from "@/lib/db";
import { SettingsPasswordForm } from "@/components/SettingsPasswordForm";
export default async function SettingsPage() {
const session = await auth();
if (!session?.user) redirect("/auth/login");
if (!session?.user?.id) redirect("/auth/login");
return <SettingsPasswordForm />;
const user = await prisma.user.findUnique({
where: { id: session.user.id },
select: { name: true },
});
return <SettingsPasswordForm currentName={user?.name ?? ""} />;
}

View File

@@ -2,9 +2,35 @@
import { useState } from "react";
import Link from "next/link";
import { changePassword } from "@/actions/password";
import { changePassword, changeName } from "@/actions/password";
export function SettingsPasswordForm() {
export function SettingsPasswordForm({ currentName }: { currentName: string }) {
// --- Nom d'affichage ---
const [name, setName] = useState(currentName);
const [nameError, setNameError] = useState("");
const [nameSuccess, setNameSuccess] = useState(false);
const [nameLoading, setNameLoading] = useState(false);
async function handleNameSubmit(e: React.FormEvent) {
e.preventDefault();
setNameError("");
setNameSuccess(false);
setNameLoading(true);
try {
const result = await changeName(name);
if (result.success) {
setNameSuccess(true);
} else {
setNameError(result.error);
}
} catch {
setNameError("Erreur de connexion");
} finally {
setNameLoading(false);
}
}
// --- Mot de passe ---
const [currentPassword, setCurrentPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
@@ -49,6 +75,43 @@ export function SettingsPasswordForm() {
</h1>
<section className="rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800/50 p-4">
<h2 className="mb-4 font-mono text-sm font-medium text-zinc-700 dark:text-zinc-300">
Nom d&apos;affichage
</h2>
<form onSubmit={handleNameSubmit} className="space-y-4">
<div>
<label className="mb-1 block font-mono text-xs text-zinc-600 dark:text-zinc-400">
Nom
</label>
<input
type="text"
value={name}
onChange={(e) => { setName(e.target.value); setNameSuccess(false); }}
required
maxLength={64}
autoComplete="name"
className="w-full rounded border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 focus:border-cyan-500 focus:ring-1 focus:ring-cyan-500/30"
/>
</div>
{nameError && (
<p className="font-mono text-xs text-red-500">{nameError}</p>
)}
{nameSuccess && (
<p className="font-mono text-xs text-emerald-600 dark:text-emerald-400">
Nom modifié.
</p>
)}
<button
type="submit"
disabled={nameLoading}
className="rounded border border-cyan-500/50 bg-cyan-500/10 px-3 py-2 font-mono text-sm text-cyan-600 dark:text-cyan-400 hover:bg-cyan-500/20 disabled:opacity-50"
>
{nameLoading ? "..." : "Modifier le nom"}
</button>
</form>
</section>
<section className="mt-4 rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800/50 p-4">
<h2 className="mb-4 font-mono text-sm font-medium text-zinc-700 dark:text-zinc-300">
Changer mon mot de passe
</h2>