- Migrate from React CRA to Next.js 15 with modern architecture - Implement comprehensive shadcn/ui component library - Create complete dashboard system with layouts and navigation - Build authentication pages (login, register) with proper forms - Implement vote management pages (active, upcoming, history, archives) - Add user profile management with security settings - Configure Tailwind CSS with custom dark theme (accent: #e8704b) - Setup TypeScript with strict type checking - Backup old React-based frontend to .backups/frontend-old - All pages compile successfully and build passes linting Pages created: - Home page with hero section and features - Authentication (login/register) - Dashboard with stats and vote cards - Vote management (active, upcoming, history, archives) - User profile with form validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
296 lines
9.7 KiB
TypeScript
296 lines
9.7 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Label } from "@/components/ui/label"
|
|
import { CheckCircle, AlertCircle } from "lucide-react"
|
|
|
|
export default function ProfilePage() {
|
|
const [formData, setFormData] = useState({
|
|
firstName: "Jean",
|
|
lastName: "Dupont",
|
|
email: "jean.dupont@example.com",
|
|
phone: "+33 6 12 34 56 78",
|
|
address: "123 Rue de l'École",
|
|
city: "Paris",
|
|
postalCode: "75001",
|
|
country: "France",
|
|
})
|
|
|
|
const [passwordData, setPasswordData] = useState({
|
|
currentPassword: "",
|
|
newPassword: "",
|
|
confirmPassword: "",
|
|
})
|
|
|
|
const [showPasswords, setShowPasswords] = useState(false)
|
|
const [saveSuccess, setSaveSuccess] = useState(false)
|
|
|
|
const handleProfileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const { name, value } = e.target
|
|
setFormData((prev) => ({ ...prev, [name]: value }))
|
|
}
|
|
|
|
const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const { name, value } = e.target
|
|
setPasswordData((prev) => ({ ...prev, [name]: value }))
|
|
}
|
|
|
|
const handleSaveProfile = () => {
|
|
setSaveSuccess(true)
|
|
setTimeout(() => setSaveSuccess(false), 3000)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-8 max-w-4xl">
|
|
{/* Header */}
|
|
<div>
|
|
<h1 className="text-3xl font-bold">Mon Profil</h1>
|
|
<p className="text-muted-foreground mt-2">
|
|
Gérez vos informations personnelles et vos paramètres de sécurité
|
|
</p>
|
|
</div>
|
|
|
|
{/* Success Message */}
|
|
{saveSuccess && (
|
|
<div className="p-4 rounded-lg bg-accent/10 border border-accent/50 flex gap-3">
|
|
<CheckCircle className="w-5 h-5 text-accent flex-shrink-0 mt-0.5" />
|
|
<div>
|
|
<p className="text-sm font-medium text-accent">Succès</p>
|
|
<p className="text-sm text-accent/80">Vos modifications ont été sauvegardées</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Profile Information */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Informations Personnelles</CardTitle>
|
|
<CardDescription>
|
|
Mettez à jour vos informations de profil
|
|
</CardDescription>
|
|
</CardHeader>
|
|
|
|
<div className="p-6 space-y-6">
|
|
{/* Name Row */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="firstName">Prénom</Label>
|
|
<Input
|
|
id="firstName"
|
|
name="firstName"
|
|
value={formData.firstName}
|
|
onChange={handleProfileChange}
|
|
placeholder="Jean"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="lastName">Nom</Label>
|
|
<Input
|
|
id="lastName"
|
|
name="lastName"
|
|
value={formData.lastName}
|
|
onChange={handleProfileChange}
|
|
placeholder="Dupont"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Contact Info */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="email">Email</Label>
|
|
<Input
|
|
id="email"
|
|
name="email"
|
|
type="email"
|
|
value={formData.email}
|
|
onChange={handleProfileChange}
|
|
placeholder="email@example.com"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="phone">Téléphone</Label>
|
|
<Input
|
|
id="phone"
|
|
name="phone"
|
|
value={formData.phone}
|
|
onChange={handleProfileChange}
|
|
placeholder="+33 6 12 34 56 78"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Address */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="address">Adresse</Label>
|
|
<Input
|
|
id="address"
|
|
name="address"
|
|
value={formData.address}
|
|
onChange={handleProfileChange}
|
|
placeholder="123 Rue de l'École"
|
|
/>
|
|
</div>
|
|
|
|
{/* City, Postal, Country */}
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="city">Ville</Label>
|
|
<Input
|
|
id="city"
|
|
name="city"
|
|
value={formData.city}
|
|
onChange={handleProfileChange}
|
|
placeholder="Paris"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="postalCode">Code Postal</Label>
|
|
<Input
|
|
id="postalCode"
|
|
name="postalCode"
|
|
value={formData.postalCode}
|
|
onChange={handleProfileChange}
|
|
placeholder="75001"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="country">Pays</Label>
|
|
<Input
|
|
id="country"
|
|
name="country"
|
|
value={formData.country}
|
|
onChange={handleProfileChange}
|
|
placeholder="France"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<Button onClick={handleSaveProfile} className="w-full">
|
|
Enregistrer les modifications
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
|
|
{/* Security - Change Password */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Sécurité</CardTitle>
|
|
<CardDescription>
|
|
Gérez vos paramètres de sécurité et votre mot de passe
|
|
</CardDescription>
|
|
</CardHeader>
|
|
|
|
<div className="p-6 space-y-6">
|
|
<div className="bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
|
|
<div className="flex gap-3">
|
|
<AlertCircle className="w-5 h-5 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" />
|
|
<div>
|
|
<p className="text-sm font-medium text-blue-900 dark:text-blue-200">
|
|
Authentification à deux facteurs
|
|
</p>
|
|
<p className="text-sm text-blue-700 dark:text-blue-300 mt-1">
|
|
Activé et sécurisé par clé de cryptographie post-quantique
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 className="font-bold text-sm">Changer le mot de passe</h3>
|
|
|
|
{/* Current Password */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="currentPassword">Mot de passe actuel</Label>
|
|
<div className="relative">
|
|
<Input
|
|
id="currentPassword"
|
|
name="currentPassword"
|
|
type={showPasswords ? "text" : "password"}
|
|
value={passwordData.currentPassword}
|
|
onChange={handlePasswordChange}
|
|
placeholder="••••••••"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* New Password */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="newPassword">Nouveau mot de passe</Label>
|
|
<Input
|
|
id="newPassword"
|
|
name="newPassword"
|
|
type={showPasswords ? "text" : "password"}
|
|
value={passwordData.newPassword}
|
|
onChange={handlePasswordChange}
|
|
placeholder="••••••••"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="confirmPassword">Confirmer le mot de passe</Label>
|
|
<Input
|
|
id="confirmPassword"
|
|
name="confirmPassword"
|
|
type={showPasswords ? "text" : "password"}
|
|
value={passwordData.confirmPassword}
|
|
onChange={handlePasswordChange}
|
|
placeholder="••••••••"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<input
|
|
id="showPasswords"
|
|
type="checkbox"
|
|
checked={showPasswords}
|
|
onChange={(e) => setShowPasswords(e.target.checked)}
|
|
className="w-4 h-4 rounded border border-border"
|
|
/>
|
|
<Label htmlFor="showPasswords" className="text-sm">
|
|
Afficher les mots de passe
|
|
</Label>
|
|
</div>
|
|
|
|
<Button className="w-full">Mettre à jour le mot de passe</Button>
|
|
</div>
|
|
</Card>
|
|
|
|
{/* Account Management */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Gestion du Compte</CardTitle>
|
|
<CardDescription>
|
|
Paramètres et actions relatifs à votre compte
|
|
</CardDescription>
|
|
</CardHeader>
|
|
|
|
<div className="p-6 space-y-4">
|
|
<div>
|
|
<h3 className="font-bold text-sm mb-2">Sessions Actives</h3>
|
|
<p className="text-sm text-muted-foreground mb-3">
|
|
Vous avez 1 session active (ce navigateur)
|
|
</p>
|
|
<Button variant="outline" size="sm">
|
|
Déconnecter d'autres sessions
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="pt-4 border-t border-border space-y-3">
|
|
<h3 className="font-bold text-sm">Zone Dangereuse</h3>
|
|
<p className="text-sm text-muted-foreground">
|
|
Actions irréversibles sur votre compte
|
|
</p>
|
|
<Button variant="destructive" size="sm">
|
|
Supprimer mon compte
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|