forked from UKSOURCE/cms.hailearning.edu.vn
230 lines
6.7 KiB
JavaScript
230 lines
6.7 KiB
JavaScript
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",
|
|
});
|
|
}
|
|
};
|