SPB Git forge

spb/immbot-ai

Public
1commits 1branches 0releases
1.5 MBsize
maindefault branch
20 days agolast push
TypeScript 98.3% CSS 0.9% Shell 0.7%
3.4 KB · 82 lines tsx
Raw Blame History
1"use client";2import { useRouter, useSearchParams } from "next/navigation";3import { Suspense, useState } from "react";4import { ImmbotLogo, UqoLogo } from "@/components/logo";5import { Button, Card, Input, Label, Spinner } from "@/components/ui";67function ChangePasswordForm() {8  const router = useRouter();9  const forced = useSearchParams().get("force") === "1";10  const [current, setCurrent] = useState("");11  const [next, setNext] = useState("");12  const [confirm, setConfirm] = useState("");13  const [error, setError] = useState<string | null>(null);14  const [loading, setLoading] = useState(false);1516  async function submit(e: React.FormEvent) {17    e.preventDefault();18    setError(null);19    if (next !== confirm) return setError("La confirmation ne correspond pas.");20    setLoading(true);21    try {22      const res = await fetch("/api/auth/change-password", {23        method: "POST",24        headers: { "Content-Type": "application/json" },25        body: JSON.stringify({ currentPassword: current, newPassword: next }),26      });27      const data = await res.json();28      if (!res.ok) return setError(data.error ?? "Erreur.");29      router.push("/chat");30      router.refresh();31    } catch {32      setError("Impossible de joindre le serveur.");33    } finally {34      setLoading(false);35    }36  }3738  return (39    <Card className="w-full max-w-sm p-7 animate-fade-up">40      <h1 className="text-lg font-bold text-fg">Changer le mot de passe</h1>41      {forced ? (42        <p className="text-sm mt-2 text-amber-700 dark:text-amber-400 bg-amber-500/10 rounded-lg px-3 py-2.5">43          <strong>Sécurité :</strong> le mot de passe initial doit être remplacé avant d'utiliser la44          plateforme. Choisissez un mot de passe fort et unique.45        </p>46      ) : (47        <p className="text-sm text-muted mt-1">Choisissez un nouveau mot de passe (10 caractères minimum).</p>48      )}49      <form onSubmit={submit} className="mt-6 space-y-4">50        <div>51          <Label htmlFor="current">Mot de passe actuel</Label>52          <Input id="current" type="password" value={current} onChange={(e) => setCurrent(e.target.value)} autoComplete="current-password" required autoFocus />53        </div>54        <div>55          <Label htmlFor="next">Nouveau mot de passe</Label>56          <Input id="next" type="password" value={next} onChange={(e) => setNext(e.target.value)} autoComplete="new-password" required minLength={10} />57        </div>58        <div>59          <Label htmlFor="confirm">Confirmer le nouveau mot de passe</Label>60          <Input id="confirm" type="password" value={confirm} onChange={(e) => setConfirm(e.target.value)} autoComplete="new-password" required minLength={10} />61        </div>62        {error && <p className="text-sm text-red-600 dark:text-red-400 bg-red-500/10 rounded-lg px-3 py-2" role="alert">{error}</p>}63        <Button type="submit" className="w-full justify-center" disabled={loading}>64          {loading ? <Spinner /> : "Enregistrer et continuer"}65        </Button>66      </form>67    </Card>68  );69}7071export default function ChangePasswordPage() {72  return (73    <div className="min-h-dvh bg-app flex flex-col items-center justify-center px-4">74      <div className="mb-8"><ImmbotLogo size={34} /></div>75      <Suspense>76        <ChangePasswordForm />77      </Suspense>78      <div className="mt-8"><UqoLogo height={28} className="opacity-80 dark:invert" /></div>79    </div>80  );81}82