Add event registration and feedback points to site preferences: Update SitePreferences model and related components to include eventRegistrationPoints and eventFeedbackPoints, ensuring proper handling of user scores during event interactions.

This commit is contained in:
Julien Froidefond
2025-12-16 16:38:01 +01:00
parent f45cc1839e
commit 3dd82c2bd4
20 changed files with 652 additions and 19 deletions

View File

@@ -20,6 +20,8 @@ export async function updateSitePreferences(data: {
eventsBackground?: string | null; eventsBackground?: string | null;
leaderboardBackground?: string | null; leaderboardBackground?: string | null;
challengesBackground?: string | null; challengesBackground?: string | null;
eventRegistrationPoints?: number;
eventFeedbackPoints?: number;
}) { }) {
try { try {
await checkAdminAccess()(); await checkAdminAccess()();
@@ -29,6 +31,8 @@ export async function updateSitePreferences(data: {
eventsBackground: data.eventsBackground, eventsBackground: data.eventsBackground,
leaderboardBackground: data.leaderboardBackground, leaderboardBackground: data.leaderboardBackground,
challengesBackground: data.challengesBackground, challengesBackground: data.challengesBackground,
eventRegistrationPoints: data.eventRegistrationPoints,
eventFeedbackPoints: data.eventFeedbackPoints,
}); });
revalidatePath("/admin"); revalidatePath("/admin");

View File

@@ -128,6 +128,9 @@ export default function FeedbackPageClient({
}); });
} }
// Rafraîchir le score dans le header
window.dispatchEvent(new Event("refreshUserScore"));
// Rediriger après 2 secondes // Rediriger après 2 secondes
setTimeout(() => { setTimeout(() => {
router.push("/events"); router.push("/events");

View File

@@ -6,6 +6,8 @@ import EventManagement from "@/components/admin/EventManagement";
import FeedbackManagement from "@/components/admin/FeedbackManagement"; import FeedbackManagement from "@/components/admin/FeedbackManagement";
import ChallengeManagement from "@/components/admin/ChallengeManagement"; import ChallengeManagement from "@/components/admin/ChallengeManagement";
import BackgroundPreferences from "@/components/admin/BackgroundPreferences"; import BackgroundPreferences from "@/components/admin/BackgroundPreferences";
import EventPointsPreferences from "@/components/admin/EventPointsPreferences";
import EventFeedbackPointsPreferences from "@/components/admin/EventFeedbackPointsPreferences";
import { Button, Card, SectionTitle } from "@/components/ui"; import { Button, Card, SectionTitle } from "@/components/ui";
interface SitePreferences { interface SitePreferences {
@@ -14,6 +16,8 @@ interface SitePreferences {
eventsBackground: string | null; eventsBackground: string | null;
leaderboardBackground: string | null; leaderboardBackground: string | null;
challengesBackground: string | null; challengesBackground: string | null;
eventRegistrationPoints: number;
eventFeedbackPoints: number;
} }
interface AdminPanelProps { interface AdminPanelProps {
@@ -93,6 +97,8 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<BackgroundPreferences initialPreferences={initialPreferences} /> <BackgroundPreferences initialPreferences={initialPreferences} />
<EventPointsPreferences initialPreferences={initialPreferences} />
<EventFeedbackPointsPreferences initialPreferences={initialPreferences} />
</div> </div>
</Card> </Card>
)} )}

View File

@@ -11,6 +11,7 @@ interface SitePreferences {
eventsBackground: string | null; eventsBackground: string | null;
leaderboardBackground: string | null; leaderboardBackground: string | null;
challengesBackground: string | null; challengesBackground: string | null;
eventRegistrationPoints?: number;
} }
interface BackgroundPreferencesProps { interface BackgroundPreferencesProps {

View File

@@ -0,0 +1,166 @@
"use client";
import { useState, useEffect } from "react";
import { updateSitePreferences } from "@/actions/admin/preferences";
import { Button, Card, Input } from "@/components/ui";
interface SitePreferences {
id: string;
eventFeedbackPoints: number;
}
interface EventFeedbackPointsPreferencesProps {
initialPreferences: SitePreferences;
}
export default function EventFeedbackPointsPreferences({
initialPreferences,
}: EventFeedbackPointsPreferencesProps) {
const [preferences, setPreferences] = useState<SitePreferences | null>(
initialPreferences
);
const [isEditing, setIsEditing] = useState(false);
const [formData, setFormData] = useState({
eventFeedbackPoints: initialPreferences.eventFeedbackPoints.toString(),
});
const [isSaving, setIsSaving] = useState(false);
// Synchroniser les préférences quand initialPreferences change
useEffect(() => {
setPreferences(initialPreferences);
setFormData({
eventFeedbackPoints: initialPreferences.eventFeedbackPoints.toString(),
});
}, [initialPreferences]);
const handleEdit = () => {
setIsEditing(true);
};
const handleSave = async () => {
const points = parseInt(formData.eventFeedbackPoints, 10);
if (isNaN(points) || points < 0) {
alert("Le nombre de points doit être un nombre positif");
return;
}
setIsSaving(true);
try {
const result = await updateSitePreferences({
eventFeedbackPoints: points,
});
if (result.success && result.data) {
setPreferences(result.data);
setFormData({
eventFeedbackPoints: result.data.eventFeedbackPoints.toString(),
});
setIsEditing(false);
} else {
console.error("Error updating preferences:", result.error);
alert(result.error || "Erreur lors de la mise à jour");
}
} catch (error) {
console.error("Error updating preferences:", error);
alert("Erreur lors de la mise à jour");
} finally {
setIsSaving(false);
}
};
const handleCancel = () => {
setIsEditing(false);
if (preferences) {
setFormData({
eventFeedbackPoints: preferences.eventFeedbackPoints.toString(),
});
}
};
return (
<Card variant="default" className="p-3 sm:p-4">
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3 mb-4">
<div className="min-w-0 flex-1">
<h3 className="text-pixel-gold font-bold text-base sm:text-lg break-words">
Points de feedback sur les événements
</h3>
<p className="text-gray-400 text-xs sm:text-sm">
Nombre de points attribués lorsqu&apos;un utilisateur donne un feedback à un événement (première fois uniquement)
</p>
</div>
{!isEditing && (
<Button
onClick={handleEdit}
variant="primary"
size="sm"
className="whitespace-nowrap flex-shrink-0"
>
Modifier
</Button>
)}
</div>
{isEditing ? (
<div className="space-y-4">
<div>
<label
htmlFor="eventFeedbackPoints"
className="block text-sm font-medium text-pixel-gold mb-2"
>
Points de feedback
</label>
<Input
id="eventFeedbackPoints"
type="number"
min="0"
value={formData.eventFeedbackPoints}
onChange={(e) =>
setFormData({
...formData,
eventFeedbackPoints: e.target.value,
})
}
placeholder="100"
className="w-full"
/>
<p className="text-xs text-gray-400 mt-1">
Les utilisateurs gagneront ce nombre de points lors de leur premier feedback sur un événement
</p>
</div>
<div className="flex flex-col sm:flex-row gap-2 pt-4">
<Button
onClick={handleSave}
variant="success"
size="md"
disabled={isSaving}
>
{isSaving ? "Enregistrement..." : "Enregistrer"}
</Button>
<Button
onClick={handleCancel}
variant="secondary"
size="md"
disabled={isSaving}
>
Annuler
</Button>
</div>
</div>
) : (
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
<span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[200px] flex-shrink-0">
Points actuels:
</span>
<div className="flex items-center gap-2">
<span className="text-lg sm:text-xl font-bold text-white">
{preferences?.eventFeedbackPoints ?? 100}
</span>
<span className="text-xs sm:text-sm text-gray-400">points</span>
</div>
</div>
)}
</Card>
);
}

View File

@@ -0,0 +1,166 @@
"use client";
import { useState, useEffect } from "react";
import { updateSitePreferences } from "@/actions/admin/preferences";
import { Button, Card, Input } from "@/components/ui";
interface SitePreferences {
id: string;
eventRegistrationPoints: number;
}
interface EventPointsPreferencesProps {
initialPreferences: SitePreferences;
}
export default function EventPointsPreferences({
initialPreferences,
}: EventPointsPreferencesProps) {
const [preferences, setPreferences] = useState<SitePreferences | null>(
initialPreferences
);
const [isEditing, setIsEditing] = useState(false);
const [formData, setFormData] = useState({
eventRegistrationPoints: initialPreferences.eventRegistrationPoints.toString(),
});
const [isSaving, setIsSaving] = useState(false);
// Synchroniser les préférences quand initialPreferences change
useEffect(() => {
setPreferences(initialPreferences);
setFormData({
eventRegistrationPoints: initialPreferences.eventRegistrationPoints.toString(),
});
}, [initialPreferences]);
const handleEdit = () => {
setIsEditing(true);
};
const handleSave = async () => {
const points = parseInt(formData.eventRegistrationPoints, 10);
if (isNaN(points) || points < 0) {
alert("Le nombre de points doit être un nombre positif");
return;
}
setIsSaving(true);
try {
const result = await updateSitePreferences({
eventRegistrationPoints: points,
});
if (result.success && result.data) {
setPreferences(result.data);
setFormData({
eventRegistrationPoints: result.data.eventRegistrationPoints.toString(),
});
setIsEditing(false);
} else {
console.error("Error updating preferences:", result.error);
alert(result.error || "Erreur lors de la mise à jour");
}
} catch (error) {
console.error("Error updating preferences:", error);
alert("Erreur lors de la mise à jour");
} finally {
setIsSaving(false);
}
};
const handleCancel = () => {
setIsEditing(false);
if (preferences) {
setFormData({
eventRegistrationPoints: preferences.eventRegistrationPoints.toString(),
});
}
};
return (
<Card variant="default" className="p-3 sm:p-4">
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3 mb-4">
<div className="min-w-0 flex-1">
<h3 className="text-pixel-gold font-bold text-base sm:text-lg break-words">
Points d&apos;inscription aux événements
</h3>
<p className="text-gray-400 text-xs sm:text-sm">
Nombre de points attribués lorsqu&apos;un utilisateur s&apos;inscrit à un événement
</p>
</div>
{!isEditing && (
<Button
onClick={handleEdit}
variant="primary"
size="sm"
className="whitespace-nowrap flex-shrink-0"
>
Modifier
</Button>
)}
</div>
{isEditing ? (
<div className="space-y-4">
<div>
<label
htmlFor="eventRegistrationPoints"
className="block text-sm font-medium text-pixel-gold mb-2"
>
Points d&apos;inscription
</label>
<Input
id="eventRegistrationPoints"
type="number"
min="0"
value={formData.eventRegistrationPoints}
onChange={(e) =>
setFormData({
...formData,
eventRegistrationPoints: e.target.value,
})
}
placeholder="100"
className="w-full"
/>
<p className="text-xs text-gray-400 mt-1">
Les utilisateurs gagneront ce nombre de points lors de leur inscription à un événement
</p>
</div>
<div className="flex flex-col sm:flex-row gap-2 pt-4">
<Button
onClick={handleSave}
variant="success"
size="md"
disabled={isSaving}
>
{isSaving ? "Enregistrement..." : "Enregistrer"}
</Button>
<Button
onClick={handleCancel}
variant="secondary"
size="md"
disabled={isSaving}
>
Annuler
</Button>
</div>
</div>
) : (
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
<span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[200px] flex-shrink-0">
Points actuels:
</span>
<div className="flex items-center gap-2">
<span className="text-lg sm:text-xl font-bold text-white">
{preferences?.eventRegistrationPoints ?? 100}
</span>
<span className="text-xs sm:text-sm text-gray-400">points</span>
</div>
</div>
)}
</Card>
);
}

View File

@@ -564,6 +564,8 @@ export default function EventsPageSection({
...prev, ...prev,
[eventId]: true, [eventId]: true,
})); }));
// Rafraîchir le score dans le header
window.dispatchEvent(new Event("refreshUserScore"));
} else { } else {
setError(result.error || "Une erreur est survenue"); setError(result.error || "Une erreur est survenue");
} }
@@ -583,6 +585,8 @@ export default function EventsPageSection({
...prev, ...prev,
[eventId]: false, [eventId]: false,
})); }));
// Rafraîchir le score dans le header
window.dispatchEvent(new Event("refreshUserScore"));
} else { } else {
setError(result.error || "Une erreur est survenue"); setError(result.error || "Une erreur est survenue");
} }

View File

@@ -155,6 +155,9 @@ export default function FeedbackModal({
}); });
} }
// Rafraîchir le score dans le header
window.dispatchEvent(new Event("refreshUserScore"));
// Fermer la modale après 1.5 secondes // Fermer la modale après 1.5 secondes
setTimeout(() => { setTimeout(() => {
onClose(); onClose();

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useEffect, useState } from "react"; import { useEffect, useState, useCallback } from "react";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import Link from "next/link"; import Link from "next/link";
import { Avatar } from "@/components/ui"; import { Avatar } from "@/components/ui";
@@ -42,6 +42,31 @@ export default function PlayerStats({ initialUserData }: PlayerStatsProps) {
initialUserData || defaultUserData initialUserData || defaultUserData
); );
const refreshUserData = useCallback(async () => {
if (!session?.user?.id) return;
try {
const res = await fetch(`/api/users/${session.user.id}`);
const data = await res.json();
if (data) {
requestAnimationFrame(() => {
setUserData({
username: data.username || "Guest",
avatar: data.avatar,
hp: data.hp || 1000,
maxHp: data.maxHp || 1000,
xp: data.xp || 0,
maxXp: data.maxXp || 5000,
level: data.level || 1,
score: data.score || 0,
});
});
}
} catch (error) {
console.error("Error refreshing user data:", error);
}
}, [session]);
useEffect(() => { useEffect(() => {
// Si on a déjà des données initiales, ne rien faire (déjà initialisé dans useState) // Si on a déjà des données initiales, ne rien faire (déjà initialisé dans useState)
if (initialUserData) { if (initialUserData) {
@@ -92,6 +117,18 @@ export default function PlayerStats({ initialUserData }: PlayerStatsProps) {
} }
}, [session, initialUserData]); }, [session, initialUserData]);
// Écouter les événements de refresh du score
useEffect(() => {
const handleRefreshScore = () => {
refreshUserData();
};
window.addEventListener("refreshUserScore", handleRefreshScore);
return () => {
window.removeEventListener("refreshUserScore", handleRefreshScore);
};
}, [refreshUserData]);
const { username, avatar, level, score } = userData; const { username, avatar, level, score } = userData;
return ( return (
@@ -136,7 +173,6 @@ export default function PlayerStats({ initialUserData }: PlayerStatsProps) {
</div> </div>
</div> </div>
</div> </div>
</div> </div>
); );
} }

File diff suppressed because one or more lines are too long

View File

@@ -1045,6 +1045,8 @@ export const SitePreferencesScalarFieldEnum = {
eventsBackground: 'eventsBackground', eventsBackground: 'eventsBackground',
leaderboardBackground: 'leaderboardBackground', leaderboardBackground: 'leaderboardBackground',
challengesBackground: 'challengesBackground', challengesBackground: 'challengesBackground',
eventRegistrationPoints: 'eventRegistrationPoints',
eventFeedbackPoints: 'eventFeedbackPoints',
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt' updatedAt: 'updatedAt'
} as const } as const

View File

@@ -154,6 +154,8 @@ export const SitePreferencesScalarFieldEnum = {
eventsBackground: 'eventsBackground', eventsBackground: 'eventsBackground',
leaderboardBackground: 'leaderboardBackground', leaderboardBackground: 'leaderboardBackground',
challengesBackground: 'challengesBackground', challengesBackground: 'challengesBackground',
eventRegistrationPoints: 'eventRegistrationPoints',
eventFeedbackPoints: 'eventFeedbackPoints',
createdAt: 'createdAt', createdAt: 'createdAt',
updatedAt: 'updatedAt' updatedAt: 'updatedAt'
} as const } as const

View File

@@ -20,16 +20,30 @@ export type SitePreferencesModel = runtime.Types.Result.DefaultSelection<Prisma.
export type AggregateSitePreferences = { export type AggregateSitePreferences = {
_count: SitePreferencesCountAggregateOutputType | null _count: SitePreferencesCountAggregateOutputType | null
_avg: SitePreferencesAvgAggregateOutputType | null
_sum: SitePreferencesSumAggregateOutputType | null
_min: SitePreferencesMinAggregateOutputType | null _min: SitePreferencesMinAggregateOutputType | null
_max: SitePreferencesMaxAggregateOutputType | null _max: SitePreferencesMaxAggregateOutputType | null
} }
export type SitePreferencesAvgAggregateOutputType = {
eventRegistrationPoints: number | null
eventFeedbackPoints: number | null
}
export type SitePreferencesSumAggregateOutputType = {
eventRegistrationPoints: number | null
eventFeedbackPoints: number | null
}
export type SitePreferencesMinAggregateOutputType = { export type SitePreferencesMinAggregateOutputType = {
id: string | null id: string | null
homeBackground: string | null homeBackground: string | null
eventsBackground: string | null eventsBackground: string | null
leaderboardBackground: string | null leaderboardBackground: string | null
challengesBackground: string | null challengesBackground: string | null
eventRegistrationPoints: number | null
eventFeedbackPoints: number | null
createdAt: Date | null createdAt: Date | null
updatedAt: Date | null updatedAt: Date | null
} }
@@ -40,6 +54,8 @@ export type SitePreferencesMaxAggregateOutputType = {
eventsBackground: string | null eventsBackground: string | null
leaderboardBackground: string | null leaderboardBackground: string | null
challengesBackground: string | null challengesBackground: string | null
eventRegistrationPoints: number | null
eventFeedbackPoints: number | null
createdAt: Date | null createdAt: Date | null
updatedAt: Date | null updatedAt: Date | null
} }
@@ -50,18 +66,32 @@ export type SitePreferencesCountAggregateOutputType = {
eventsBackground: number eventsBackground: number
leaderboardBackground: number leaderboardBackground: number
challengesBackground: number challengesBackground: number
eventRegistrationPoints: number
eventFeedbackPoints: number
createdAt: number createdAt: number
updatedAt: number updatedAt: number
_all: number _all: number
} }
export type SitePreferencesAvgAggregateInputType = {
eventRegistrationPoints?: true
eventFeedbackPoints?: true
}
export type SitePreferencesSumAggregateInputType = {
eventRegistrationPoints?: true
eventFeedbackPoints?: true
}
export type SitePreferencesMinAggregateInputType = { export type SitePreferencesMinAggregateInputType = {
id?: true id?: true
homeBackground?: true homeBackground?: true
eventsBackground?: true eventsBackground?: true
leaderboardBackground?: true leaderboardBackground?: true
challengesBackground?: true challengesBackground?: true
eventRegistrationPoints?: true
eventFeedbackPoints?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
} }
@@ -72,6 +102,8 @@ export type SitePreferencesMaxAggregateInputType = {
eventsBackground?: true eventsBackground?: true
leaderboardBackground?: true leaderboardBackground?: true
challengesBackground?: true challengesBackground?: true
eventRegistrationPoints?: true
eventFeedbackPoints?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
} }
@@ -82,6 +114,8 @@ export type SitePreferencesCountAggregateInputType = {
eventsBackground?: true eventsBackground?: true
leaderboardBackground?: true leaderboardBackground?: true
challengesBackground?: true challengesBackground?: true
eventRegistrationPoints?: true
eventFeedbackPoints?: true
createdAt?: true createdAt?: true
updatedAt?: true updatedAt?: true
_all?: true _all?: true
@@ -122,6 +156,18 @@ export type SitePreferencesAggregateArgs<ExtArgs extends runtime.Types.Extension
* Count returned SitePreferences * Count returned SitePreferences
**/ **/
_count?: true | SitePreferencesCountAggregateInputType _count?: true | SitePreferencesCountAggregateInputType
/**
* {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs}
*
* Select which fields to average
**/
_avg?: SitePreferencesAvgAggregateInputType
/**
* {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs}
*
* Select which fields to sum
**/
_sum?: SitePreferencesSumAggregateInputType
/** /**
* {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs}
* *
@@ -155,6 +201,8 @@ export type SitePreferencesGroupByArgs<ExtArgs extends runtime.Types.Extensions.
take?: number take?: number
skip?: number skip?: number
_count?: SitePreferencesCountAggregateInputType | true _count?: SitePreferencesCountAggregateInputType | true
_avg?: SitePreferencesAvgAggregateInputType
_sum?: SitePreferencesSumAggregateInputType
_min?: SitePreferencesMinAggregateInputType _min?: SitePreferencesMinAggregateInputType
_max?: SitePreferencesMaxAggregateInputType _max?: SitePreferencesMaxAggregateInputType
} }
@@ -165,9 +213,13 @@ export type SitePreferencesGroupByOutputType = {
eventsBackground: string | null eventsBackground: string | null
leaderboardBackground: string | null leaderboardBackground: string | null
challengesBackground: string | null challengesBackground: string | null
eventRegistrationPoints: number
eventFeedbackPoints: number
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
_count: SitePreferencesCountAggregateOutputType | null _count: SitePreferencesCountAggregateOutputType | null
_avg: SitePreferencesAvgAggregateOutputType | null
_sum: SitePreferencesSumAggregateOutputType | null
_min: SitePreferencesMinAggregateOutputType | null _min: SitePreferencesMinAggregateOutputType | null
_max: SitePreferencesMaxAggregateOutputType | null _max: SitePreferencesMaxAggregateOutputType | null
} }
@@ -196,6 +248,8 @@ export type SitePreferencesWhereInput = {
eventsBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null eventsBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null
leaderboardBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null leaderboardBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null
challengesBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null challengesBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null
eventRegistrationPoints?: Prisma.IntFilter<"SitePreferences"> | number
eventFeedbackPoints?: Prisma.IntFilter<"SitePreferences"> | number
createdAt?: Prisma.DateTimeFilter<"SitePreferences"> | Date | string createdAt?: Prisma.DateTimeFilter<"SitePreferences"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"SitePreferences"> | Date | string updatedAt?: Prisma.DateTimeFilter<"SitePreferences"> | Date | string
} }
@@ -206,6 +260,8 @@ export type SitePreferencesOrderByWithRelationInput = {
eventsBackground?: Prisma.SortOrderInput | Prisma.SortOrder eventsBackground?: Prisma.SortOrderInput | Prisma.SortOrder
leaderboardBackground?: Prisma.SortOrderInput | Prisma.SortOrder leaderboardBackground?: Prisma.SortOrderInput | Prisma.SortOrder
challengesBackground?: Prisma.SortOrderInput | Prisma.SortOrder challengesBackground?: Prisma.SortOrderInput | Prisma.SortOrder
eventRegistrationPoints?: Prisma.SortOrder
eventFeedbackPoints?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
} }
@@ -219,6 +275,8 @@ export type SitePreferencesWhereUniqueInput = Prisma.AtLeast<{
eventsBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null eventsBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null
leaderboardBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null leaderboardBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null
challengesBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null challengesBackground?: Prisma.StringNullableFilter<"SitePreferences"> | string | null
eventRegistrationPoints?: Prisma.IntFilter<"SitePreferences"> | number
eventFeedbackPoints?: Prisma.IntFilter<"SitePreferences"> | number
createdAt?: Prisma.DateTimeFilter<"SitePreferences"> | Date | string createdAt?: Prisma.DateTimeFilter<"SitePreferences"> | Date | string
updatedAt?: Prisma.DateTimeFilter<"SitePreferences"> | Date | string updatedAt?: Prisma.DateTimeFilter<"SitePreferences"> | Date | string
}, "id"> }, "id">
@@ -229,11 +287,15 @@ export type SitePreferencesOrderByWithAggregationInput = {
eventsBackground?: Prisma.SortOrderInput | Prisma.SortOrder eventsBackground?: Prisma.SortOrderInput | Prisma.SortOrder
leaderboardBackground?: Prisma.SortOrderInput | Prisma.SortOrder leaderboardBackground?: Prisma.SortOrderInput | Prisma.SortOrder
challengesBackground?: Prisma.SortOrderInput | Prisma.SortOrder challengesBackground?: Prisma.SortOrderInput | Prisma.SortOrder
eventRegistrationPoints?: Prisma.SortOrder
eventFeedbackPoints?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
_count?: Prisma.SitePreferencesCountOrderByAggregateInput _count?: Prisma.SitePreferencesCountOrderByAggregateInput
_avg?: Prisma.SitePreferencesAvgOrderByAggregateInput
_max?: Prisma.SitePreferencesMaxOrderByAggregateInput _max?: Prisma.SitePreferencesMaxOrderByAggregateInput
_min?: Prisma.SitePreferencesMinOrderByAggregateInput _min?: Prisma.SitePreferencesMinOrderByAggregateInput
_sum?: Prisma.SitePreferencesSumOrderByAggregateInput
} }
export type SitePreferencesScalarWhereWithAggregatesInput = { export type SitePreferencesScalarWhereWithAggregatesInput = {
@@ -245,6 +307,8 @@ export type SitePreferencesScalarWhereWithAggregatesInput = {
eventsBackground?: Prisma.StringNullableWithAggregatesFilter<"SitePreferences"> | string | null eventsBackground?: Prisma.StringNullableWithAggregatesFilter<"SitePreferences"> | string | null
leaderboardBackground?: Prisma.StringNullableWithAggregatesFilter<"SitePreferences"> | string | null leaderboardBackground?: Prisma.StringNullableWithAggregatesFilter<"SitePreferences"> | string | null
challengesBackground?: Prisma.StringNullableWithAggregatesFilter<"SitePreferences"> | string | null challengesBackground?: Prisma.StringNullableWithAggregatesFilter<"SitePreferences"> | string | null
eventRegistrationPoints?: Prisma.IntWithAggregatesFilter<"SitePreferences"> | number
eventFeedbackPoints?: Prisma.IntWithAggregatesFilter<"SitePreferences"> | number
createdAt?: Prisma.DateTimeWithAggregatesFilter<"SitePreferences"> | Date | string createdAt?: Prisma.DateTimeWithAggregatesFilter<"SitePreferences"> | Date | string
updatedAt?: Prisma.DateTimeWithAggregatesFilter<"SitePreferences"> | Date | string updatedAt?: Prisma.DateTimeWithAggregatesFilter<"SitePreferences"> | Date | string
} }
@@ -255,6 +319,8 @@ export type SitePreferencesCreateInput = {
eventsBackground?: string | null eventsBackground?: string | null
leaderboardBackground?: string | null leaderboardBackground?: string | null
challengesBackground?: string | null challengesBackground?: string | null
eventRegistrationPoints?: number
eventFeedbackPoints?: number
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
} }
@@ -265,6 +331,8 @@ export type SitePreferencesUncheckedCreateInput = {
eventsBackground?: string | null eventsBackground?: string | null
leaderboardBackground?: string | null leaderboardBackground?: string | null
challengesBackground?: string | null challengesBackground?: string | null
eventRegistrationPoints?: number
eventFeedbackPoints?: number
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
} }
@@ -275,6 +343,8 @@ export type SitePreferencesUpdateInput = {
eventsBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null eventsBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
leaderboardBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null leaderboardBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
challengesBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null challengesBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
eventRegistrationPoints?: Prisma.IntFieldUpdateOperationsInput | number
eventFeedbackPoints?: Prisma.IntFieldUpdateOperationsInput | number
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
} }
@@ -285,6 +355,8 @@ export type SitePreferencesUncheckedUpdateInput = {
eventsBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null eventsBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
leaderboardBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null leaderboardBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
challengesBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null challengesBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
eventRegistrationPoints?: Prisma.IntFieldUpdateOperationsInput | number
eventFeedbackPoints?: Prisma.IntFieldUpdateOperationsInput | number
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
} }
@@ -295,6 +367,8 @@ export type SitePreferencesCreateManyInput = {
eventsBackground?: string | null eventsBackground?: string | null
leaderboardBackground?: string | null leaderboardBackground?: string | null
challengesBackground?: string | null challengesBackground?: string | null
eventRegistrationPoints?: number
eventFeedbackPoints?: number
createdAt?: Date | string createdAt?: Date | string
updatedAt?: Date | string updatedAt?: Date | string
} }
@@ -305,6 +379,8 @@ export type SitePreferencesUpdateManyMutationInput = {
eventsBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null eventsBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
leaderboardBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null leaderboardBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
challengesBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null challengesBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
eventRegistrationPoints?: Prisma.IntFieldUpdateOperationsInput | number
eventFeedbackPoints?: Prisma.IntFieldUpdateOperationsInput | number
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
} }
@@ -315,6 +391,8 @@ export type SitePreferencesUncheckedUpdateManyInput = {
eventsBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null eventsBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
leaderboardBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null leaderboardBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
challengesBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null challengesBackground?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
eventRegistrationPoints?: Prisma.IntFieldUpdateOperationsInput | number
eventFeedbackPoints?: Prisma.IntFieldUpdateOperationsInput | number
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
} }
@@ -325,16 +403,25 @@ export type SitePreferencesCountOrderByAggregateInput = {
eventsBackground?: Prisma.SortOrder eventsBackground?: Prisma.SortOrder
leaderboardBackground?: Prisma.SortOrder leaderboardBackground?: Prisma.SortOrder
challengesBackground?: Prisma.SortOrder challengesBackground?: Prisma.SortOrder
eventRegistrationPoints?: Prisma.SortOrder
eventFeedbackPoints?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
} }
export type SitePreferencesAvgOrderByAggregateInput = {
eventRegistrationPoints?: Prisma.SortOrder
eventFeedbackPoints?: Prisma.SortOrder
}
export type SitePreferencesMaxOrderByAggregateInput = { export type SitePreferencesMaxOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
homeBackground?: Prisma.SortOrder homeBackground?: Prisma.SortOrder
eventsBackground?: Prisma.SortOrder eventsBackground?: Prisma.SortOrder
leaderboardBackground?: Prisma.SortOrder leaderboardBackground?: Prisma.SortOrder
challengesBackground?: Prisma.SortOrder challengesBackground?: Prisma.SortOrder
eventRegistrationPoints?: Prisma.SortOrder
eventFeedbackPoints?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
} }
@@ -345,10 +432,17 @@ export type SitePreferencesMinOrderByAggregateInput = {
eventsBackground?: Prisma.SortOrder eventsBackground?: Prisma.SortOrder
leaderboardBackground?: Prisma.SortOrder leaderboardBackground?: Prisma.SortOrder
challengesBackground?: Prisma.SortOrder challengesBackground?: Prisma.SortOrder
eventRegistrationPoints?: Prisma.SortOrder
eventFeedbackPoints?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder
} }
export type SitePreferencesSumOrderByAggregateInput = {
eventRegistrationPoints?: Prisma.SortOrder
eventFeedbackPoints?: Prisma.SortOrder
}
export type SitePreferencesSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{ export type SitePreferencesSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
@@ -357,6 +451,8 @@ export type SitePreferencesSelect<ExtArgs extends runtime.Types.Extensions.Inter
eventsBackground?: boolean eventsBackground?: boolean
leaderboardBackground?: boolean leaderboardBackground?: boolean
challengesBackground?: boolean challengesBackground?: boolean
eventRegistrationPoints?: boolean
eventFeedbackPoints?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
}, ExtArgs["result"]["sitePreferences"]> }, ExtArgs["result"]["sitePreferences"]>
@@ -367,6 +463,8 @@ export type SitePreferencesSelectCreateManyAndReturn<ExtArgs extends runtime.Typ
eventsBackground?: boolean eventsBackground?: boolean
leaderboardBackground?: boolean leaderboardBackground?: boolean
challengesBackground?: boolean challengesBackground?: boolean
eventRegistrationPoints?: boolean
eventFeedbackPoints?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
}, ExtArgs["result"]["sitePreferences"]> }, ExtArgs["result"]["sitePreferences"]>
@@ -377,6 +475,8 @@ export type SitePreferencesSelectUpdateManyAndReturn<ExtArgs extends runtime.Typ
eventsBackground?: boolean eventsBackground?: boolean
leaderboardBackground?: boolean leaderboardBackground?: boolean
challengesBackground?: boolean challengesBackground?: boolean
eventRegistrationPoints?: boolean
eventFeedbackPoints?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
}, ExtArgs["result"]["sitePreferences"]> }, ExtArgs["result"]["sitePreferences"]>
@@ -387,11 +487,13 @@ export type SitePreferencesSelectScalar = {
eventsBackground?: boolean eventsBackground?: boolean
leaderboardBackground?: boolean leaderboardBackground?: boolean
challengesBackground?: boolean challengesBackground?: boolean
eventRegistrationPoints?: boolean
eventFeedbackPoints?: boolean
createdAt?: boolean createdAt?: boolean
updatedAt?: boolean updatedAt?: boolean
} }
export type SitePreferencesOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "homeBackground" | "eventsBackground" | "leaderboardBackground" | "challengesBackground" | "createdAt" | "updatedAt", ExtArgs["result"]["sitePreferences"]> export type SitePreferencesOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "homeBackground" | "eventsBackground" | "leaderboardBackground" | "challengesBackground" | "eventRegistrationPoints" | "eventFeedbackPoints" | "createdAt" | "updatedAt", ExtArgs["result"]["sitePreferences"]>
export type $SitePreferencesPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type $SitePreferencesPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
name: "SitePreferences" name: "SitePreferences"
@@ -402,6 +504,8 @@ export type $SitePreferencesPayload<ExtArgs extends runtime.Types.Extensions.Int
eventsBackground: string | null eventsBackground: string | null
leaderboardBackground: string | null leaderboardBackground: string | null
challengesBackground: string | null challengesBackground: string | null
eventRegistrationPoints: number
eventFeedbackPoints: number
createdAt: Date createdAt: Date
updatedAt: Date updatedAt: Date
}, ExtArgs["result"]["sitePreferences"]> }, ExtArgs["result"]["sitePreferences"]>
@@ -832,6 +936,8 @@ export interface SitePreferencesFieldRefs {
readonly eventsBackground: Prisma.FieldRef<"SitePreferences", 'String'> readonly eventsBackground: Prisma.FieldRef<"SitePreferences", 'String'>
readonly leaderboardBackground: Prisma.FieldRef<"SitePreferences", 'String'> readonly leaderboardBackground: Prisma.FieldRef<"SitePreferences", 'String'>
readonly challengesBackground: Prisma.FieldRef<"SitePreferences", 'String'> readonly challengesBackground: Prisma.FieldRef<"SitePreferences", 'String'>
readonly eventRegistrationPoints: Prisma.FieldRef<"SitePreferences", 'Int'>
readonly eventFeedbackPoints: Prisma.FieldRef<"SitePreferences", 'Int'>
readonly createdAt: Prisma.FieldRef<"SitePreferences", 'DateTime'> readonly createdAt: Prisma.FieldRef<"SitePreferences", 'DateTime'>
readonly updatedAt: Prisma.FieldRef<"SitePreferences", 'DateTime'> readonly updatedAt: Prisma.FieldRef<"SitePreferences", 'DateTime'>
} }

View File

@@ -0,0 +1,18 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_SitePreferences" (
"id" TEXT NOT NULL PRIMARY KEY DEFAULT 'global',
"homeBackground" TEXT,
"eventsBackground" TEXT,
"leaderboardBackground" TEXT,
"challengesBackground" TEXT,
"eventRegistrationPoints" INTEGER NOT NULL DEFAULT 100,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_SitePreferences" ("challengesBackground", "createdAt", "eventsBackground", "homeBackground", "id", "leaderboardBackground", "updatedAt") SELECT "challengesBackground", "createdAt", "eventsBackground", "homeBackground", "id", "leaderboardBackground", "updatedAt" FROM "SitePreferences";
DROP TABLE "SitePreferences";
ALTER TABLE "new_SitePreferences" RENAME TO "SitePreferences";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,19 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_SitePreferences" (
"id" TEXT NOT NULL PRIMARY KEY DEFAULT 'global',
"homeBackground" TEXT,
"eventsBackground" TEXT,
"leaderboardBackground" TEXT,
"challengesBackground" TEXT,
"eventRegistrationPoints" INTEGER NOT NULL DEFAULT 100,
"eventFeedbackPoints" INTEGER NOT NULL DEFAULT 50,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_SitePreferences" ("challengesBackground", "createdAt", "eventRegistrationPoints", "eventsBackground", "homeBackground", "id", "leaderboardBackground", "updatedAt") SELECT "challengesBackground", "createdAt", "eventRegistrationPoints", "eventsBackground", "homeBackground", "id", "leaderboardBackground", "updatedAt" FROM "SitePreferences";
DROP TABLE "SitePreferences";
ALTER TABLE "new_SitePreferences" RENAME TO "SitePreferences";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,19 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_SitePreferences" (
"id" TEXT NOT NULL PRIMARY KEY DEFAULT 'global',
"homeBackground" TEXT,
"eventsBackground" TEXT,
"leaderboardBackground" TEXT,
"challengesBackground" TEXT,
"eventRegistrationPoints" INTEGER NOT NULL DEFAULT 100,
"eventFeedbackPoints" INTEGER NOT NULL DEFAULT 100,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_SitePreferences" ("challengesBackground", "createdAt", "eventFeedbackPoints", "eventRegistrationPoints", "eventsBackground", "homeBackground", "id", "leaderboardBackground", "updatedAt") SELECT "challengesBackground", "createdAt", "eventFeedbackPoints", "eventRegistrationPoints", "eventsBackground", "homeBackground", "id", "leaderboardBackground", "updatedAt" FROM "SitePreferences";
DROP TABLE "SitePreferences";
ALTER TABLE "new_SitePreferences" RENAME TO "SitePreferences";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -100,6 +100,8 @@ model SitePreferences {
eventsBackground String? eventsBackground String?
leaderboardBackground String? leaderboardBackground String?
challengesBackground String? challengesBackground String?
eventRegistrationPoints Int @default(100)
eventFeedbackPoints Int @default(100)
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
} }

View File

@@ -2,6 +2,7 @@ import { prisma } from "../database";
import type { EventFeedback, Prisma } from "@/prisma/generated/prisma/client"; import type { EventFeedback, Prisma } from "@/prisma/generated/prisma/client";
import { ValidationError, NotFoundError } from "../errors"; import { ValidationError, NotFoundError } from "../errors";
import { eventService } from "./event.service"; import { eventService } from "./event.service";
import { sitePreferencesService } from "../preferences/site-preferences.service";
export interface CreateOrUpdateFeedbackInput { export interface CreateOrUpdateFeedbackInput {
rating: number; rating: number;
@@ -168,11 +169,34 @@ export class EventFeedbackService {
throw new NotFoundError("Événement"); throw new NotFoundError("Événement");
} }
// Créer ou mettre à jour le feedback // Vérifier si c'est un nouveau feedback ou une mise à jour
return this.createOrUpdateFeedback(userId, eventId, { const existingFeedback = await this.getUserFeedback(userId, eventId);
rating: data.rating, const isNewFeedback = !existingFeedback;
comment: data.comment || null,
}); // Récupérer les points à attribuer depuis les préférences du site
const sitePreferences = await sitePreferencesService.getOrCreateSitePreferences();
const pointsToAward = sitePreferences.eventFeedbackPoints || 100;
// Créer ou mettre à jour le feedback et attribuer les points (seulement pour nouveau feedback)
const [feedback] = await Promise.all([
this.createOrUpdateFeedback(userId, eventId, {
rating: data.rating,
comment: data.comment || null,
}),
// Attribuer les points seulement si c'est un nouveau feedback
isNewFeedback
? prisma.user.update({
where: { id: userId },
data: {
score: {
increment: pointsToAward,
},
},
})
: Promise.resolve(null),
]);
return feedback;
} }
} }

View File

@@ -3,6 +3,7 @@ import type { EventRegistration } from "@/prisma/generated/prisma/client";
import { ValidationError, NotFoundError, ConflictError } from "../errors"; import { ValidationError, NotFoundError, ConflictError } from "../errors";
import { eventService } from "./event.service"; import { eventService } from "./event.service";
import { calculateEventStatus } from "@/lib/eventStatus"; import { calculateEventStatus } from "@/lib/eventStatus";
import { sitePreferencesService } from "../preferences/site-preferences.service";
/** /**
* Service de gestion des inscriptions aux événements * Service de gestion des inscriptions aux événements
@@ -24,18 +25,39 @@ export class EventRegistrationService {
} }
/** /**
* Désinscrit un utilisateur d'un événement * Désinscrit un utilisateur d'un événement et retire les points attribués
*/ */
async unregisterUserFromEvent( async unregisterUserFromEvent(
userId: string, userId: string,
eventId: string eventId: string
): Promise<void> { ): Promise<void> {
await prisma.eventRegistration.deleteMany({ // Vérifier que l'utilisateur est bien inscrit avant de retirer les points
where: { const isRegistered = await this.checkUserRegistration(userId, eventId);
userId, if (!isRegistered) {
eventId, return; // Pas d'inscription, rien à faire
}, }
});
// Récupérer les points à retirer depuis les préférences du site
const sitePreferences = await sitePreferencesService.getOrCreateSitePreferences();
const pointsToRemove = sitePreferences.eventRegistrationPoints || 100;
// Supprimer l'inscription et retirer les points en parallèle
await Promise.all([
prisma.eventRegistration.deleteMany({
where: {
userId,
eventId,
},
}),
prisma.user.update({
where: { id: userId },
data: {
score: {
decrement: pointsToRemove,
},
},
}),
]);
} }
/** /**
@@ -123,8 +145,24 @@ export class EventRegistrationService {
throw new ConflictError("Vous êtes déjà inscrit à cet événement"); throw new ConflictError("Vous êtes déjà inscrit à cet événement");
} }
// Créer l'inscription // Récupérer les points à attribuer depuis les préférences du site
return this.registerUserToEvent(userId, eventId); const sitePreferences = await sitePreferencesService.getOrCreateSitePreferences();
const pointsToAward = sitePreferences.eventRegistrationPoints || 100;
// Créer l'inscription et attribuer les points en parallèle
const [registration] = await Promise.all([
this.registerUserToEvent(userId, eventId),
prisma.user.update({
where: { id: userId },
data: {
score: {
increment: pointsToAward,
},
},
}),
]);
return registration;
} }
} }

View File

@@ -7,6 +7,8 @@ export interface UpdateSitePreferencesInput {
eventsBackground?: string | null; eventsBackground?: string | null;
leaderboardBackground?: string | null; leaderboardBackground?: string | null;
challengesBackground?: string | null; challengesBackground?: string | null;
eventRegistrationPoints?: number;
eventFeedbackPoints?: number;
} }
/** /**
@@ -38,6 +40,8 @@ export class SitePreferencesService {
eventsBackground: null, eventsBackground: null,
leaderboardBackground: null, leaderboardBackground: null,
challengesBackground: null, challengesBackground: null,
eventRegistrationPoints: 100,
eventFeedbackPoints: 100,
}, },
}); });
} }
@@ -70,6 +74,14 @@ export class SitePreferencesService {
data.challengesBackground === "" data.challengesBackground === ""
? null ? null
: (data.challengesBackground ?? undefined), : (data.challengesBackground ?? undefined),
eventRegistrationPoints:
data.eventRegistrationPoints !== undefined
? data.eventRegistrationPoints
: undefined,
eventFeedbackPoints:
data.eventFeedbackPoints !== undefined
? data.eventFeedbackPoints
: undefined,
}, },
create: { create: {
id: "global", id: "global",
@@ -85,6 +97,8 @@ export class SitePreferencesService {
data.challengesBackground === "" data.challengesBackground === ""
? null ? null
: (data.challengesBackground ?? null), : (data.challengesBackground ?? null),
eventRegistrationPoints: data.eventRegistrationPoints ?? 100,
eventFeedbackPoints: data.eventFeedbackPoints ?? 100,
}, },
}); });
} }