Alexis Bruneteau 14eff8d0da feat: Rebuild frontend with Next.js and shadcn/ui components
- 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>
2025-11-06 17:02:14 +01:00

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 é 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>
)
}