const { addBaseUrlToImages } = require("../utils/imageHelper"); const { normalizeIconClass } = require("../utils/iconOptions"); const StudentSupport = require("../models/studentSupport"); const writeAuditLog = require("../audit/writeAuditLog"); const diffObject = require("../audit/diffObject"); const AUDIT_ACTIONS = require("../constants/auditAction"); const SLUG = "student-support"; function emptyPageShape() { return { metadata: { title: "", description: "" }, hero: { badge: "", title: "", description: "", primaryButton: { label: "", href: "" }, secondaryButton: { label: "", href: "" }, image: "", imageAlt: "", }, directory: { title: "", subtitle: "", services: [] }, contactSection: { heading: "", description: "", channels: [], form: { heading: "", fields: { firstName: { label: "", placeholder: "" }, lastName: { label: "", placeholder: "" }, studentId: { label: "", placeholder: "" }, department: { label: "" }, message: { label: "", placeholder: "" }, }, departments: [], submitLabel: "", successMessage: "", }, }, }; } function parseJsonField(raw) { if (raw == null || raw === "") return null; if (typeof raw === "object") return raw; try { return JSON.parse(raw); } catch { return null; } } /** Chuẩn hoá mọi field icon theo whitelist (dropdown admin). */ function sanitizeIcons(payload) { if (!payload) return payload; if (payload.hero) { /* hero không có icon list */ } if (payload.directory?.services?.length) { payload.directory.services = payload.directory.services.map((s) => ({ ...s, icon: normalizeIconClass(s.icon), hoursIcon: normalizeIconClass(s.hoursIcon), })); } if (payload.contactSection?.channels?.length) { payload.contactSection.channels = payload.contactSection.channels.map((c) => ({ ...c, icon: normalizeIconClass(c.icon), })); } return payload; } async function getDocument() { return StudentSupport.findOne({ slug: SLUG }).lean(); } /** * GET /api/student-support — public payload giống file JSON frontend (không kèm _id/slug). */ exports.api = async (req, res) => { try { const doc = await getDocument(); if (!doc) { return res.status(404).json({ error: "Student Support content not found" }); } const baseUrl = process.env.BACKEND_URL ?? `${req.protocol}://${req.get("host")}`; const body = { metadata: doc.metadata || {}, hero: doc.hero || {}, directory: doc.directory || { services: [] }, contactSection: doc.contactSection || {}, }; res.json(addBaseUrlToImages(body, baseUrl)); } catch (err) { console.error("studentSupport.api:", err); res.status(500).json({ error: "Error loading Student Support data" }); } }; exports.index = async (req, res) => { try { const doc = await getDocument(); const data = doc ? { metadata: doc.metadata || {}, hero: doc.hero || {}, directory: doc.directory || { services: [] }, contactSection: doc.contactSection || {}, } : emptyPageShape(); const { ICON_OPTIONS } = require("../utils/iconOptions"); const frontendUrl = process.env.FRONTEND_URL || ""; res.render("admin/student-support/index", { title: "Student Support", layout: "layouts/main", data, iconOptions: ICON_OPTIONS, frontendUrl, currentPath: req.path, user: req.session.user, }); } catch (error) { console.error("studentSupport.index:", error); req.flash("error_msg", "Could not load Student Support page"); res.redirect("/admin/dashboard"); } }; exports.update = async (req, res) => { try { const metadata = parseJsonField(req.body.metadata); const hero = parseJsonField(req.body.hero); const directory = parseJsonField(req.body.directory); const contactSection = parseJsonField(req.body.contactSection); if (!metadata || !hero || !directory || !contactSection) { req.flash("error_msg", "Invalid form payload. Please try again."); return res.redirect("/admin/student-support"); } const payload = sanitizeIcons({ metadata, hero, directory, contactSection, }); let doc = await StudentSupport.findOne({ slug: SLUG }); const beforeData = doc ? JSON.parse(JSON.stringify(doc.toObject())) : {}; if (!doc) { doc = new StudentSupport({ slug: SLUG, ...payload }); } else { doc.set(payload); } await doc.save(); const afterData = JSON.parse(JSON.stringify(doc.toObject())); const changes = diffObject(beforeData, afterData); if (changes.length > 0) { await writeAuditLog({ model: "StudentSupport", documentId: doc._id, action: AUDIT_ACTIONS.UPDATE_STUDENT_SUPPORT, before: beforeData, after: afterData, changes, req, }); } req.flash("success_msg", "Student Support updated successfully"); res.redirect("/admin/student-support"); } catch (err) { console.error("studentSupport.update:", err); req.flash("error_msg", err.message || "Error updating Student Support"); res.redirect("/admin/student-support"); } };