const Insurance = require("../models/insurance"); const { addBaseUrlToImages } = require("../utils/imageHelper"); // API để lấy insurance data (cho frontend) exports.api = async (req, res) => { try { const language = req.query.lang || "en"; // Sử dụng getDefault để đảm bảo luôn có data const insurance = await Insurance.getDefault(language); // Trả về data với cấu trúc mới const insuranceData = insurance.toObject(); // Sử dụng helper để thêm base URL vào đường dẫn ảnh const baseUrl = process.env.BACKEND_URL || `${req.protocol}://${req.get('host')}`; const processedData = addBaseUrlToImages(insuranceData, baseUrl); // Trả về trực tiếp hero, page, content (không wrap trong object) res.json({ hero: processedData.hero, page: processedData.page, content: processedData.content }); } catch (error) { console.error("API Error:", error); res.status(500).json({ success: false, error: "Error loading insurance data", message: error.message }); } }; // API để lấy toàn bộ insurance data (cho admin) exports.getInsuranceData = async (req, res) => { try { const language = req.query.lang || "en"; const insurance = await Insurance.findOne({ name: "default", language: language }); if (!insurance) { return res.status(404).json({ success: false, error: "Insurance data not found" }); } const insuranceData = insurance.toObject(); // Thêm base URL vào đường dẫn ảnh const baseUrl = process.env.BACKEND_URL || `${req.protocol}://${req.get('host')}`; const processedData = addBaseUrlToImages(insuranceData, baseUrl); res.json({ success: true, data: processedData }); } catch (error) { console.error("Error getting insurance data:", error); res.status(500).json({ success: false, error: "Error loading insurance data" }); } }; // API để lấy data theo ngôn ngữ exports.getByLanguage = async (req, res) => { try { const language = req.params.lang || "en"; const insurance = await Insurance.findOne({ name: "default", language: language }); if (!insurance) { return res.status(404).json({ success: false, error: "Insurance data not found" }); } const insuranceData = insurance.toObject(); // Thêm base URL vào đường dẫn ảnh const baseUrl = process.env.BACKEND_URL || `${req.protocol}://${req.get('host')}`; const processedData = addBaseUrlToImages(insuranceData, baseUrl); res.json({ success: true, data: { hero: processedData.hero, page: processedData.page, content: processedData.content } }); } catch (error) { console.error("Error getting insurance by language:", error); res.status(500).json({ success: false, error: "Error loading insurance data" }); } }; // Render admin view exports.index = async (req, res) => { try { // Luôn đảm bảo có default data const insurance = await Insurance.getDefault("en"); const data = insurance.toObject(); const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000"; res.render("admin/insurance/index", { title: "Insurance Management", layout: "layouts/main", data, frontendUrl, currentPath: req.path, user: req.session.user }); } catch (error) { console.error("Error in insurance index:", error); req.flash("error_msg", "An error occurred while loading the page"); res.redirect("/admin/dashboard"); } }; // Seed data từ JSON file (cấu trúc mới) exports.seed = async (req, res) => { try { const fs = require('fs').promises; const path = require('path'); // Đọc file JSON const jsonPath = path.join(__dirname, '../data/insurance.json'); const jsonData = JSON.parse(await fs.readFile(jsonPath, 'utf8')); console.log('Seeding insurance from JSON...'); // Migrate từ cấu trúc cũ sang mới const insurance = await Insurance.migrateFromJson(jsonData, "en"); res.json({ success: true, message: "Insurance data seeded successfully", data: { id: insurance._id, hero: insurance.hero, page: insurance.page, content: insurance.content } }); } catch (error) { console.error("Error seeding insurance:", error); res.status(500).json({ success: false, error: error.message || "Error seeding insurance data" }); } }; // API preview cho admin (tạo HTML preview) exports.preview = async (req, res) => { try { const { hero, page, content } = req.body; // Parse JSON strings const parseJson = (data) => { if (!data) return null; if (typeof data === "string") { try { return JSON.parse(data); } catch (e) { console.error("JSON parse error:", e); return null; } } return data; }; const heroData = parseJson(hero) || {}; const pageData = parseJson(page) || {}; const contentData = parseJson(content) || {}; // Thêm base URL vào đường dẫn ảnh cho preview const baseUrl = process.env.BACKEND_URL || `${req.protocol}://${req.get('host')}`; const processedHeroData = addBaseUrlToImages(heroData, baseUrl); // Render preview HTML const html = ` ${pageData.title || 'Insurance Preview'}

${heroData.title || 'Insurance'}

${heroData.subtitle || ''}

${renderContentItems(contentData.content || [])}
`; res.send(html); } catch (error) { console.error("Error generating preview:", error); res.status(500).send("Error generating preview"); } }; // Helper function để render content items function renderContentItems(contentItems) { if (!Array.isArray(contentItems) || contentItems.length === 0) { return '

No content available.

'; } return contentItems.map(item => { switch (item.type) { case 'header': return `${item.text}`; case 'paragraph': return `

${item.text}

`; case 'section': return `

${item.title}

${item.content}

`; case 'list': const listItems = (item.items || []).map(li => `
  • ${li}
  • `).join(''); return ``; case 'note': return `
    ${item.text}
    `; case 'embed': if (item.source === 'youtube') { return `
    ${item.caption ? `

    ${item.caption}

    ` : ''}
    `; } return ''; default: return ''; } }).join(''); } // API để tạo insurance mới (cho các ngôn ngữ khác) exports.create = async (req, res) => { try { const { hero, page, content, language } = req.body; if (!language) { return res.status(400).json({ success: false, error: "Language is required" }); } // Kiểm tra đã tồn tại chưa const existing = await Insurance.findOne({ name: "default", language: language }); if (existing) { return res.status(400).json({ success: false, error: "Insurance already exists for this language" }); } // Parse JSON nếu cần const parseJson = (data) => { if (!data) return null; if (typeof data === "string") { try { return JSON.parse(data); } catch (e) { console.error("JSON parse error:", e); return null; } } return data; }; const insurance = new Insurance({ name: "default", language: language, hero: parseJson(hero) || {}, page: parseJson(page) || {}, content: parseJson(content) || {}, version: "2.0.0", isActive: true, migratedFromOldStructure: false }); await insurance.save(); res.json({ success: true, message: "Insurance created successfully for language: " + language, data: insurance }); } catch (error) { console.error("Error creating insurance:", error); res.status(500).json({ success: false, error: error.message || "Error creating insurance" }); } }; // Cập nhật dữ liệu insurance (CẬP NHẬT CẤU TRÚC MỚI) exports.update = async (req, res) => { try { const { hero, page, content } = req.body; // Parse JSON strings const parseJson = (data) => { if (!data) return null; if (typeof data === "string") { try { return JSON.parse(data); } catch (e) { console.error("JSON parse error:", e); return null; } } return data; }; // Parse all data với cấu trúc mới const heroData = parseJson(hero) || {}; const pageData = parseJson(page) || {}; const contentData = parseJson(content) || {}; // Normalize embed blocks (convert YouTube watch URLs to /embed/ URLs) function extractYouTubeId(url) { const regex = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/; const match = url.match(regex); return match ? match[1] : null; } if (contentData && Array.isArray(contentData.content)) { contentData.content.forEach(item => { if (item.type === 'embed' && item.source === 'youtube') { if (item.url && item.url.includes('watch?v=')) { const videoId = extractYouTubeId(item.url); if (videoId) { item.url = `https://www.youtube.com/embed/${videoId}`; item.videoId = videoId; } } if (item.embed && item.embed.includes('watch?v=')) { const videoId = extractYouTubeId(item.embed); if (videoId) { item.embed = `https://www.youtube.com/embed/${videoId}`; item.videoId = videoId; } } } }); } // Tìm hoặc tạo insurance let insurance = await Insurance.findOne({ name: "default", language: "en" }); if (!insurance) { insurance = new Insurance({ name: "default", language: "en", hero: heroData, page: pageData, content: contentData, version: "2.0.0", isActive: true }); } else { insurance.hero = heroData; insurance.page = pageData; insurance.content = contentData; insurance.version = "2.0.0"; } await insurance.save(); req.flash("success_msg", "Insurance updated successfully"); res.redirect("/admin/insurance"); } catch (err) { console.error("Error updating insurance:", err); req.flash("error_msg", err.message || "Error updating insurance"); res.redirect("/admin/insurance"); } }; // API để xóa insurance (theo ngôn ngữ) exports.delete = async (req, res) => { try { const language = req.params.lang; if (!language) { return res.status(400).json({ success: false, error: "Language parameter is required" }); } // Không cho phép xóa tiếng Anh mặc định if (language === "en") { return res.status(400).json({ success: false, error: "Cannot delete default English insurance data" }); } const result = await Insurance.deleteOne({ name: "default", language: language }); if (result.deletedCount === 0) { return res.status(404).json({ success: false, error: "Insurance not found for this language" }); } res.json({ success: true, message: "Insurance deleted successfully for language: " + language }); } catch (error) { console.error("Error deleting insurance:", error); res.status(500).json({ success: false, error: error.message || "Error deleting insurance" }); } };