Spaces:
Sleeping
Sleeping
File size: 5,445 Bytes
e8c33fa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | 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 };
|