diff --git a/app/register/page.tsx b/app/register/page.tsx index bfcebfd..23b580e 100644 --- a/app/register/page.tsx +++ b/app/register/page.tsx @@ -14,6 +14,7 @@ import { BackgroundSection, SectionTitle, } from "@/components/ui"; +import { CHARACTER_CLASSES } from "@/lib/character-classes"; export default function RegisterPage() { const router = useRouter(); @@ -397,22 +398,7 @@ export default function RegisterPage() { Classe de Personnage (optionnel)
- {[ - { value: "WARRIOR", name: "Guerrier", icon: "⚔️" }, - { value: "MAGE", name: "Mage", icon: "🔮" }, - { value: "ROGUE", name: "Voleur", icon: "🗡️" }, - { value: "RANGER", name: "Rôdeur", icon: "🏹" }, - { value: "PALADIN", name: "Paladin", icon: "🛡️" }, - { value: "ENGINEER", name: "Ingénieur", icon: "⚙️" }, - { value: "MERCHANT", name: "Marchand", icon: "💰" }, - { value: "SCHOLAR", name: "Érudit", icon: "📚" }, - { value: "BERSERKER", name: "Berserker", icon: "🔥" }, - { - value: "NECROMANCER", - name: "Nécromancien", - icon: "💀", - }, - ].map((cls) => ( + {CHARACTER_CLASSES.map((cls) => (
@@ -177,34 +167,10 @@ export default function Leaderboard() { {selectedEntry.characterClass && (
- {selectedEntry.characterClass === "WARRIOR" && "⚔️"} - {selectedEntry.characterClass === "MAGE" && "🔮"} - {selectedEntry.characterClass === "ROGUE" && "🗡️"} - {selectedEntry.characterClass === "RANGER" && "🏹"} - {selectedEntry.characterClass === "PALADIN" && "🛡️"} - {selectedEntry.characterClass === "ENGINEER" && "⚙️"} - {selectedEntry.characterClass === "MERCHANT" && "💰"} - {selectedEntry.characterClass === "SCHOLAR" && "📚"} - {selectedEntry.characterClass === "BERSERKER" && "🔥"} - {selectedEntry.characterClass === "NECROMANCER" && "💀"} + {getCharacterClassIcon(selectedEntry.characterClass)} - {selectedEntry.characterClass === "WARRIOR" && - "Guerrier"} - {selectedEntry.characterClass === "MAGE" && "Mage"} - {selectedEntry.characterClass === "ROGUE" && "Voleur"} - {selectedEntry.characterClass === "RANGER" && "Rôdeur"} - {selectedEntry.characterClass === "PALADIN" && - "Paladin"} - {selectedEntry.characterClass === "ENGINEER" && - "Ingénieur"} - {selectedEntry.characterClass === "MERCHANT" && - "Marchand"} - {selectedEntry.characterClass === "SCHOLAR" && "Érudit"} - {selectedEntry.characterClass === "BERSERKER" && - "Berserker"} - {selectedEntry.characterClass === "NECROMANCER" && - "Nécromancien"} + {getCharacterClassName(selectedEntry.characterClass)}
)} diff --git a/components/leaderboard/LeaderboardSection.tsx b/components/leaderboard/LeaderboardSection.tsx index d34c080..e79367c 100644 --- a/components/leaderboard/LeaderboardSection.tsx +++ b/components/leaderboard/LeaderboardSection.tsx @@ -9,6 +9,11 @@ import { BackgroundSection, SectionTitle, } from "@/components/ui"; +import { + getCharacterClassIcon, + getCharacterClassName, + type CharacterClass, +} from "@/lib/character-classes"; interface LeaderboardEntry { rank: number; @@ -18,7 +23,7 @@ interface LeaderboardEntry { level: number; avatar?: string | null; bio?: string | null; - characterClass?: string | null; + characterClass?: CharacterClass | null; } interface LeaderboardSectionProps { @@ -111,16 +116,7 @@ export default function LeaderboardSection({ {entry.characterClass && ( - [{entry.characterClass === "WARRIOR" && "⚔️"} - {entry.characterClass === "MAGE" && "🔮"} - {entry.characterClass === "ROGUE" && "🗡️"} - {entry.characterClass === "RANGER" && "🏹"} - {entry.characterClass === "PALADIN" && "🛡️"} - {entry.characterClass === "ENGINEER" && "⚙️"} - {entry.characterClass === "MERCHANT" && "💰"} - {entry.characterClass === "SCHOLAR" && "📚"} - {entry.characterClass === "BERSERKER" && "🔥"} - {entry.characterClass === "NECROMANCER" && "💀"}] + [{getCharacterClassIcon(entry.characterClass)}] )} {entry.rank <= 3 && ( @@ -190,32 +186,10 @@ export default function LeaderboardSection({ {selectedEntry.characterClass && (
- {selectedEntry.characterClass === "WARRIOR" && "⚔️"} - {selectedEntry.characterClass === "MAGE" && "🔮"} - {selectedEntry.characterClass === "ROGUE" && "🗡️"} - {selectedEntry.characterClass === "RANGER" && "🏹"} - {selectedEntry.characterClass === "PALADIN" && "🛡️"} - {selectedEntry.characterClass === "ENGINEER" && "⚙️"} - {selectedEntry.characterClass === "MERCHANT" && "💰"} - {selectedEntry.characterClass === "SCHOLAR" && "📚"} - {selectedEntry.characterClass === "BERSERKER" && "🔥"} - {selectedEntry.characterClass === "NECROMANCER" && "💀"} + {getCharacterClassIcon(selectedEntry.characterClass)} - {selectedEntry.characterClass === "WARRIOR" && "Guerrier"} - {selectedEntry.characterClass === "MAGE" && "Mage"} - {selectedEntry.characterClass === "ROGUE" && "Voleur"} - {selectedEntry.characterClass === "RANGER" && "Rôdeur"} - {selectedEntry.characterClass === "PALADIN" && "Paladin"} - {selectedEntry.characterClass === "ENGINEER" && - "Ingénieur"} - {selectedEntry.characterClass === "MERCHANT" && - "Marchand"} - {selectedEntry.characterClass === "SCHOLAR" && "Érudit"} - {selectedEntry.characterClass === "BERSERKER" && - "Berserker"} - {selectedEntry.characterClass === "NECROMANCER" && - "Nécromancien"} + {getCharacterClassName(selectedEntry.characterClass)}
)} diff --git a/components/profile/ProfileForm.tsx b/components/profile/ProfileForm.tsx index f04d7ae..a29197f 100644 --- a/components/profile/ProfileForm.tsx +++ b/components/profile/ProfileForm.tsx @@ -1,22 +1,23 @@ "use client"; import { useState, useRef, useTransition, type ChangeEvent } from "react"; -import { Avatar, Input, Textarea, Button, Alert, Card, BackgroundSection, SectionTitle, ProgressBar } from "@/components/ui"; +import { + Avatar, + Input, + Textarea, + Button, + Alert, + Card, + BackgroundSection, + SectionTitle, + ProgressBar, +} from "@/components/ui"; import { updateProfile } from "@/actions/profile/update-profile"; import { updatePassword } from "@/actions/profile/update-password"; - -type CharacterClass = - | "WARRIOR" - | "MAGE" - | "ROGUE" - | "RANGER" - | "PALADIN" - | "ENGINEER" - | "MERCHANT" - | "SCHOLAR" - | "BERSERKER" - | "NECROMANCER" - | null; +import { + CHARACTER_CLASSES, + type CharacterClass, +} from "@/lib/character-classes"; interface UserProfile { id: string; @@ -24,7 +25,7 @@ interface UserProfile { username: string; avatar: string | null; bio: string | null; - characterClass: CharacterClass; + characterClass: CharacterClass | null; hp: number; maxHp: number; xp: number; @@ -55,7 +56,7 @@ export default function ProfileForm({ const [username, setUsername] = useState(initialProfile.username); const [avatar, setAvatar] = useState(initialProfile.avatar); const [bio, setBio] = useState(initialProfile.bio || null); - const [characterClass, setCharacterClass] = useState( + const [characterClass, setCharacterClass] = useState( initialProfile.characterClass || null ); const fileInputRef = useRef(null); @@ -120,12 +121,15 @@ export default function ProfileForm({ if (result.success && result.data) { setProfile({ ...result.data, - createdAt: result.data.createdAt instanceof Date - ? result.data.createdAt.toISOString() - : result.data.createdAt, + createdAt: + result.data.createdAt instanceof Date + ? result.data.createdAt.toISOString() + : result.data.createdAt, } as UserProfile); setBio(result.data.bio || null); - setCharacterClass(result.data.characterClass as CharacterClass || null); + setCharacterClass( + (result.data.characterClass as CharacterClass) || null + ); setSuccess("Profil mis à jour avec succès"); setTimeout(() => setSuccess(null), 3000); } else { @@ -154,7 +158,9 @@ export default function ProfileForm({ setShowPasswordForm(false); setTimeout(() => setSuccess(null), 3000); } else { - setError(result.error || "Erreur lors de la modification du mot de passe"); + setError( + result.error || "Erreur lors de la modification du mot de passe" + ); } }); }; @@ -163,7 +169,12 @@ export default function ProfileForm({
{/* Title Section */} - + PROFIL @@ -238,8 +249,15 @@ export default function ProfileForm({ id="avatar-upload" />
@@ -276,68 +294,7 @@ export default function ProfileForm({ Classe de Personnage
- {[ - { - value: "WARRIOR", - name: "Guerrier", - icon: "⚔️", - desc: "Maître du combat au corps à corps", - }, - { - value: "MAGE", - name: "Mage", - icon: "🔮", - desc: "Manipulateur des arcanes", - }, - { - value: "ROGUE", - name: "Voleur", - icon: "🗡️", - desc: "Furtif et mortel", - }, - { - value: "RANGER", - name: "Rôdeur", - icon: "🏹", - desc: "Chasseur des terres sauvages", - }, - { - value: "PALADIN", - name: "Paladin", - icon: "🛡️", - desc: "Protecteur sacré", - }, - { - value: "ENGINEER", - name: "Ingénieur", - icon: "⚙️", - desc: "Créateur d'artefacts", - }, - { - value: "MERCHANT", - name: "Marchand", - icon: "💰", - desc: "Maître du commerce", - }, - { - value: "SCHOLAR", - name: "Érudit", - icon: "📚", - desc: "Gardien du savoir", - }, - { - value: "BERSERKER", - name: "Berserker", - icon: "🔥", - desc: "Rage destructrice", - }, - { - value: "NECROMANCER", - name: "Nécromancien", - icon: "💀", - desc: "Maître des morts", - }, - ].map((cls) => ( + {CHARACTER_CLASSES.map((cls) => (
diff --git a/lib/character-classes.ts b/lib/character-classes.ts new file mode 100644 index 0000000..f86c72e --- /dev/null +++ b/lib/character-classes.ts @@ -0,0 +1,118 @@ +export type CharacterClass = + | "WARRIOR" + | "MAGE" + | "ROGUE" + | "RANGER" + | "PALADIN" + | "ENGINEER" + | "MERCHANT" + | "SCHOLAR" + | "BERSERKER" + | "NECROMANCER"; + +export interface CharacterClassConfig { + value: CharacterClass; + name: string; + icon: string; + desc?: string; +} + +export const CHARACTER_CLASSES: CharacterClassConfig[] = [ + { + value: "WARRIOR", + name: "Guerrier", + icon: "⚔️", + desc: "Maître du combat au corps à corps", + }, + { + value: "MAGE", + name: "Mage", + icon: "🔮", + desc: "Manipulateur des arcanes", + }, + { + value: "ROGUE", + name: "Voleur", + icon: "🗡️", + desc: "Furtif et mortel", + }, + { + value: "RANGER", + name: "Rôdeur", + icon: "🏹", + desc: "Chasseur des terres sauvages", + }, + { + value: "PALADIN", + name: "Paladin", + icon: "🛡️", + desc: "Protecteur sacré", + }, + { + value: "ENGINEER", + name: "Ingénieur", + icon: "⚙️", + desc: "Créateur d'artefacts", + }, + { + value: "MERCHANT", + name: "Marchand", + icon: "💰", + desc: "Maître du commerce", + }, + { + value: "SCHOLAR", + name: "Érudit", + icon: "📚", + desc: "Gardien du savoir", + }, + { + value: "BERSERKER", + name: "Berserker", + icon: "🔥", + desc: "Rage destructrice", + }, + { + value: "NECROMANCER", + name: "Nécromancien", + icon: "💀", + desc: "Maître des morts", + }, +]; + +export const CHARACTER_CLASS_MAP: Record = + CHARACTER_CLASSES.reduce( + (acc, cls) => { + acc[cls.value] = cls; + return acc; + }, + {} as Record + ); + +export function getCharacterClassIcon( + characterClass: CharacterClass | null | undefined +): string { + if (!characterClass) return ""; + return CHARACTER_CLASS_MAP[characterClass]?.icon || ""; +} + +export function getCharacterClassName( + characterClass: CharacterClass | null | undefined +): string { + if (!characterClass) return ""; + return CHARACTER_CLASS_MAP[characterClass]?.name || ""; +} + +export function getCharacterClassConfig( + characterClass: CharacterClass | null | undefined +): CharacterClassConfig | null { + if (!characterClass) return null; + return CHARACTER_CLASS_MAP[characterClass] || null; +} + +export function isValidCharacterClass( + characterClass: string | null | undefined +): characterClass is CharacterClass { + if (!characterClass) return false; + return characterClass in CHARACTER_CLASS_MAP; +} diff --git a/services/users/user-stats.service.ts b/services/users/user-stats.service.ts index 2535a15..6db381e 100644 --- a/services/users/user-stats.service.ts +++ b/services/users/user-stats.service.ts @@ -1,5 +1,5 @@ import { prisma } from "../database"; -import type { User, Role, Prisma } from "@/prisma/generated/prisma/client"; +import type { User, Role, Prisma, CharacterClass } from "@/prisma/generated/prisma/client"; import { NotFoundError } from "../errors"; import { userService } from "./user.service"; @@ -19,7 +19,7 @@ export interface LeaderboardEntry { level: number; avatar: string | null; bio: string | null; - characterClass: string | null; + characterClass: CharacterClass | null; } /** diff --git a/services/users/user.service.ts b/services/users/user.service.ts index c34e6cb..5683952 100644 --- a/services/users/user.service.ts +++ b/services/users/user.service.ts @@ -6,20 +6,7 @@ import type { Prisma, } from "@/prisma/generated/prisma/client"; import { ValidationError, NotFoundError, ConflictError } from "../errors"; - -// Constantes de validation -const VALID_CHARACTER_CLASSES = [ - "WARRIOR", - "MAGE", - "ROGUE", - "RANGER", - "PALADIN", - "ENGINEER", - "MERCHANT", - "SCHOLAR", - "BERSERKER", - "NECROMANCER", -] as const; +import { isValidCharacterClass } from "@/lib/character-classes"; const USERNAME_MIN_LENGTH = 3; const USERNAME_MAX_LENGTH = 20; @@ -305,10 +292,7 @@ export class UserService { } // Validation du characterClass - if ( - data.characterClass && - !VALID_CHARACTER_CLASSES.includes(data.characterClass as CharacterClass) - ) { + if (data.characterClass && !isValidCharacterClass(data.characterClass)) { throw new ValidationError( "Classe de personnage invalide", "characterClass" @@ -402,7 +386,7 @@ export class UserService { if ( data.characterClass !== undefined && data.characterClass !== null && - !VALID_CHARACTER_CLASSES.includes(data.characterClass as CharacterClass) + !isValidCharacterClass(data.characterClass) ) { throw new ValidationError( "Classe de personnage invalide",