Add challenges background preference support: Extend site preferences and related components to include challengesBackground, update API and UI to handle new background image settings for challenges.
Some checks failed
Deploy with Docker Compose / deploy (push) Failing after 2m23s

This commit is contained in:
Julien Froidefond
2025-12-15 21:26:30 +01:00
parent 83446759fe
commit d3a4fa7cf5
25 changed files with 8373 additions and 12328 deletions

View File

@@ -10,6 +10,7 @@ interface SitePreferences {
homeBackground: string | null;
eventsBackground: string | null;
leaderboardBackground: string | null;
challengesBackground: string | null;
}
interface BackgroundPreferencesProps {
@@ -20,6 +21,7 @@ const DEFAULT_IMAGES = {
home: "/got-2.jpg",
events: "/got-2.jpg",
leaderboard: "/leaderboard-bg.jpg",
challenges: "/got-2.jpg",
};
export default function BackgroundPreferences({
@@ -57,6 +59,10 @@ export default function BackgroundPreferences({
initialPreferences.leaderboardBackground,
DEFAULT_IMAGES.leaderboard
),
challengesBackground: getFormValue(
initialPreferences.challengesBackground,
DEFAULT_IMAGES.challenges
),
}),
[initialPreferences]
);
@@ -90,6 +96,10 @@ export default function BackgroundPreferences({
formData.leaderboardBackground,
DEFAULT_IMAGES.leaderboard
),
challengesBackground: getApiValue(
formData.challengesBackground,
DEFAULT_IMAGES.challenges
),
};
const result = await updateSitePreferences(apiData);
@@ -110,6 +120,10 @@ export default function BackgroundPreferences({
result.data.leaderboardBackground,
DEFAULT_IMAGES.leaderboard
),
challengesBackground: getFormValue(
result.data.challengesBackground,
DEFAULT_IMAGES.challenges
),
});
setIsEditing(false);
} else {
@@ -138,6 +152,10 @@ export default function BackgroundPreferences({
preferences.leaderboardBackground,
DEFAULT_IMAGES.leaderboard
),
challengesBackground: getFormValue(
preferences.challengesBackground,
DEFAULT_IMAGES.challenges
),
});
}
};
@@ -197,6 +215,16 @@ export default function BackgroundPreferences({
}
label="Background Leaderboard"
/>
<ImageSelector
value={formData.challengesBackground}
onChange={(url) =>
setFormData({
...formData,
challengesBackground: url,
})
}
label="Background Challenges"
/>
<div className="flex flex-col sm:flex-row gap-2 pt-4">
<Button onClick={handleSave} variant="success" size="md">
Enregistrer
@@ -376,6 +404,62 @@ export default function BackgroundPreferences({
);
})()}
</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-[120px] flex-shrink-0">
Challenges:
</span>
{(() => {
const currentImage =
preferences?.challengesBackground &&
preferences.challengesBackground.trim() !== ""
? preferences.challengesBackground
: DEFAULT_IMAGES.challenges;
const isDefault =
!preferences?.challengesBackground ||
preferences.challengesBackground.trim() === "";
return (
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
<div className="relative w-16 h-10 sm:w-20 sm:h-12 rounded border border-pixel-gold/30 overflow-hidden bg-black/60 flex-shrink-0">
<img
src={currentImage}
alt="Challenges background"
className="w-full h-full object-cover"
onError={(e) => {
const target = e.currentTarget;
const currentSrc = target.src;
const fallbackSrc = "/got-2.jpg";
if (!currentSrc.includes(fallbackSrc)) {
target.src = fallbackSrc;
} else {
target.style.display = "none";
const fallbackDiv =
target.nextElementSibling as HTMLElement;
if (fallbackDiv) {
fallbackDiv.classList.remove("hidden");
}
}
}}
/>
<div className="absolute inset-0 flex items-center justify-center bg-black/60 text-gray-500 text-xs hidden">
No image
</div>
</div>
<div className="flex flex-col min-w-0 flex-1">
<span className="text-xs text-gray-400 truncate min-w-0">
{isDefault ? "Par défaut: " : ""}
{currentImage}
</span>
{isDefault && (
<span className="text-[10px] text-gray-500 italic">
(Image par défaut)
</span>
)}
</div>
</div>
);
})()}
</div>
</div>
)}
</Card>