Refactor admin actions and improve code formatting: Standardize import statements, enhance error handling messages, and apply consistent formatting across event, user, and preference management functions for better readability and maintainability.
Some checks failed
Deploy with Docker Compose / deploy (push) Has been cancelled

This commit is contained in:
Julien Froidefond
2025-12-15 21:20:39 +01:00
parent 321da3176e
commit b790ee21f2
52 changed files with 12712 additions and 8554 deletions

View File

@@ -1,73 +1,79 @@
'use server'
"use server";
import { revalidatePath } from 'next/cache'
import { auth } from '@/lib/auth'
import { eventService } from '@/services/events/event.service'
import { Role, EventType } from '@/prisma/generated/prisma/client'
import { ValidationError, NotFoundError } from '@/services/errors'
import { revalidatePath } from "next/cache";
import { auth } from "@/lib/auth";
import { eventService } from "@/services/events/event.service";
import { Role, EventType } from "@/prisma/generated/prisma/client";
import { ValidationError, NotFoundError } from "@/services/errors";
function checkAdminAccess() {
return async () => {
const session = await auth()
const session = await auth();
if (!session?.user || session.user.role !== Role.ADMIN) {
throw new Error('Accès refusé')
}
return session
throw new Error("Accès refusé");
}
return session;
};
}
export async function createEvent(data: {
date: string
name: string
description?: string | null
type: string
room?: string | null
time?: string | null
maxPlaces?: number | null
date: string;
name: string;
description?: string | null;
type: string;
room?: string | null;
time?: string | null;
maxPlaces?: number | null;
}) {
try {
await checkAdminAccess()()
await checkAdminAccess()();
const event = await eventService.validateAndCreateEvent({
date: data.date,
name: data.name,
description: data.description ?? '',
description: data.description ?? "",
type: data.type as EventType,
room: data.room ?? undefined,
time: data.time ?? undefined,
maxPlaces: data.maxPlaces ?? undefined,
})
});
revalidatePath('/admin')
revalidatePath('/events')
revalidatePath('/')
revalidatePath("/admin");
revalidatePath("/events");
revalidatePath("/");
return { success: true, data: event }
return { success: true, data: event };
} catch (error) {
console.error('Error creating event:', error)
console.error("Error creating event:", error);
if (error instanceof ValidationError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof Error && error.message === 'Accès refusé') {
return { success: false, error: 'Accès refusé' }
if (error instanceof Error && error.message === "Accès refusé") {
return { success: false, error: "Accès refusé" };
}
return { success: false, error: 'Erreur lors de la création de l\'événement' }
return {
success: false,
error: "Erreur lors de la création de l'événement",
};
}
}
export async function updateEvent(eventId: string, data: {
date?: string
name?: string
description?: string | null
type?: string
room?: string | null
time?: string | null
maxPlaces?: number | null
}) {
export async function updateEvent(
eventId: string,
data: {
date?: string;
name?: string;
description?: string | null;
type?: string;
room?: string | null;
time?: string | null;
maxPlaces?: number | null;
}
) {
try {
await checkAdminAccess()()
await checkAdminAccess()();
const event = await eventService.validateAndUpdateEvent(eventId, {
date: data.date,
@@ -77,55 +83,60 @@ export async function updateEvent(eventId: string, data: {
room: data.room ?? undefined,
time: data.time ?? undefined,
maxPlaces: data.maxPlaces ?? undefined,
})
});
revalidatePath('/admin')
revalidatePath('/events')
revalidatePath('/')
revalidatePath("/admin");
revalidatePath("/events");
revalidatePath("/");
return { success: true, data: event }
return { success: true, data: event };
} catch (error) {
console.error('Error updating event:', error)
console.error("Error updating event:", error);
if (error instanceof ValidationError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof Error && error.message === 'Accès refusé') {
return { success: false, error: 'Accès refusé' }
if (error instanceof Error && error.message === "Accès refusé") {
return { success: false, error: "Accès refusé" };
}
return { success: false, error: 'Erreur lors de la mise à jour de l\'événement' }
return {
success: false,
error: "Erreur lors de la mise à jour de l'événement",
};
}
}
export async function deleteEvent(eventId: string) {
try {
await checkAdminAccess()()
await checkAdminAccess()();
const existingEvent = await eventService.getEventById(eventId)
const existingEvent = await eventService.getEventById(eventId);
if (!existingEvent) {
return { success: false, error: 'Événement non trouvé' }
return { success: false, error: "Événement non trouvé" };
}
await eventService.deleteEvent(eventId)
await eventService.deleteEvent(eventId);
revalidatePath('/admin')
revalidatePath('/events')
revalidatePath('/')
revalidatePath("/admin");
revalidatePath("/events");
revalidatePath("/");
return { success: true }
return { success: true };
} catch (error) {
console.error('Error deleting event:', error)
console.error("Error deleting event:", error);
if (error instanceof Error && error.message === 'Accès refusé') {
return { success: false, error: 'Accès refusé' }
if (error instanceof Error && error.message === "Accès refusé") {
return { success: false, error: "Accès refusé" };
}
return { success: false, error: 'Erreur lors de la suppression de l\'événement' }
return {
success: false,
error: "Erreur lors de la suppression de l'événement",
};
}
}

View File

@@ -1,48 +1,50 @@
'use server'
"use server";
import { revalidatePath } from 'next/cache'
import { auth } from '@/lib/auth'
import { sitePreferencesService } from '@/services/preferences/site-preferences.service'
import { Role } from '@/prisma/generated/prisma/client'
import { revalidatePath } from "next/cache";
import { auth } from "@/lib/auth";
import { sitePreferencesService } from "@/services/preferences/site-preferences.service";
import { Role } from "@/prisma/generated/prisma/client";
function checkAdminAccess() {
return async () => {
const session = await auth()
const session = await auth();
if (!session?.user || session.user.role !== Role.ADMIN) {
throw new Error('Accès refusé')
}
return session
throw new Error("Accès refusé");
}
return session;
};
}
export async function updateSitePreferences(data: {
homeBackground?: string | null
eventsBackground?: string | null
leaderboardBackground?: string | null
homeBackground?: string | null;
eventsBackground?: string | null;
leaderboardBackground?: string | null;
}) {
try {
await checkAdminAccess()()
await checkAdminAccess()();
const preferences = await sitePreferencesService.updateSitePreferences({
homeBackground: data.homeBackground,
eventsBackground: data.eventsBackground,
leaderboardBackground: data.leaderboardBackground,
})
});
revalidatePath('/admin')
revalidatePath('/')
revalidatePath('/events')
revalidatePath('/leaderboard')
revalidatePath("/admin");
revalidatePath("/");
revalidatePath("/events");
revalidatePath("/leaderboard");
return { success: true, data: preferences }
return { success: true, data: preferences };
} catch (error) {
console.error('Error updating admin preferences:', error)
console.error("Error updating admin preferences:", error);
if (error instanceof Error && error.message === 'Accès refusé') {
return { success: false, error: 'Accès refusé' }
if (error instanceof Error && error.message === "Accès refusé") {
return { success: false, error: "Accès refusé" };
}
return { success: false, error: 'Erreur lors de la mise à jour des préférences' }
return {
success: false,
error: "Erreur lors de la mise à jour des préférences",
};
}
}

View File

@@ -1,47 +1,55 @@
'use server'
"use server";
import { revalidatePath } from 'next/cache'
import { auth } from '@/lib/auth'
import { userService } from '@/services/users/user.service'
import { userStatsService } from '@/services/users/user-stats.service'
import { Role } from '@/prisma/generated/prisma/client'
import { revalidatePath } from "next/cache";
import { auth } from "@/lib/auth";
import { userService } from "@/services/users/user.service";
import { userStatsService } from "@/services/users/user-stats.service";
import { Role } from "@/prisma/generated/prisma/client";
import {
ValidationError,
NotFoundError,
ConflictError,
} from '@/services/errors'
} from "@/services/errors";
function checkAdminAccess() {
return async () => {
const session = await auth()
const session = await auth();
if (!session?.user || session.user.role !== Role.ADMIN) {
throw new Error('Accès refusé')
}
return session
throw new Error("Accès refusé");
}
return session;
};
}
export async function updateUser(userId: string, data: {
username?: string
avatar?: string | null
hpDelta?: number
xpDelta?: number
score?: number
level?: number
role?: string
}) {
export async function updateUser(
userId: string,
data: {
username?: string;
avatar?: string | null;
hpDelta?: number;
xpDelta?: number;
score?: number;
level?: number;
role?: string;
}
) {
try {
await checkAdminAccess()()
await checkAdminAccess()();
// Valider username si fourni
if (data.username !== undefined) {
try {
await userService.validateAndUpdateUserProfile(userId, { username: data.username })
await userService.validateAndUpdateUserProfile(userId, {
username: data.username,
});
} catch (error) {
if (error instanceof ValidationError || error instanceof ConflictError) {
return { success: false, error: error.message }
if (
error instanceof ValidationError ||
error instanceof ConflictError
) {
return { success: false, error: error.message };
}
throw error
throw error;
}
}
@@ -70,47 +78,52 @@ export async function updateUser(userId: string, data: {
maxXp: true,
avatar: true,
}
)
);
revalidatePath('/admin')
revalidatePath('/leaderboard')
revalidatePath("/admin");
revalidatePath("/leaderboard");
return { success: true, data: updatedUser }
return { success: true, data: updatedUser };
} catch (error) {
console.error('Error updating user:', error)
console.error("Error updating user:", error);
if (error instanceof Error && error.message === 'Accès refusé') {
return { success: false, error: 'Accès refusé' }
if (error instanceof Error && error.message === "Accès refusé") {
return { success: false, error: "Accès refusé" };
}
return { success: false, error: 'Erreur lors de la mise à jour de l\'utilisateur' }
return {
success: false,
error: "Erreur lors de la mise à jour de l'utilisateur",
};
}
}
export async function deleteUser(userId: string) {
try {
const session = await checkAdminAccess()()
const session = await checkAdminAccess()();
await userService.validateAndDeleteUser(userId, session.user.id)
await userService.validateAndDeleteUser(userId, session.user.id);
revalidatePath('/admin')
revalidatePath('/leaderboard')
revalidatePath("/admin");
revalidatePath("/leaderboard");
return { success: true }
return { success: true };
} catch (error) {
console.error('Error deleting user:', error)
console.error("Error deleting user:", error);
if (error instanceof ValidationError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof Error && error.message === 'Accès refusé') {
return { success: false, error: 'Accès refusé' }
if (error instanceof Error && error.message === "Accès refusé") {
return { success: false, error: "Accès refusé" };
}
return { success: false, error: 'Erreur lors de la suppression de l\'utilisateur' }
return {
success: false,
error: "Erreur lors de la suppression de l'utilisateur",
};
}
}

View File

@@ -1,25 +1,28 @@
'use server'
"use server";
import { revalidatePath } from 'next/cache'
import { auth } from '@/lib/auth'
import { challengeService } from '@/services/challenges/challenge.service'
import { revalidatePath } from "next/cache";
import { auth } from "@/lib/auth";
import { challengeService } from "@/services/challenges/challenge.service";
import {
ValidationError,
NotFoundError,
ConflictError,
} from '@/services/errors'
} from "@/services/errors";
export async function createChallenge(data: {
challengedId: string
title: string
description: string
pointsReward?: number
challengedId: string;
title: string;
description: string;
pointsReward?: number;
}) {
try {
const session = await auth()
const session = await auth();
if (!session?.user?.id) {
return { success: false, error: 'Vous devez être connecté pour créer un défi' }
return {
success: false,
error: "Vous devez être connecté pour créer un défi",
};
}
const challenge = await challengeService.createChallenge({
@@ -28,85 +31,99 @@ export async function createChallenge(data: {
title: data.title,
description: data.description,
pointsReward: data.pointsReward || 100,
})
});
revalidatePath('/challenges')
revalidatePath('/profile')
revalidatePath("/challenges");
revalidatePath("/profile");
return { success: true, message: 'Défi créé avec succès', data: challenge }
return { success: true, message: "Défi créé avec succès", data: challenge };
} catch (error) {
console.error('Create challenge error:', error)
console.error("Create challenge error:", error);
if (error instanceof ValidationError || error instanceof ConflictError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
return { success: false, error: 'Une erreur est survenue lors de la création du défi' }
return {
success: false,
error: "Une erreur est survenue lors de la création du défi",
};
}
}
export async function acceptChallenge(challengeId: string) {
try {
const session = await auth()
const session = await auth();
if (!session?.user?.id) {
return { success: false, error: 'Vous devez être connecté pour accepter un défi' }
return {
success: false,
error: "Vous devez être connecté pour accepter un défi",
};
}
const challenge = await challengeService.acceptChallenge(
challengeId,
session.user.id
)
);
revalidatePath('/challenges')
revalidatePath('/profile')
revalidatePath("/challenges");
revalidatePath("/profile");
return { success: true, message: 'Défi accepté', data: challenge }
return { success: true, message: "Défi accepté", data: challenge };
} catch (error) {
console.error('Accept challenge error:', error)
console.error("Accept challenge error:", error);
if (error instanceof ValidationError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
return { success: false, error: 'Une erreur est survenue lors de l\'acceptation du défi' }
return {
success: false,
error: "Une erreur est survenue lors de l'acceptation du défi",
};
}
}
export async function cancelChallenge(challengeId: string) {
try {
const session = await auth()
const session = await auth();
if (!session?.user?.id) {
return { success: false, error: 'Vous devez être connecté pour annuler un défi' }
return {
success: false,
error: "Vous devez être connecté pour annuler un défi",
};
}
const challenge = await challengeService.cancelChallenge(
challengeId,
session.user.id
)
);
revalidatePath('/challenges')
revalidatePath('/profile')
revalidatePath("/challenges");
revalidatePath("/profile");
return { success: true, message: 'Défi annulé', data: challenge }
return { success: true, message: "Défi annulé", data: challenge };
} catch (error) {
console.error('Cancel challenge error:', error)
console.error("Cancel challenge error:", error);
if (error instanceof ValidationError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
return { success: false, error: 'Une erreur est survenue lors de l\'annulation du défi' }
return {
success: false,
error: "Une erreur est survenue lors de l'annulation du défi",
};
}
}

View File

@@ -1,45 +1,47 @@
'use server'
"use server";
import { revalidatePath } from 'next/cache'
import { auth } from '@/lib/auth'
import { eventFeedbackService } from '@/services/events/event-feedback.service'
import {
ValidationError,
NotFoundError,
} from '@/services/errors'
import { revalidatePath } from "next/cache";
import { auth } from "@/lib/auth";
import { eventFeedbackService } from "@/services/events/event-feedback.service";
import { ValidationError, NotFoundError } from "@/services/errors";
export async function createFeedback(eventId: string, data: {
rating: number
comment?: string | null
}) {
export async function createFeedback(
eventId: string,
data: {
rating: number;
comment?: string | null;
}
) {
try {
const session = await auth()
const session = await auth();
if (!session?.user?.id) {
return { success: false, error: 'Non authentifié' }
return { success: false, error: "Non authentifié" };
}
const feedback = await eventFeedbackService.validateAndCreateFeedback(
session.user.id,
eventId,
{ rating: data.rating, comment: data.comment }
)
);
revalidatePath(`/feedback/${eventId}`)
revalidatePath('/events')
revalidatePath(`/feedback/${eventId}`);
revalidatePath("/events");
return { success: true, data: feedback }
return { success: true, data: feedback };
} catch (error) {
console.error('Error saving feedback:', error)
console.error("Error saving feedback:", error);
if (error instanceof ValidationError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
return { success: false, error: 'Erreur lors de l\'enregistrement du feedback' }
return {
success: false,
error: "Erreur lors de l'enregistrement du feedback",
};
}
}

View File

@@ -1,65 +1,77 @@
'use server'
"use server";
import { revalidatePath } from 'next/cache'
import { auth } from '@/lib/auth'
import { eventRegistrationService } from '@/services/events/event-registration.service'
import { revalidatePath } from "next/cache";
import { auth } from "@/lib/auth";
import { eventRegistrationService } from "@/services/events/event-registration.service";
import {
ValidationError,
NotFoundError,
ConflictError,
} from '@/services/errors'
} from "@/services/errors";
export async function registerForEvent(eventId: string) {
try {
const session = await auth()
const session = await auth();
if (!session?.user?.id) {
return { success: false, error: 'Vous devez être connecté pour vous inscrire' }
return {
success: false,
error: "Vous devez être connecté pour vous inscrire",
};
}
const registration = await eventRegistrationService.validateAndRegisterUser(
session.user.id,
eventId
)
);
revalidatePath('/events')
revalidatePath('/')
revalidatePath("/events");
revalidatePath("/");
return { success: true, message: 'Inscription réussie', data: registration }
return {
success: true,
message: "Inscription réussie",
data: registration,
};
} catch (error) {
console.error('Registration error:', error)
console.error("Registration error:", error);
if (error instanceof ValidationError || error instanceof ConflictError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
return { success: false, error: 'Une erreur est survenue lors de l\'inscription' }
return {
success: false,
error: "Une erreur est survenue lors de l'inscription",
};
}
}
export async function unregisterFromEvent(eventId: string) {
try {
const session = await auth()
const session = await auth();
if (!session?.user?.id) {
return { success: false, error: 'Vous devez être connecté' }
return { success: false, error: "Vous devez être connecté" };
}
await eventRegistrationService.unregisterUserFromEvent(
session.user.id,
eventId
)
);
revalidatePath('/events')
revalidatePath('/')
revalidatePath("/events");
revalidatePath("/");
return { success: true, message: 'Inscription annulée' }
return { success: true, message: "Inscription annulée" };
} catch (error) {
console.error('Unregistration error:', error)
return { success: false, error: 'Une erreur est survenue lors de l\'annulation' }
console.error("Unregistration error:", error);
return {
success: false,
error: "Une erreur est survenue lors de l'annulation",
};
}
}

View File

@@ -1,23 +1,20 @@
'use server'
"use server";
import { revalidatePath } from 'next/cache'
import { auth } from '@/lib/auth'
import { userService } from '@/services/users/user.service'
import {
ValidationError,
NotFoundError,
} from '@/services/errors'
import { revalidatePath } from "next/cache";
import { auth } from "@/lib/auth";
import { userService } from "@/services/users/user.service";
import { ValidationError, NotFoundError } from "@/services/errors";
export async function updatePassword(data: {
currentPassword: string
newPassword: string
confirmPassword: string
currentPassword: string;
newPassword: string;
confirmPassword: string;
}) {
try {
const session = await auth()
const session = await auth();
if (!session?.user) {
return { success: false, error: 'Non authentifié' }
return { success: false, error: "Non authentifié" };
}
await userService.validateAndUpdatePassword(
@@ -25,22 +22,24 @@ export async function updatePassword(data: {
data.currentPassword,
data.newPassword,
data.confirmPassword
)
);
revalidatePath('/profile')
revalidatePath("/profile");
return { success: true, message: 'Mot de passe modifié avec succès' }
return { success: true, message: "Mot de passe modifié avec succès" };
} catch (error) {
console.error('Error updating password:', error)
console.error("Error updating password:", error);
if (error instanceof ValidationError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
return { success: false, error: 'Erreur lors de la modification du mot de passe' }
return {
success: false,
error: "Erreur lors de la modification du mot de passe",
};
}
}

View File

@@ -1,25 +1,22 @@
'use server'
"use server";
import { revalidatePath } from 'next/cache'
import { auth } from '@/lib/auth'
import { userService } from '@/services/users/user.service'
import { CharacterClass } from '@/prisma/generated/prisma/client'
import {
ValidationError,
ConflictError,
} from '@/services/errors'
import { revalidatePath } from "next/cache";
import { auth } from "@/lib/auth";
import { userService } from "@/services/users/user.service";
import { CharacterClass } from "@/prisma/generated/prisma/client";
import { ValidationError, ConflictError } from "@/services/errors";
export async function updateProfile(data: {
username?: string
avatar?: string | null
bio?: string | null
characterClass?: string | null
username?: string;
avatar?: string | null;
bio?: string | null;
characterClass?: string | null;
}) {
try {
const session = await auth()
const session = await auth();
if (!session?.user) {
return { success: false, error: 'Non authentifié' }
return { success: false, error: "Non authentifié" };
}
const updatedUser = await userService.validateAndUpdateUserProfile(
@@ -28,7 +25,9 @@ export async function updateProfile(data: {
username: data.username,
avatar: data.avatar,
bio: data.bio,
characterClass: data.characterClass ? (data.characterClass as CharacterClass) : null,
characterClass: data.characterClass
? (data.characterClass as CharacterClass)
: null,
},
{
id: true,
@@ -44,20 +43,19 @@ export async function updateProfile(data: {
level: true,
score: true,
}
)
);
revalidatePath('/profile')
revalidatePath('/')
revalidatePath("/profile");
revalidatePath("/");
return { success: true, data: updatedUser }
return { success: true, data: updatedUser };
} catch (error) {
console.error('Error updating profile:', error)
console.error("Error updating profile:", error);
if (error instanceof ValidationError || error instanceof ConflictError) {
return { success: false, error: error.message }
return { success: false, error: error.message };
}
return { success: false, error: 'Erreur lors de la mise à jour du profil' }
return { success: false, error: "Erreur lors de la mise à jour du profil" };
}
}

View File

@@ -27,4 +27,3 @@ export async function GET() {
);
}
}

View File

@@ -38,4 +38,3 @@ export async function GET() {
);
}
}

View File

@@ -12,7 +12,8 @@ export async function GET() {
}
// Récupérer les préférences globales du site (ou créer si elles n'existent pas)
const sitePreferences = await sitePreferencesService.getOrCreateSitePreferences();
const sitePreferences =
await sitePreferencesService.getOrCreateSitePreferences();
return NextResponse.json(sitePreferences);
} catch (error) {

View File

@@ -7,11 +7,16 @@ export async function GET() {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ error: "Vous devez être connecté" }, { status: 401 });
return NextResponse.json(
{ error: "Vous devez être connecté" },
{ status: 401 }
);
}
// Récupérer tous les défis de l'utilisateur
const challenges = await challengeService.getUserChallenges(session.user.id);
const challenges = await challengeService.getUserChallenges(
session.user.id
);
return NextResponse.json(challenges);
} catch (error) {
@@ -22,4 +27,3 @@ export async function GET() {
);
}
}

View File

@@ -2,7 +2,6 @@ import { NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { eventRegistrationService } from "@/services/events/event-registration.service";
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }

View File

@@ -2,7 +2,6 @@ import { NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { eventFeedbackService } from "@/services/events/event-feedback.service";
export async function GET(
request: Request,
{ params }: { params: Promise<{ eventId: string }> }

View File

@@ -42,4 +42,3 @@ export async function GET() {
);
}
}

View File

@@ -30,10 +30,7 @@ export async function POST(request: Request) {
} catch (error) {
console.error("Error completing registration:", error);
if (
error instanceof ValidationError ||
error instanceof ConflictError
) {
if (error instanceof ValidationError || error instanceof ConflictError) {
return NextResponse.json({ error: error.message }, { status: 400 });
}
if (error instanceof NotFoundError) {

View File

@@ -7,7 +7,10 @@ export async function GET() {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ error: "Vous devez être connecté" }, { status: 401 });
return NextResponse.json(
{ error: "Vous devez être connecté" },
{ status: 401 }
);
}
// Récupérer tous les utilisateurs (pour sélectionner qui défier)
@@ -36,4 +39,3 @@ export async function GET() {
);
}
}

View File

@@ -25,4 +25,3 @@ export default async function ChallengesPage() {
</main>
);
}

View File

@@ -39,9 +39,7 @@ export default function StyleGuidePage() {
{/* Buttons */}
<Card variant="dark" className="p-6 mb-8">
<h2 className="text-2xl font-bold text-pixel-gold mb-6">
Buttons
</h2>
<h2 className="text-2xl font-bold text-pixel-gold mb-6">Buttons</h2>
<div className="space-y-6">
<div>
<h3 className="text-lg text-gray-300 mb-3">Variantes</h3>
@@ -103,15 +101,8 @@ export default function StyleGuidePage() {
type="password"
placeholder="••••••••"
/>
<Input
label="Number Input"
type="number"
placeholder="123"
/>
<Input
label="Date Input"
type="date"
/>
<Input label="Number Input" type="number" placeholder="123" />
<Input label="Date Input" type="date" />
</div>
</div>
<div>
@@ -320,11 +311,7 @@ export default function StyleGuidePage() {
<div className="space-y-6">
<div>
<h3 className="text-lg text-gray-300 mb-3">Interactif</h3>
<StarRating
value={rating}
onChange={setRating}
showValue
/>
<StarRating value={rating} onChange={setRating} showValue />
<p className="text-gray-400 text-sm mt-2">
Note sélectionnée : {rating}/5
</p>
@@ -356,21 +343,9 @@ export default function StyleGuidePage() {
<div>
<h3 className="text-lg text-gray-300 mb-3">Tailles</h3>
<div className="flex items-center gap-6">
<Avatar
src="/avatar-1.jpg"
username="User"
size="sm"
/>
<Avatar
src="/avatar-2.jpg"
username="User"
size="md"
/>
<Avatar
src="/avatar-3.jpg"
username="User"
size="lg"
/>
<Avatar src="/avatar-1.jpg" username="User" size="sm" />
<Avatar src="/avatar-2.jpg" username="User" size="md" />
<Avatar src="/avatar-3.jpg" username="User" size="lg" />
</div>
</div>
<div>
@@ -492,4 +467,3 @@ export default function StyleGuidePage() {
</main>
);
}

View File

@@ -19,7 +19,12 @@ interface AdminPanelProps {
initialPreferences: SitePreferences;
}
type AdminSection = "preferences" | "users" | "events" | "feedbacks" | "challenges";
type AdminSection =
| "preferences"
| "users"
| "events"
| "feedbacks"
| "challenges";
export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
const [activeSection, setActiveSection] =

View File

@@ -37,4 +37,3 @@ export default function Footer() {
</footer>
);
}

View File

@@ -2,7 +2,11 @@
import { useEffect, useState } from "react";
import { Avatar } from "@/components/ui";
import { getCharacterClassIcon, getCharacterClassName, type CharacterClass } from "@/lib/character-classes";
import {
getCharacterClassIcon,
getCharacterClassName,
type CharacterClass,
} from "@/lib/character-classes";
interface LeaderboardEntry {
rank: number;
@@ -99,7 +103,8 @@ export default function Leaderboard() {
</span>
{entry.characterClass && (
<span className="text-xs text-gray-400 uppercase tracking-wider">
[{getCharacterClassIcon(entry.characterClass)} {getCharacterClassName(entry.characterClass)}]
[{getCharacterClassIcon(entry.characterClass)}{" "}
{getCharacterClassName(entry.characterClass)}]
</span>
)}
</div>

View File

@@ -49,4 +49,3 @@ export default function BackgroundSection({
</section>
);
}

View File

@@ -30,7 +30,8 @@ export default function Badge({
}: BadgeProps) {
const variantStyles = {
default: {
backgroundColor: "color-mix(in srgb, var(--accent-color) 20%, transparent)",
backgroundColor:
"color-mix(in srgb, var(--accent-color) 20%, transparent)",
borderColor: "color-mix(in srgb, var(--accent-color) 50%, transparent)",
color: "var(--accent-color)",
},
@@ -45,7 +46,8 @@ export default function Badge({
color: "var(--yellow)",
},
danger: {
backgroundColor: "color-mix(in srgb, var(--destructive) 20%, transparent)",
backgroundColor:
"color-mix(in srgb, var(--destructive) 20%, transparent)",
borderColor: "color-mix(in srgb, var(--destructive) 50%, transparent)",
color: "var(--destructive)",
},
@@ -66,4 +68,3 @@ export default function Badge({
</span>
);
}

View File

@@ -39,4 +39,3 @@ export default function Card({
</div>
);
}

View File

@@ -26,4 +26,3 @@ export default function CloseButton({
</button>
);
}

View File

@@ -35,9 +35,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
}}
{...props}
/>
{error && (
<p className="text-red-400 text-xs mt-1">{error}</p>
)}
{error && <p className="text-red-400 text-xs mt-1">{error}</p>}
</div>
);
}
@@ -46,4 +44,3 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
Input.displayName = "Input";
export default Input;

View File

@@ -41,7 +41,8 @@ export default function Modal({
<div
className="fixed inset-0 z-[200] flex items-center justify-center p-4 backdrop-blur-sm"
style={{
backgroundColor: "color-mix(in srgb, var(--background) 80%, transparent)",
backgroundColor:
"color-mix(in srgb, var(--background) 80%, transparent)",
}}
onClick={closeOnOverlayClick ? onClose : undefined}
>
@@ -49,7 +50,8 @@ export default function Modal({
className={`border-2 rounded-lg w-full ${sizeClasses[size]} max-h-[90vh] overflow-y-auto shadow-2xl`}
style={{
backgroundColor: "var(--card-hover)",
borderColor: "color-mix(in srgb, var(--accent-color) 70%, transparent)",
borderColor:
"color-mix(in srgb, var(--accent-color) 70%, transparent)",
}}
onClick={(e) => e.stopPropagation()}
>
@@ -58,4 +60,3 @@ export default function Modal({
</div>
);
}

View File

@@ -10,7 +10,10 @@ interface ProgressBarProps extends HTMLAttributes<HTMLDivElement> {
label?: string;
}
const getGradientStyle = (variant: "hp" | "xp" | "default", percentage: number) => {
const getGradientStyle = (
variant: "hp" | "xp" | "default",
percentage: number
) => {
if (variant === "hp") {
if (percentage > 60) {
return {
@@ -50,7 +53,10 @@ export default function ProgressBar({
return (
<div className={className} {...props}>
{showLabel && (
<div className="flex justify-between text-xs mb-1" style={{ color: "var(--gray-400)" }}>
<div
className="flex justify-between text-xs mb-1"
style={{ color: "var(--gray-400)" }}
>
<span>{label || variant.toUpperCase()}</span>
<span>
{value} / {max}
@@ -74,7 +80,8 @@ export default function ProgressBar({
<div
className="absolute inset-0"
style={{
background: "linear-gradient(to right, transparent, color-mix(in srgb, var(--foreground) 10%, transparent), transparent)",
background:
"linear-gradient(to right, transparent, color-mix(in srgb, var(--foreground) 10%, transparent), transparent)",
}}
/>
</div>
@@ -88,4 +95,3 @@ export default function ProgressBar({
</div>
);
}

View File

@@ -60,7 +60,10 @@ export default function StarRating({
}}
className={`transition-transform hover:scale-110 disabled:hover:scale-100 disabled:cursor-not-allowed ${sizeClasses[size]}`}
style={{
color: star <= displayValue ? "var(--accent-color)" : "var(--gray-500)",
color:
star <= displayValue
? "var(--accent-color)"
: "var(--gray-500)",
}}
aria-label={`Noter ${star} étoile${star > 1 ? "s" : ""}`}
>
@@ -69,11 +72,8 @@ export default function StarRating({
))}
</div>
{showValue && value > 0 && (
<p className="text-gray-500 text-xs text-center">
{value}/5
</p>
<p className="text-gray-500 text-xs text-center">{value}/5</p>
)}
</div>
);
}

View File

@@ -10,7 +10,10 @@ interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
}
const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
({ label, error, showCharCount, maxLength, className = "", value, ...props }, ref) => {
(
{ label, error, showCharCount, maxLength, className = "", value, ...props },
ref
) => {
const charCount = typeof value === "string" ? value.length : 0;
return (
@@ -46,9 +49,7 @@ const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
{charCount}/{maxLength} caractères
</p>
)}
{error && (
<p className="text-red-400 text-xs mt-1">{error}</p>
)}
{error && <p className="text-red-400 text-xs mt-1">{error}</p>}
</div>
);
}
@@ -57,4 +58,3 @@ const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
Textarea.displayName = "Textarea";
export default Textarea;

View File

@@ -16,7 +16,8 @@ export default function ThemeToggle() {
}}
onMouseEnter={(e) => {
e.currentTarget.style.borderColor = "var(--accent-color)";
e.currentTarget.style.backgroundColor = "color-mix(in srgb, var(--accent-color) 10%, transparent)";
e.currentTarget.style.backgroundColor =
"color-mix(in srgb, var(--accent-color) 10%, transparent)";
}}
onMouseLeave={(e) => {
e.currentTarget.style.borderColor = "var(--border)";
@@ -28,4 +29,3 @@ export default function ThemeToggle() {
</button>
);
}

View File

@@ -12,4 +12,3 @@ export { default as BackgroundSection } from "./BackgroundSection";
export { default as Alert } from "./Alert";
export { default as CloseButton } from "./CloseButton";
export { default as ThemeToggle } from "./ThemeToggle";

View File

@@ -1,4 +1,3 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
@@ -13,42 +12,42 @@
* 🟢 You can import this file directly.
*/
import * as Prisma from './internal/prismaNamespaceBrowser'
export { Prisma }
export * as $Enums from './enums'
export * from './enums';
import * as Prisma from "./internal/prismaNamespaceBrowser";
export { Prisma };
export * as $Enums from "./enums";
export * from "./enums";
/**
* Model User
*
*/
export type User = Prisma.UserModel
export type User = Prisma.UserModel;
/**
* Model UserPreferences
*
*/
export type UserPreferences = Prisma.UserPreferencesModel
export type UserPreferences = Prisma.UserPreferencesModel;
/**
* Model Event
*
*/
export type Event = Prisma.EventModel
export type Event = Prisma.EventModel;
/**
* Model EventRegistration
*
*/
export type EventRegistration = Prisma.EventRegistrationModel
export type EventRegistration = Prisma.EventRegistrationModel;
/**
* Model EventFeedback
*
*/
export type EventFeedback = Prisma.EventFeedbackModel
export type EventFeedback = Prisma.EventFeedbackModel;
/**
* Model SitePreferences
*
*/
export type SitePreferences = Prisma.SitePreferencesModel
export type SitePreferences = Prisma.SitePreferencesModel;
/**
* Model Challenge
*
*/
export type Challenge = Prisma.ChallengeModel
export type Challenge = Prisma.ChallengeModel;

View File

@@ -1,4 +1,3 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
@@ -10,18 +9,18 @@
* 🟢 You can import this file directly.
*/
import * as process from 'node:process'
import * as path from 'node:path'
import { fileURLToPath } from 'node:url'
globalThis['__dirname'] = path.dirname(fileURLToPath(import.meta.url))
import * as process from "node:process";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
globalThis["__dirname"] = path.dirname(fileURLToPath(import.meta.url));
import * as runtime from "@prisma/client/runtime/client"
import * as $Enums from "./enums"
import * as $Class from "./internal/class"
import * as Prisma from "./internal/prismaNamespace"
import * as runtime from "@prisma/client/runtime/client";
import * as $Enums from "./enums";
import * as $Class from "./internal/class";
import * as Prisma from "./internal/prismaNamespace";
export * as $Enums from './enums'
export * from "./enums"
export * as $Enums from "./enums";
export * from "./enums";
/**
* ## Prisma Client
*
@@ -35,42 +34,48 @@ export * from "./enums"
*
* Read more in our [docs](https://pris.ly/d/client).
*/
export const PrismaClient = $Class.getPrismaClientClass()
export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
export { Prisma }
export const PrismaClient = $Class.getPrismaClientClass();
export type PrismaClient<
LogOpts extends Prisma.LogLevel = never,
OmitOpts extends Prisma.PrismaClientOptions["omit"] =
Prisma.PrismaClientOptions["omit"],
ExtArgs extends runtime.Types.Extensions.InternalArgs =
runtime.Types.Extensions.DefaultArgs,
> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>;
export { Prisma };
/**
* Model User
*
*/
export type User = Prisma.UserModel
export type User = Prisma.UserModel;
/**
* Model UserPreferences
*
*/
export type UserPreferences = Prisma.UserPreferencesModel
export type UserPreferences = Prisma.UserPreferencesModel;
/**
* Model Event
*
*/
export type Event = Prisma.EventModel
export type Event = Prisma.EventModel;
/**
* Model EventRegistration
*
*/
export type EventRegistration = Prisma.EventRegistrationModel
export type EventRegistration = Prisma.EventRegistrationModel;
/**
* Model EventFeedback
*
*/
export type EventFeedback = Prisma.EventFeedbackModel
export type EventFeedback = Prisma.EventFeedbackModel;
/**
* Model SitePreferences
*
*/
export type SitePreferences = Prisma.SitePreferencesModel
export type SitePreferences = Prisma.SitePreferencesModel;
/**
* Model Challenge
*
*/
export type Challenge = Prisma.ChallengeModel
export type Challenge = Prisma.ChallengeModel;

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +1,52 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck
/*
* This file exports all enum related types from the schema.
*
* 🟢 You can import this file directly.
*/
* This file exports all enum related types from the schema.
*
* 🟢 You can import this file directly.
*/
export const Role = {
USER: 'USER',
ADMIN: 'ADMIN'
} as const
export type Role = (typeof Role)[keyof typeof Role]
USER: "USER",
ADMIN: "ADMIN",
} as const;
export type Role = (typeof Role)[keyof typeof Role];
export const EventType = {
ATELIER: 'ATELIER',
KATA: 'KATA',
PRESENTATION: 'PRESENTATION',
LEARNING_HOUR: 'LEARNING_HOUR'
} as const
export type EventType = (typeof EventType)[keyof typeof EventType]
ATELIER: "ATELIER",
KATA: "KATA",
PRESENTATION: "PRESENTATION",
LEARNING_HOUR: "LEARNING_HOUR",
} as const;
export type EventType = (typeof EventType)[keyof typeof EventType];
export const CharacterClass = {
WARRIOR: 'WARRIOR',
MAGE: 'MAGE',
ROGUE: 'ROGUE',
RANGER: 'RANGER',
PALADIN: 'PALADIN',
ENGINEER: 'ENGINEER',
MERCHANT: 'MERCHANT',
SCHOLAR: 'SCHOLAR',
BERSERKER: 'BERSERKER',
NECROMANCER: 'NECROMANCER'
} as const
export type CharacterClass = (typeof CharacterClass)[keyof typeof CharacterClass]
WARRIOR: "WARRIOR",
MAGE: "MAGE",
ROGUE: "ROGUE",
RANGER: "RANGER",
PALADIN: "PALADIN",
ENGINEER: "ENGINEER",
MERCHANT: "MERCHANT",
SCHOLAR: "SCHOLAR",
BERSERKER: "BERSERKER",
NECROMANCER: "NECROMANCER",
} as const;
export type CharacterClass =
(typeof CharacterClass)[keyof typeof CharacterClass];
export const ChallengeStatus = {
PENDING: 'PENDING',
ACCEPTED: 'ACCEPTED',
COMPLETED: 'COMPLETED',
REJECTED: 'REJECTED',
CANCELLED: 'CANCELLED'
} as const
PENDING: "PENDING",
ACCEPTED: "ACCEPTED",
COMPLETED: "COMPLETED",
REJECTED: "REJECTED",
CANCELLED: "CANCELLED",
} as const;
export type ChallengeStatus = (typeof ChallengeStatus)[keyof typeof ChallengeStatus]
export type ChallengeStatus =
(typeof ChallengeStatus)[keyof typeof ChallengeStatus];

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
@@ -15,183 +14,185 @@
* model files in the `model` directory!
*/
import * as runtime from "@prisma/client/runtime/index-browser"
import * as runtime from "@prisma/client/runtime/index-browser";
export type * from '../models'
export type * from './prismaNamespace'
export const Decimal = runtime.Decimal
export type * from "../models";
export type * from "./prismaNamespace";
export const Decimal = runtime.Decimal;
export const NullTypes = {
DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull),
JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull),
AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull),
}
DbNull: runtime.NullTypes.DbNull as new (
secret: never
) => typeof runtime.DbNull,
JsonNull: runtime.NullTypes.JsonNull as new (
secret: never
) => typeof runtime.JsonNull,
AnyNull: runtime.NullTypes.AnyNull as new (
secret: never
) => typeof runtime.AnyNull,
};
/**
* Helper for filtering JSON entries that have `null` on the database (empty on the db)
*
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
*/
export const DbNull = runtime.DbNull
export const DbNull = runtime.DbNull;
/**
* Helper for filtering JSON entries that have JSON `null` values (not empty on the db)
*
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
*/
export const JsonNull = runtime.JsonNull
export const JsonNull = runtime.JsonNull;
/**
* Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull`
*
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
*/
export const AnyNull = runtime.AnyNull
export const AnyNull = runtime.AnyNull;
export const ModelName = {
User: 'User',
UserPreferences: 'UserPreferences',
Event: 'Event',
EventRegistration: 'EventRegistration',
EventFeedback: 'EventFeedback',
SitePreferences: 'SitePreferences',
Challenge: 'Challenge'
} as const
User: "User",
UserPreferences: "UserPreferences",
Event: "Event",
EventRegistration: "EventRegistration",
EventFeedback: "EventFeedback",
SitePreferences: "SitePreferences",
Challenge: "Challenge",
} as const;
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
export type ModelName = (typeof ModelName)[keyof typeof ModelName];
/*
* Enums
*/
export const TransactionIsolationLevel = {
Serializable: 'Serializable'
} as const
export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel]
Serializable: "Serializable",
} as const;
export type TransactionIsolationLevel =
(typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel];
export const UserScalarFieldEnum = {
id: 'id',
email: 'email',
password: 'password',
username: 'username',
role: 'role',
score: 'score',
level: 'level',
hp: 'hp',
maxHp: 'maxHp',
xp: 'xp',
maxXp: 'maxXp',
avatar: 'avatar',
createdAt: 'createdAt',
updatedAt: 'updatedAt',
bio: 'bio',
characterClass: 'characterClass'
} as const
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
id: "id",
email: "email",
password: "password",
username: "username",
role: "role",
score: "score",
level: "level",
hp: "hp",
maxHp: "maxHp",
xp: "xp",
maxXp: "maxXp",
avatar: "avatar",
createdAt: "createdAt",
updatedAt: "updatedAt",
bio: "bio",
characterClass: "characterClass",
} as const;
export type UserScalarFieldEnum =
(typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum];
export const UserPreferencesScalarFieldEnum = {
id: 'id',
userId: 'userId',
homeBackground: 'homeBackground',
eventsBackground: 'eventsBackground',
leaderboardBackground: 'leaderboardBackground',
theme: 'theme',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type UserPreferencesScalarFieldEnum = (typeof UserPreferencesScalarFieldEnum)[keyof typeof UserPreferencesScalarFieldEnum]
id: "id",
userId: "userId",
homeBackground: "homeBackground",
eventsBackground: "eventsBackground",
leaderboardBackground: "leaderboardBackground",
theme: "theme",
createdAt: "createdAt",
updatedAt: "updatedAt",
} as const;
export type UserPreferencesScalarFieldEnum =
(typeof UserPreferencesScalarFieldEnum)[keyof typeof UserPreferencesScalarFieldEnum];
export const EventScalarFieldEnum = {
id: 'id',
date: 'date',
name: 'name',
description: 'description',
type: 'type',
room: 'room',
time: 'time',
maxPlaces: 'maxPlaces',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type EventScalarFieldEnum = (typeof EventScalarFieldEnum)[keyof typeof EventScalarFieldEnum]
id: "id",
date: "date",
name: "name",
description: "description",
type: "type",
room: "room",
time: "time",
maxPlaces: "maxPlaces",
createdAt: "createdAt",
updatedAt: "updatedAt",
} as const;
export type EventScalarFieldEnum =
(typeof EventScalarFieldEnum)[keyof typeof EventScalarFieldEnum];
export const EventRegistrationScalarFieldEnum = {
id: 'id',
userId: 'userId',
eventId: 'eventId',
createdAt: 'createdAt'
} as const
export type EventRegistrationScalarFieldEnum = (typeof EventRegistrationScalarFieldEnum)[keyof typeof EventRegistrationScalarFieldEnum]
id: "id",
userId: "userId",
eventId: "eventId",
createdAt: "createdAt",
} as const;
export type EventRegistrationScalarFieldEnum =
(typeof EventRegistrationScalarFieldEnum)[keyof typeof EventRegistrationScalarFieldEnum];
export const EventFeedbackScalarFieldEnum = {
id: 'id',
userId: 'userId',
eventId: 'eventId',
rating: 'rating',
comment: 'comment',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type EventFeedbackScalarFieldEnum = (typeof EventFeedbackScalarFieldEnum)[keyof typeof EventFeedbackScalarFieldEnum]
id: "id",
userId: "userId",
eventId: "eventId",
rating: "rating",
comment: "comment",
createdAt: "createdAt",
updatedAt: "updatedAt",
} as const;
export type EventFeedbackScalarFieldEnum =
(typeof EventFeedbackScalarFieldEnum)[keyof typeof EventFeedbackScalarFieldEnum];
export const SitePreferencesScalarFieldEnum = {
id: 'id',
homeBackground: 'homeBackground',
eventsBackground: 'eventsBackground',
leaderboardBackground: 'leaderboardBackground',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type SitePreferencesScalarFieldEnum = (typeof SitePreferencesScalarFieldEnum)[keyof typeof SitePreferencesScalarFieldEnum]
id: "id",
homeBackground: "homeBackground",
eventsBackground: "eventsBackground",
leaderboardBackground: "leaderboardBackground",
createdAt: "createdAt",
updatedAt: "updatedAt",
} as const;
export type SitePreferencesScalarFieldEnum =
(typeof SitePreferencesScalarFieldEnum)[keyof typeof SitePreferencesScalarFieldEnum];
export const ChallengeScalarFieldEnum = {
id: 'id',
challengerId: 'challengerId',
challengedId: 'challengedId',
title: 'title',
description: 'description',
pointsReward: 'pointsReward',
status: 'status',
adminId: 'adminId',
adminComment: 'adminComment',
winnerId: 'winnerId',
createdAt: 'createdAt',
acceptedAt: 'acceptedAt',
completedAt: 'completedAt',
updatedAt: 'updatedAt'
} as const
export type ChallengeScalarFieldEnum = (typeof ChallengeScalarFieldEnum)[keyof typeof ChallengeScalarFieldEnum]
id: "id",
challengerId: "challengerId",
challengedId: "challengedId",
title: "title",
description: "description",
pointsReward: "pointsReward",
status: "status",
adminId: "adminId",
adminComment: "adminComment",
winnerId: "winnerId",
createdAt: "createdAt",
acceptedAt: "acceptedAt",
completedAt: "completedAt",
updatedAt: "updatedAt",
} as const;
export type ChallengeScalarFieldEnum =
(typeof ChallengeScalarFieldEnum)[keyof typeof ChallengeScalarFieldEnum];
export const SortOrder = {
asc: 'asc',
desc: 'desc'
} as const
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
asc: "asc",
desc: "desc",
} as const;
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder];
export const NullsOrder = {
first: 'first',
last: 'last'
} as const
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
first: "first",
last: "last",
} as const;
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder];

View File

@@ -1,4 +1,3 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
@@ -8,11 +7,11 @@
*
* 🟢 You can import this file directly.
*/
export type * from './models/User'
export type * from './models/UserPreferences'
export type * from './models/Event'
export type * from './models/EventRegistration'
export type * from './models/EventFeedback'
export type * from './models/SitePreferences'
export type * from './models/Challenge'
export type * from './commonInputTypes'
export type * from "./models/User";
export type * from "./models/UserPreferences";
export type * from "./models/Event";
export type * from "./models/EventRegistration";
export type * from "./models/EventFeedback";
export type * from "./models/SitePreferences";
export type * from "./models/Challenge";
export type * from "./commonInputTypes";

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4,4 +4,3 @@
* Tous les services doivent importer depuis ici, pas directement depuis lib/prisma.ts
*/
export { prisma } from "@/lib/prisma";

View File

@@ -2,14 +2,20 @@
* Erreurs métier personnalisées
*/
export class BusinessError extends Error {
constructor(message: string, public code?: string) {
constructor(
message: string,
public code?: string
) {
super(message);
this.name = "BusinessError";
}
}
export class ValidationError extends BusinessError {
constructor(message: string, public field?: string) {
constructor(
message: string,
public field?: string
) {
super(message, "VALIDATION_ERROR");
this.name = "ValidationError";
}
@@ -28,4 +34,3 @@ export class ConflictError extends BusinessError {
this.name = "ConflictError";
}
}

View File

@@ -1,8 +1,5 @@
import { prisma } from "../database";
import type {
Event,
Prisma,
} from "@/prisma/generated/prisma/client";
import type { Event, Prisma } from "@/prisma/generated/prisma/client";
import { EventType } from "@/prisma/generated/prisma/client";
import { ValidationError, NotFoundError } from "../errors";
import { calculateEventStatus } from "@/lib/eventStatus";

View File

@@ -1,5 +1,10 @@
import { prisma } from "../database";
import type { User, Role, Prisma, CharacterClass } 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";