Add visibility toggle for picks features and rename Mes choix to Mes picks
- Renamed 'Mes choix' to 'Mes picks' across all pages and JavaScript files - Added visibility toggle in control panel (Réglages > Visibilité) to control: - Display of 'Mes picks' button in navigation - Display of 'Bon picks' column in user statistics - Combined both visibility options into single toggle for simplicity - Added backend API endpoints for visibility configuration - Implemented localStorage caching for instant visibility updates - Fixed flash of content issues when navigating between pages - Updated stats endpoint to calculate correct picks on-the-fly from current winners - Renamed 'Bonnes réponses' to 'Bon picks' in user statistics table
This commit is contained in:
@@ -15,6 +15,7 @@ const OSCAR_DATES_BY_YEAR_KEY = "oscar_date_by_year";
|
||||
const APP_VERSION_KEY = "app_version_control";
|
||||
const PLAYER_ADMIN_STATUS_UI_KEY = "player_admin_status_ui";
|
||||
const POINTS_CONFIG_KEY = "points_config";
|
||||
const VISIBILITY_CONFIG_KEY = "visibility_config";
|
||||
|
||||
const crypto = require("crypto");
|
||||
|
||||
@@ -36,6 +37,11 @@ const DEFAULT_POINTS_CONFIG = Object.freeze({
|
||||
pointsPerCorrectPick: 1,
|
||||
});
|
||||
|
||||
const DEFAULT_VISIBILITY_CONFIG = Object.freeze({
|
||||
showPicksButton: true,
|
||||
showBonPicksColumn: true,
|
||||
});
|
||||
|
||||
function parseOscarYear(raw) {
|
||||
if (raw === undefined || raw === null || raw === "") return null;
|
||||
const n = Number(raw);
|
||||
@@ -762,6 +768,13 @@ function normalizePointsConfig(rawValue) {
|
||||
return { pointsPerMovie, pointsPerCorrectPick };
|
||||
}
|
||||
|
||||
function normalizeVisibilityConfig(rawValue) {
|
||||
const v = rawValue && typeof rawValue === "object" && !Array.isArray(rawValue) ? rawValue : {};
|
||||
const showPicksButton = typeof v.showPicksButton === "boolean" ? v.showPicksButton : DEFAULT_VISIBILITY_CONFIG.showPicksButton;
|
||||
const showBonPicksColumn = typeof v.showBonPicksColumn === "boolean" ? v.showBonPicksColumn : DEFAULT_VISIBILITY_CONFIG.showBonPicksColumn;
|
||||
return { showPicksButton, showBonPicksColumn };
|
||||
}
|
||||
|
||||
// Public: get points configuration
|
||||
router.get("/points-config", async (req, res) => {
|
||||
try {
|
||||
@@ -800,5 +813,43 @@ router.put("/points-config", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Public: get visibility configuration
|
||||
router.get("/visibility-config", async (req, res) => {
|
||||
try {
|
||||
const existing = await Setting.findOne({ key: VISIBILITY_CONFIG_KEY }).select("value");
|
||||
const normalized = normalizeVisibilityConfig(existing?.value);
|
||||
return res.status(200).json(normalized);
|
||||
} catch (err) {
|
||||
return res.status(200).json(DEFAULT_VISIBILITY_CONFIG);
|
||||
}
|
||||
});
|
||||
|
||||
// Admin-only: set visibility configuration
|
||||
router.put("/visibility-config", async (req, res) => {
|
||||
const token = req.headers.authorization?.split(" ")[1];
|
||||
if (!token) return res.status(401).json({ message: "Authentication token is required" });
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||
if (!decoded.admin) {
|
||||
return res.status(403).json({ message: "You do not have admin privileges" });
|
||||
}
|
||||
|
||||
const normalized = normalizeVisibilityConfig(req.body);
|
||||
const updated = await Setting.findOneAndUpdate(
|
||||
{ key: VISIBILITY_CONFIG_KEY },
|
||||
{ $set: { value: normalized } },
|
||||
{ upsert: true, new: true }
|
||||
).select("value");
|
||||
|
||||
return res.status(200).json(normalizeVisibilityConfig(updated?.value));
|
||||
} catch (err) {
|
||||
if (err instanceof jwt.JsonWebTokenError) {
|
||||
return res.status(401).json({ message: "Invalid or expired token" });
|
||||
}
|
||||
return res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user