Spaces:
Running
Running
| const SiteContent = require('../models/SiteContent'); | |
| const { asyncController } = require('../utils/asyncController'); | |
| const DEFAULT_SITE_CONTENT = { | |
| welcome: { | |
| title: 'ITS IT Department Kiosk', | |
| subtitle: | |
| "Hi I'm ITS IT Department Kiosk, I can help you explore our department, meet our faculty, and discover our achievements.", | |
| cta: 'Start Exploring', | |
| footerHint: 'Touch anywhere to begin', | |
| }, | |
| mainMenu: { | |
| title: 'Department of Information Technology', | |
| subtitle: 'What would you like to explore?', | |
| footerHint: 'Touch any card to explore that section', | |
| modules: [ | |
| { | |
| key: 'aboutus', | |
| label: 'About Us', | |
| subtitle: 'Learn about our department', | |
| bg: '#3b82f6', | |
| href: '/aboutus', | |
| iconImage: '', | |
| }, | |
| { | |
| key: 'profile', | |
| label: 'Faculty Profiles', | |
| subtitle: 'Meet our expert faculty', | |
| bg: '#8b5cf6', | |
| href: '/profile', | |
| iconImage: '', | |
| }, | |
| { | |
| key: 'admission', | |
| label: 'Admissions/Other Info', | |
| subtitle: 'Join our program', | |
| bg: '#06b6d4', | |
| href: '/admission', | |
| iconImage: '', | |
| }, | |
| { | |
| key: 'achievement', | |
| label: 'Achievements/News', | |
| subtitle: 'Our success stories', | |
| bg: '#f97316', | |
| href: '/achievement', | |
| iconImage: '', | |
| }, | |
| { | |
| key: 'announcement', | |
| label: 'Announcements', | |
| subtitle: 'Latest updates and news', | |
| bg: '#22c55e', | |
| href: '/announcement', | |
| iconImage: '', | |
| }, | |
| ], | |
| }, | |
| }; | |
| const sanitizeCopy = (value, fallback) => { | |
| if (!value || typeof value !== 'object') return fallback; | |
| return { | |
| title: String(value.title || fallback.title).trim(), | |
| subtitle: String(value.subtitle || fallback.subtitle).trim(), | |
| cta: String(value.cta || fallback.cta).trim(), | |
| footerHint: String(value.footerHint || fallback.footerHint).trim(), | |
| }; | |
| }; | |
| const toKeySlug = (value = '') => | |
| String(value) | |
| .toLowerCase() | |
| .trim() | |
| .replace(/[^a-z0-9\s-]/g, '') | |
| .replace(/\s+/g, '-') | |
| .replace(/-+/g, '-'); | |
| const sanitizeModule = (item = {}, fallback = {}) => ({ | |
| key: String(item.key || fallback.key || '').trim(), | |
| label: String(item.label || fallback.label || '').trim(), | |
| subtitle: String(item.subtitle || fallback.subtitle || '').trim(), | |
| bg: String(item.bg || fallback.bg || '#3b82f6').trim(), | |
| href: String(item.href || fallback.href || '').trim(), | |
| iconImage: String(item.iconImage || fallback.iconImage || '').trim(), | |
| }); | |
| const sanitizeMainMenu = (value) => { | |
| const fallback = DEFAULT_SITE_CONTENT.mainMenu; | |
| const modules = Array.isArray(value?.modules) && value.modules.length | |
| ? value.modules | |
| : fallback.modules; | |
| return { | |
| title: value?.title || fallback.title, | |
| subtitle: value?.subtitle || fallback.subtitle, | |
| footerHint: value?.footerHint || fallback.footerHint, | |
| modules: modules | |
| .map((item, index) => { | |
| const moduleItem = sanitizeModule(item, fallback.modules[index] || {}); | |
| const generatedKey = toKeySlug(moduleItem.key || moduleItem.label || moduleItem.href || `card-${index + 1}`); | |
| return { | |
| ...moduleItem, | |
| key: generatedKey || `card-${index + 1}`, | |
| }; | |
| }) | |
| .filter((item) => item.label), | |
| }; | |
| }; | |
| const normalizeSiteContent = (doc) => ({ | |
| welcome: sanitizeCopy(doc?.welcome?.EN || doc?.welcome, DEFAULT_SITE_CONTENT.welcome), | |
| mainMenu: sanitizeMainMenu(doc?.mainMenu), | |
| }); | |
| const getSiteContent = asyncController(async (req, res) => { | |
| const doc = await SiteContent.findOne({ slug: 'main' }).lean(); | |
| res.json(normalizeSiteContent(doc)); | |
| }); | |
| const updateSiteContent = asyncController(async (req, res) => { | |
| const { welcome, mainMenu } = req.body; | |
| const payload = {}; | |
| if (welcome && typeof welcome === 'object') { | |
| const source = welcome.EN && typeof welcome.EN === 'object' ? welcome.EN : welcome; | |
| payload.welcome = { | |
| title: String(source?.title || '').trim(), | |
| subtitle: String(source?.subtitle || '').trim(), | |
| cta: String(source?.cta || '').trim(), | |
| footerHint: String(source?.footerHint || '').trim(), | |
| }; | |
| } | |
| if (mainMenu && typeof mainMenu === 'object') { | |
| payload.mainMenu = { | |
| title: String(mainMenu?.title || '').trim(), | |
| subtitle: String(mainMenu?.subtitle || '').trim(), | |
| footerHint: String(mainMenu?.footerHint || '').trim(), | |
| modules: Array.isArray(mainMenu?.modules) | |
| ? mainMenu.modules | |
| .map((item, index) => { | |
| const moduleItem = sanitizeModule(item); | |
| const generatedKey = toKeySlug(moduleItem.key || moduleItem.label || moduleItem.href || `card-${index + 1}`); | |
| return { | |
| ...moduleItem, | |
| key: generatedKey || `card-${index + 1}`, | |
| }; | |
| }) | |
| .filter((item) => item.label) | |
| : [], | |
| }; | |
| } | |
| if (!Object.keys(payload).length) { | |
| return res.status(400).json({ message: 'No fields provided to update' }); | |
| } | |
| const doc = await SiteContent.findOneAndUpdate( | |
| { slug: 'main' }, | |
| { $set: payload }, | |
| { returnDocument: 'after', upsert: true, runValidators: true } | |
| ); | |
| if (!doc) { | |
| return res.status(500).json({ message: 'Failed to persist site content' }); | |
| } | |
| res.json(normalizeSiteContent(doc)); | |
| }, { defaultStatus: 400 }); | |
| module.exports = { getSiteContent, updateSiteContent }; | |