const { addBaseUrlToImages } = require("../utils/imageHelper"); const Home = require("../models/home"); // -------------------- Helpers -------------------- const getHomeDoc = async () => { // Keep newest document as the source of truth return await Home.findOne().sort({ updatedAt: -1 }); }; const getHomeData = async () => { const doc = await Home.findOne().sort({ updatedAt: -1 }).lean(); return doc || {}; }; /** * Default structure used by the current CMS Home admin UI (`views/admin/home/index.ejs`). * This is intentionally permissive; the Home model itself also supports the Next.js * structure from `hailearning.edu.vn/app/home.json`. */ const getDefaultHomeData = () => ({ hero: { title: "", description: "", backgroundImage: "", button: { label: "Book Your Adventure", href: "/booking" }, contactBox: { welcomeText: "", phone: { label: "Call us", number: "", href: "" }, email: { label: "Email", address: "", href: "" }, workingHours: { label: "Working Hours", hours: "" }, }, }, about: { title: "", subtitle: "", description: "", images: { mainImage1: "", mainImage2: "", avatars: [] }, features: [], quote: "", button: { label: "", href: "" }, stats: { customerCount: 0, customerLabel: "" }, }, missionVision: { title: "", subtitle: "", backgroundImage: "", cards: [], }, whyChooseUs: { title: "", subtitle: "", description: "", button: { label: "", href: "" }, features: [], tags: [], cta: { text: "", linkText: "", linkHref: "" }, }, activities: { cards: [] }, faq: { title: "", subtitle: "", description: "", image: "", contact: { title: "", info: "" }, questions: [], }, partners: { title: "", subtitle: "", backgroundImage: "", logos: [], cta: { badge: "", text: "", linkText: "", linkHref: "" }, }, programs: { title: "", subtitle: "", button: { label: "", href: "" }, card: { pricePrefix: "from", priceSuffix: "USD", buttonLabel: "Camp Detail", buttonHref: "/camp-profiles", }, items: [], }, newsletter: { title: "", subtitle: "", description: "", image: "", decorativeImage: "", button: { label: "", placeholder: "", href: "" }, }, latestPosts: { title: "", subtitle: "", searchPlaceholder: "", sidebarTitle: "", blogPosts: [], sidebarPosts: [], featuredCard: { image: "", title: "", description: "" }, }, }); // -------------------- Admin -------------------- exports.index = async (req, res) => { try { let data = await getHomeData(); if (!data || Object.keys(data).length === 0) { data = getDefaultHomeData(); } else { // Merge minimal defaults to keep the view safe const defaults = getDefaultHomeData(); data.hero = data.hero || defaults.hero; data.about = data.about || defaults.about; data.missionVision = data.missionVision || defaults.missionVision; data.whyChooseUs = data.whyChooseUs || defaults.whyChooseUs; data.activities = data.activities || defaults.activities; data.faq = data.faq || defaults.faq; data.partners = data.partners || defaults.partners; data.programs = data.programs || defaults.programs; data.newsletter = data.newsletter || defaults.newsletter; data.latestPosts = data.latestPosts || defaults.latestPosts; } const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000"; return res.render("admin/home/index", { layout: "layouts/main", title: "Home Management", data, frontendUrl, currentPath: req.path, user: req.session.user, }); } catch (err) { console.error("Home index error:", err); req.flash("error_msg", "Error loading home data"); return req.session.save(() => res.redirect("/admin/dashboard")); } }; exports.update = async (req, res) => { try { const currentDoc = await getHomeDoc(); const currentData = currentDoc ? currentDoc.toObject() : {}; const updatedData = { ...currentData }; // Quick fields (Hero) from classic form fields if (req.body.heroTitle || req.body.heroDescription || req.body.heroBackgroundImage) { updatedData.hero = { title: req.body.heroTitle || "", description: req.body.heroDescription || "", backgroundImage: req.body.heroBackgroundImage || "", button: { label: req.body.heroButtonLabel || "Book Your Adventure", href: req.body.heroButtonHref || "/booking", }, contactBox: { welcomeText: req.body.heroContactWelcome || "", phone: { label: "Call us", number: req.body.heroContactPhone || "", href: req.body.heroContactPhone ? `tel:${req.body.heroContactPhone}` : "", }, email: { label: "Email", address: req.body.heroContactEmail || "", href: req.body.heroContactEmail ? `mailto:${req.body.heroContactEmail}` : "", }, workingHours: { label: "Working Hours", hours: req.body.heroContactHours || "", }, }, }; } // Handle sections sent as JSON payloads const sections = [ "hero", "about", "missionVision", "whyChooseUs", "activities", "faq", "partners", "programs", "newsletter", "latestPosts", ]; let hasChanges = false; for (const section of sections) { if (!req.body[section]) continue; try { const newSectionData = JSON.parse(req.body[section]); const currentSectionData = currentData?.[section]; if (JSON.stringify(newSectionData) !== JSON.stringify(currentSectionData)) { updatedData[section] = newSectionData; hasChanges = true; } } catch (e) { console.error(`Error processing section "${section}":`, e); req.flash("error_msg", `Invalid JSON for section "${section}": ${e.message}`); return req.session.save(() => res.redirect("/admin/home")); } } if (!hasChanges) { req.flash("info_msg", "No changes were made"); return req.session.save(() => res.redirect("/admin/home")); } if (currentDoc?._id) { await Home.findByIdAndUpdate(currentDoc._id, updatedData, { new: true }); } else { await Home.create(updatedData); } req.flash("success_msg", "Home data updated successfully"); return req.session.save(() => res.redirect("/admin/home")); } catch (err) { console.error("Home update error:", err); req.flash("error_msg", `Update error: ${err.message || "Unknown"}`); return req.session.save(() => res.redirect("/admin/home")); } }; // -------------------- Public API -------------------- exports.api = async (req, res) => { try { const homeData = await getHomeData(); const baseUrl = process.env.BACKEND_URL || `${req.protocol}://${req.get("host")}`; const processedData = addBaseUrlToImages(homeData, baseUrl); return res.json(processedData); } catch (err) { console.error("Home API error:", err); return res.status(500).json({ error: "Error loading home data" }); } };