Files
cms.uldp.edu.vn/controllers/homeController.js
r2xrzh9q2z-lab d1b931d547 first commit
2026-02-02 11:07:09 +07:00

315 lines
9.1 KiB
JavaScript

const { addBaseUrlToImages } = require('../utils/imageHelper');
const Home = require('../models/home');
// -------------------- Helper Functions --------------------
// Get home data from MongoDB
const getHomeData = async () => {
const home = await Home.findOne().sort({ updatedAt: -1 }).lean();
return home || {};
};
// Get default home data structure
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 --------------------
// Display home management page
exports.index = async (req, res) => {
try {
// Fetch Home data
let data = await getHomeData();
// If no data exists, use default
if (!data || Object.keys(data).length === 0) {
data = getDefaultHomeData();
} else {
// Merge with defaults to ensure all fields exist
const defaultData = getDefaultHomeData();
// Ensure all sections exist with defaults
data.hero = data.hero || defaultData.hero;
data.about = data.about || defaultData.about;
data.missionVision = data.missionVision || defaultData.missionVision;
data.whyChooseUs = data.whyChooseUs || defaultData.whyChooseUs;
data.activities = data.activities || defaultData.activities;
data.faq = data.faq || defaultData.faq;
data.partners = data.partners || defaultData.partners;
data.programs = data.programs || defaultData.programs;
data.newsletter = data.newsletter || defaultData.newsletter;
data.latestPosts = data.latestPosts || defaultData.latestPosts;
}
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
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');
res.redirect('/admin/dashboard');
}
};
// Update home data
exports.update = async (req, res) => {
try {
// Get current data
const currentData = await getHomeData();
// Create updated data object
const updatedData = { ...(currentData.toObject ? currentData.toObject() : currentData) };
// Update Hero section data (from Welcome tab)
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 || ''
}
}
};
}
// Update Why Choose Us section
if (req.body.whyChooseUsTitle || req.body.whyChooseUsSubtitle) {
updatedData.whyChooseUs = {
...(updatedData.whyChooseUs || {}),
title: req.body.whyChooseUsTitle || '',
subtitle: req.body.whyChooseUsSubtitle || '',
description: req.body.whyChooseUsDescription || '',
button: {
label: req.body.whyChooseUsButtonLabel || '',
href: req.body.whyChooseUsButtonHref || ''
},
features: updatedData.whyChooseUs?.features || [],
tags: updatedData.whyChooseUs?.tags || [],
cta: updatedData.whyChooseUs?.cta || { text: '', linkText: '', linkHref: '' }
};
}
// Handle Home sections (new camp structure only)
const sections = ['hero', 'about', 'missionVision', 'whyChooseUs', 'activities', 'faq',
'partners', 'programs', 'newsletter', 'latestPosts'];
const errors = [];
let hasChanges = false;
// Process each section
for (const section of sections) {
try {
if (!req.body[section]) {
console.warn(`No data for section: ${section}`);
continue;
}
// Parse JSON data from form
const newSectionData = JSON.parse(req.body[section]);
// Check for changes
const currentSectionData = currentData[section];
const sectionHasChanges = JSON.stringify(newSectionData) !== JSON.stringify(currentSectionData);
if (sectionHasChanges) {
updatedData[section] = newSectionData;
hasChanges = true;
}
} catch (error) {
console.error(`Error processing section ${section}:`, error);
errors.push(`Error processing ${section} data: ${error.message}`);
}
}
// Handle errors
if (errors.length > 0) {
req.flash('error_msg', `Data processing error: ${errors[0]}`);
return req.session.save(() => res.redirect('/admin/home'));
}
// Check if there are changes
if (!hasChanges) {
req.flash('info_msg', 'No changes were made');
return req.session.save(() => res.redirect('/admin/home'));
}
// Update or create document
try {
if (currentData._id) {
await Home.findByIdAndUpdate(currentData._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 (dbError) {
console.error('Database error:', dbError);
req.flash('error_msg', `Database error: ${dbError.message || 'Unknown'}`);
return req.session.save(() => res.redirect('/admin/home'));
}
} catch (err) {
console.error('Update error:', err);
req.flash('error_msg', `Update error: ${err.message || 'Unknown'}`);
return req.session.save(() => res.redirect('/admin/home'));
}
};
// -------------------- Public API Exports --------------------
// API to get home data for frontend
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);
res.json(processedData);
} catch (err) {
console.error('Home API error:', err);
res.status(500).json({ error: 'Error loading home data' });
}
};
// API to get hero data for frontend
exports.apiHero = async (req, res) => {
try {
const homeData = await getHomeData();
const heroData = homeData?.hero;
if (!heroData) {
return res.status(404).json({
error: 'Hero data not found',
data: null
});
}
const baseUrl = process.env.BACKEND_URL || `${req.protocol}://${req.get('host')}`;
const processedData = addBaseUrlToImages(heroData, baseUrl);
res.json(processedData);
} catch (err) {
console.error('Hero API error:', err);
res.status(500).json({ error: 'Error loading hero data' });
}
};