const { addBaseUrlToImages } = require('../utils/imageHelper'); const Header = require('../models/header'); const Menu = require('../models/menuHeader'); // Helper function để thêm title và url cho programmes const addProgrammeDetails = (programmes, menuUrl) => { return programmes.map(prog => ({ ...prog, title: prog.name, url: `${menuUrl}${prog.code}/` })); }; // Helper function để xử lý menu tree cho API (đơn giản hóa, map menuid thành id) const processMenuTreeForAPI = (menuTree) => { return menuTree.map(item => { const processedItem = { id: item.menuid, // Map menuid to id for frontend title: item.title, url: item.url, order: item.order, parent: item.parent || null, type: item.type, children: [] }; // Đệ quy cho children if (item.children && item.children.length > 0) { processedItem.children = processMenuTreeForAPI(item.children); } return processedItem; }); }; // Helper function để xử lý menu tree và thêm programme details (cho admin) const processMenuTree = (menuTree) => { return menuTree.map(item => { const processedItem = { ...item }; // Nếu có programmes, thêm title và url if (item.programmes && item.programmes.length > 0) { processedItem.programmes = addProgrammeDetails(item.programmes, item.url); } // Đệ quy cho children if (item.children && item.children.length > 0) { processedItem.children = processMenuTree(item.children); } return processedItem; }); }; // Get header data from MongoDB const getHeaderData = async () => { const header = await Header.findOne({ name: 'default' }); if (!header) { return { topbar: { contactInfo: { phone: '', email: '' }, links: [] }, mainMenu: [], logo: '' }; } // Convert to plain object to allow modifications const headerData = header.toObject(); // Lấy menu tree từ collection menuHeader (đơn giản, không có programmes) try { const menuTree = await Menu.getMenuTree(); // Xử lý menu tree để map menuid thành id cho frontend headerData.mainMenu = processMenuTreeForAPI(menuTree); } catch (error) { console.error('Error getting menu tree:', error); headerData.mainMenu = []; } return headerData; }; // API to get header data exports.api = async (req, res) => { try { // Lấy header data const header = await getHeaderData(); // Xử lý URL cho logo và các hình ảnh khác const processedData = addBaseUrlToImages(header); res.json(processedData); } catch (err) { console.error('API Error:', err); res.status(500).json({ error: 'Error loading header data' }); } }; // API để lấy menu tree cho frontend (public API) exports.getMenuTreeAPI = async (req, res) => { try { const menuTree = await Menu.getMenuTree(); // Xử lý menu tree để map menuid thành id cho frontend const processedMenuTree = processMenuTreeForAPI(menuTree); res.json(processedMenuTree); } catch (error) { console.error('Error getting menu tree:', error); res.status(500).json({ error: 'Error loading menu tree' }); } }; // API để lấy menu tree (cho admin) exports.getMenuTree = async (req, res) => { try { const menuTree = await Menu.getMenuTree(); res.json(menuTree); } catch (error) { console.error('Error getting menu tree:', error); res.status(500).json({ error: 'Error loading menu tree' }); } }; // API để lấy programmes theo menu ID exports.getProgrammesByMenuId = async (req, res) => { try { const { menuId } = req.params; const programmes = await Header.getProgrammesByMenuId(menuId); // Lấy menu item để có URL const menuItem = await Menu.findOne({ menuid: menuId }); if (menuItem) { const programmesWithDetails = addProgrammeDetails(programmes, menuItem.url); res.json(programmesWithDetails); } else { res.json(programmes); } } catch (error) { console.error('Error getting programmes by menu ID:', error); res.status(500).json({ error: 'Error loading programmes' }); } }; // API để lấy toàn bộ header data exports.getHeaderData = async (req, res) => { try { const headerData = await getHeaderData(); res.json(headerData); } catch (error) { console.error('Error getting header data:', error); res.status(500).json({ error: 'Error loading header data' }); } }; // API để lấy menu item theo ID exports.getMenuItem = async (req, res) => { try { const { menuId } = req.params; const Menu = require('../models/menuHeader'); const menuItem = await Menu.findOne({ menuid: menuId }); if (!menuItem) { return res.status(404).json({ error: 'Menu item not found' }); } // Nếu là level type và có fetch = true, lấy programmes if (menuItem.type === 'level' && menuItem.fetch) { const programmes = await Menu.getProgrammesByMenuId(menuItem.menuid); menuItem.programmes = addProgrammeDetails(programmes, menuItem.url); } res.json(menuItem); } catch (error) { console.error('Error getting menu item:', error); res.status(500).json({ error: 'Error loading menu item' }); } }; // Render admin view exports.index = async (req, res) => { try { const data = await getHeaderData(); res.render('admin/header/index', { title: 'Header Management', data }); } catch (error) { console.error('Error in header index:', error); req.flash('error_msg', 'An error occurred while loading the page'); res.redirect('/admin/dashboard'); } }; // Update header (chỉ cập nhật topbar và logo) exports.update = async (req, res) => { try { const headerData = req.body; // Tìm và cập nhật header const header = await Header.findOne({ name: 'default' }); if (!header) { req.flash('error_msg', 'Header not found'); return res.redirect('/admin/header'); } // Cập nhật từng phần if (headerData.topbarJson) { header.topbar = JSON.parse(headerData.topbarJson); } if (headerData.logo) { header.logo = headerData.logo; } header.updatedAt = new Date(); await header.save(); // Process menu updates if any let menuUpdateCount = 0; let menuErrorCount = 0; if (headerData.menuUpdates) { try { const updates = JSON.parse(headerData.menuUpdates); if (Array.isArray(updates) && updates.length > 0) { const Menu = require('../models/menuHeader'); for (const update of updates) { try { const { menuid, title, order, type, parent, fetch, isActive } = update; const updateData = { title: title, order: order, type: type, parent: parent }; // Add fetch field if provided if (fetch !== undefined) { updateData.fetch = fetch; } // Add isActive field if provided if (isActive !== undefined) { updateData.isActive = isActive; } const result = await Menu.findOneAndUpdate( { menuid: menuid }, updateData, { new: true } ); if (result) { menuUpdateCount++; } else { console.warn(`Menu item not found for update: ${menuid}`); menuErrorCount++; } } catch (innerErr) { console.error(`Error updating menu item ${update.menuid}:`, innerErr); menuErrorCount++; } } } } catch (err) { console.error('Error processing menu updates:', err); } } let flashMsg = 'Header updated successfully.'; if (menuUpdateCount > 0) { flashMsg += ` Updated ${menuUpdateCount} menu items.`; } if (menuErrorCount > 0) { req.flash('error_msg', `Updated ${menuUpdateCount} items, but failed to update ${menuErrorCount} items. Check logs.`); } else { req.flash('success_msg', flashMsg); } // Redirect back to the active tab const activeTab = req.body.activeTab || 'topbar'; res.redirect(`/admin/header?activeTab=${activeTab}`); } catch (error) { console.error('Error updating header:', error); req.flash('error_msg', 'Error updating header: ' + error.message); res.redirect('/admin/header'); } }; // Update menu structure (order and parent) exports.updateMenu = async (req, res) => { try { const { updates } = req.body; if (!updates || !Array.isArray(updates)) { return res.status(400).json({ success: false, error: 'Invalid updates data' }); } const Menu = require('../models/menuHeader'); // Update each menu item for (const update of updates) { const { menuid, title, order, type, parent, fetch, isActive } = update; console.log(menuid, title, order, type, parent, fetch, isActive); const updateData = { title: title, order: order, type: type, parent: parent }; // Add fetch field if provided (for level type menus) if (fetch !== undefined) { updateData.fetch = fetch; } // Add isActive field if provided if (isActive !== undefined) { updateData.isActive = isActive; } await Menu.findOneAndUpdate( { menuid: menuid }, updateData, { new: true } ); } res.json({ success: true }); } catch (error) { console.error('Error updating menu structure:', error); req.flash('error_msg', 'Error updating menu structure: ' + error.message); res.redirect('/admin/header'); } };