const Pricing = require("../models/pricing"); const writeAuditLog = require("../audit/writeAuditLog"); const diffObject = require("../audit/diffObject"); const AUDIT_ACTIONS = require("../constants/auditAction"); // ==================== CMS ADMIN FUNCTIONS ==================== // Render admin page for pricing management exports.index = async (req, res) => { try { let pricing = await Pricing.findOne({ name: "default" }); // If no data in DB, try to load from JSON file if (!pricing) { const fs = require("fs"); const path = require("path"); const jsonPath = path.join(__dirname, "../data/pricing.json"); if (fs.existsSync(jsonPath)) { const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); pricing = await Pricing.migrateFromJson(jsonData); } else { // Create default pricing pricing = await Pricing.create({ name: "default", hero: { title: "Pricing Plan", backgroundImage: "/assets/img/inner-page/breadcrumb.jpg", shapeImage: "/assets/img/inner-page/shape.png", breadcrumb: [ { text: "Home", link: "/" }, { text: "Pricing Plan", link: "" }, ], }, pricingSection: { subtitle: "pricing plan", heading: "Flexible Plans to Suit Every Traveler", description: "Choose the plan that fits your visa needs and enjoy expert guidance every step of the way.", }, plans: { monthly: [], yearly: [], }, testimonials: { subtitle: "What Our Clients Say", heading: "Immigration Success Stories", buttonText: "View All Review", buttonLink: "/contact", buttonIcon: "fa-solid fa-arrow-right", image: "", items: [], }, }); } } res.render("admin/pricing/index", { layout: "layouts/main", title: "Pricing Management", data: pricing, user: req.session.user, frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000", }); } catch (err) { console.error("Error loading pricing admin page:", err); req.flash("error", "Error loading pricing data"); res.redirect("/admin/dashboard"); } }; // Update pricing data exports.update = async (req, res) => { try { const { hero, pricingSection, plans, testimonials } = req.body; // Parse JSON strings if needed const heroData = typeof hero === "string" ? JSON.parse(hero) : hero; const pricingSectionData = typeof pricingSection === "string" ? JSON.parse(pricingSection) : pricingSection; const plansData = typeof plans === "string" ? JSON.parse(plans) : plans; const testimonialsData = typeof testimonials === "string" ? JSON.parse(testimonials) : testimonials; let pricing = await Pricing.findOne({ name: "default" }); // ✅ Capture BEFORE state const beforeData = pricing ? JSON.parse(JSON.stringify(pricing.toObject())) : {}; if (pricing) { pricing.hero = heroData; pricing.pricingSection = pricingSectionData; pricing.plans = plansData; pricing.testimonials = testimonialsData; await pricing.save(); } else { pricing = await Pricing.create({ name: "default", hero: heroData, pricingSection: pricingSectionData, plans: plansData, testimonials: testimonialsData, }); } // ✅ Capture AFTER state const afterData = JSON.parse(JSON.stringify(pricing.toObject())); // ✅ AUDIT LOGGING - Pricing Updated const changes = diffObject(beforeData, afterData); if (changes.length > 0) { await writeAuditLog({ model: "Pricing", documentId: pricing._id, action: AUDIT_ACTIONS.UPDATE_PRICING, before: beforeData, after: afterData, changes, req, }); } req.flash("success", "Pricing data updated successfully"); res.redirect("/admin/pricing"); } catch (err) { console.error("Error updating pricing:", err); req.flash("error", "Error updating pricing data"); res.redirect("/admin/pricing"); } }; // API to get pricing data (admin) exports.getPricingData = async (req, res) => { try { let pricing = await Pricing.findOne({ name: "default" }); if (!pricing) { const fs = require("fs"); const path = require("path"); const jsonPath = path.join(__dirname, "../data/pricing.json"); if (fs.existsSync(jsonPath)) { const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); pricing = await Pricing.migrateFromJson(jsonData); } } res.json({ success: true, data: pricing, }); } catch (err) { console.error("Error getting pricing data:", err); res.status(500).json({ success: false, error: "Error loading pricing data", }); } }; // Public API to get pricing page data (for frontend) exports.api = async (req, res) => { try { let pricing = await Pricing.findOne({ name: "default" }); if (!pricing) { const fs = require("fs"); const path = require("path"); const jsonPath = path.join(__dirname, "../data/pricing.json"); if (fs.existsSync(jsonPath)) { const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); pricing = await Pricing.migrateFromJson(jsonData); } } if (!pricing) { return res.status(404).json({ success: false, error: "Pricing data not found", }); } const backendUrl = process.env.BACKEND_URL || "http://localhost:3001"; const getFullUrl = (path) => { if (!path || path.startsWith("http")) return path; return `${backendUrl}${path.startsWith("/") ? "" : "/"}${path}`; }; // Convert to plain object to modify properties safely const pricingData = pricing.toObject ? pricing.toObject() : pricing; if (pricingData.hero) { pricingData.hero.backgroundImage = getFullUrl( pricingData.hero.backgroundImage, ); pricingData.hero.shapeImage = getFullUrl(pricingData.hero.shapeImage); } if (pricingData.testimonials) { pricingData.testimonials.image = getFullUrl( pricingData.testimonials.image, ); } res.json({ success: true, data: { hero: pricingData.hero, pricingSection: pricingData.pricingSection, plans: pricingData.plans, testimonials: pricingData.testimonials, }, }); } catch (err) { console.error("Error getting pricing API data:", err); res.status(500).json({ success: false, error: "Error loading pricing data", }); } };