forked from UKSOURCE/cms.hailearning.edu.vn
Merge branch 'main' of https://gits.techvanguard.vn/UKSOURCE/cms.hailearning.edu.vn into fea/bao-03022026-Admin-Management-Service
This commit is contained in:
206
models/appointment.js
Normal file
206
models/appointment.js
Normal file
@@ -0,0 +1,206 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
// Clear cache
|
||||
if (mongoose.models.Appointment) {
|
||||
delete mongoose.models.Appointment;
|
||||
}
|
||||
if (mongoose.connection.models.Appointment) {
|
||||
delete mongoose.connection.models.Appointment;
|
||||
}
|
||||
|
||||
// Schema cho hero section
|
||||
const heroSchema = new mongoose.Schema(
|
||||
{
|
||||
title: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "Make Appointment",
|
||||
},
|
||||
backgroundImage: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
subtitle: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
heading: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho form field
|
||||
const formFieldSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
enum: ["text", "email", "tel", "textarea", "date", "select"],
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
colClass: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "col-lg-12",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho submit button
|
||||
const submitButtonSchema = new mongoose.Schema(
|
||||
{
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
default: "Request Appointment",
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "fa-solid fa-arrow-right",
|
||||
},
|
||||
buttonClass: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "theme-btn",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho form
|
||||
const formSchema = new mongoose.Schema(
|
||||
{
|
||||
heading: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "Request Appointment",
|
||||
},
|
||||
fields: {
|
||||
type: [formFieldSchema],
|
||||
default: [],
|
||||
},
|
||||
submitButton: {
|
||||
type: submitButtonSchema,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Main Appointment Schema
|
||||
const appointmentSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
default: "default",
|
||||
unique: true,
|
||||
},
|
||||
hero: {
|
||||
type: heroSchema,
|
||||
default: () => ({}),
|
||||
},
|
||||
visaOptions: {
|
||||
type: [String],
|
||||
default: [],
|
||||
},
|
||||
form: {
|
||||
type: formSchema,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Migration method to import data from JSON
|
||||
appointmentSchema.statics.migrateFromJson = async function (jsonData) {
|
||||
try {
|
||||
// Check if default appointment exists
|
||||
const existingAppointment = await this.findOne({ name: "default" });
|
||||
|
||||
// Process data from JSON
|
||||
const processedData = {
|
||||
hero: {
|
||||
title: jsonData.hero?.title || "Make Appointment",
|
||||
backgroundImage: jsonData.hero?.backgroundImage || "",
|
||||
subtitle: jsonData.hero?.subtitle || "",
|
||||
heading: jsonData.hero?.heading || "",
|
||||
description: jsonData.hero?.description || "",
|
||||
},
|
||||
visaOptions: Array.isArray(jsonData.visaOptions) ? jsonData.visaOptions : [],
|
||||
form: {
|
||||
heading: jsonData.form?.heading || "Request Appointment",
|
||||
fields: (jsonData.form?.fields || []).map((field) => ({
|
||||
name: field.name || "",
|
||||
label: field.label || "",
|
||||
type: field.type || "text",
|
||||
placeholder: field.placeholder || "",
|
||||
required: field.required || false,
|
||||
colClass: field.colClass || "col-lg-12",
|
||||
})),
|
||||
submitButton: {
|
||||
text: jsonData.form?.submitButton?.text || "Request Appointment",
|
||||
icon: jsonData.form?.submitButton?.icon || "fa-solid fa-arrow-right",
|
||||
buttonClass: jsonData.form?.submitButton?.buttonClass || "theme-btn",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (existingAppointment) {
|
||||
// Update existing appointment
|
||||
existingAppointment.hero = processedData.hero;
|
||||
existingAppointment.visaOptions = processedData.visaOptions;
|
||||
existingAppointment.form = processedData.form;
|
||||
await existingAppointment.save();
|
||||
console.log("Appointment data updated successfully");
|
||||
return existingAppointment;
|
||||
} else {
|
||||
// Create new appointment
|
||||
const newAppointment = await this.create({
|
||||
name: "default",
|
||||
...processedData,
|
||||
});
|
||||
console.log("Appointment data imported successfully");
|
||||
return newAppointment;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error migrating appointment data:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = mongoose.model("Appointment", appointmentSchema);
|
||||
83
models/appointmentSubmission.js
Normal file
83
models/appointmentSubmission.js
Normal file
@@ -0,0 +1,83 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
/**
|
||||
* Schema for Appointment Submissions
|
||||
* Stores appointment requests from users
|
||||
*/
|
||||
const appointmentSubmissionSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: [true, "Name is required"],
|
||||
trim: true,
|
||||
maxlength: [100, "Name cannot exceed 100 characters"],
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: [true, "Email is required"],
|
||||
trim: true,
|
||||
lowercase: true,
|
||||
match: [/^\S+@\S+\.\S+$/, "Please enter a valid email"],
|
||||
},
|
||||
phone: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
address: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
appointmentDate: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
visaTypes: {
|
||||
type: [String],
|
||||
default: [],
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
enum: ["pending", "confirmed", "completed", "cancelled"],
|
||||
default: "pending",
|
||||
},
|
||||
notes: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
confirmedAt: {
|
||||
type: Date,
|
||||
default: null,
|
||||
},
|
||||
completedAt: {
|
||||
type: Date,
|
||||
default: null,
|
||||
},
|
||||
ipAddress: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
userAgent: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Index for faster queries
|
||||
appointmentSubmissionSchema.index({ status: 1, createdAt: -1 });
|
||||
appointmentSubmissionSchema.index({ email: 1 });
|
||||
appointmentSubmissionSchema.index({ appointmentDate: 1 });
|
||||
|
||||
module.exports = mongoose.model("AppointmentSubmission", appointmentSubmissionSchema);
|
||||
@@ -145,6 +145,11 @@ const mapSchema = new mongoose.Schema(
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
embedUrl: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
tileLayer: {
|
||||
type: tileLayerSchema,
|
||||
required: true,
|
||||
@@ -161,11 +166,16 @@ const formFieldSchema = new mongoose.Schema(
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
enum: ["text", "email", "tel", "textarea", "programme"],
|
||||
enum: ["text", "email", "tel", "textarea", "programme", "date"],
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
@@ -176,6 +186,11 @@ const formFieldSchema = new mongoose.Schema(
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
colClass: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "col-lg-12",
|
||||
},
|
||||
programmeName: {
|
||||
type: String,
|
||||
trim: true,
|
||||
@@ -193,6 +208,16 @@ const submitButtonSchema = new mongoose.Schema(
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "fa-solid fa-arrow-right",
|
||||
},
|
||||
buttonClass: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "theme-btn style-2",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
@@ -210,6 +235,11 @@ const formSchema = new mongoose.Schema(
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
fields: {
|
||||
type: [formFieldSchema],
|
||||
default: [],
|
||||
@@ -335,6 +365,7 @@ contactSchema.statics.migrateFromJson = async function (jsonData) {
|
||||
zoom: jsonData.map?.zoom || 15,
|
||||
location: jsonData.map?.location || "",
|
||||
markerTitle: jsonData.map?.markerTitle || "",
|
||||
embedUrl: jsonData.map?.embedUrl || "",
|
||||
tileLayer: {
|
||||
url:
|
||||
jsonData.map?.tileLayer?.url ||
|
||||
@@ -347,15 +378,20 @@ contactSchema.statics.migrateFromJson = async function (jsonData) {
|
||||
form: {
|
||||
sectionLabel: jsonData.form?.sectionLabel || "",
|
||||
heading: jsonData.form?.heading || "",
|
||||
description: jsonData.form?.description || "",
|
||||
fields: (jsonData.form?.fields || []).map((field) => ({
|
||||
name: field.name || "",
|
||||
label: field.label || "",
|
||||
type: field.type || "text",
|
||||
placeholder: field.placeholder || "",
|
||||
required: field.required || false,
|
||||
colClass: field.colClass || "col-lg-12",
|
||||
programmeName: field.programmeName || "",
|
||||
})),
|
||||
submitButton: {
|
||||
text: jsonData.form?.submitButton?.text || "Send Message",
|
||||
icon: jsonData.form?.submitButton?.icon || "fa-solid fa-arrow-right",
|
||||
buttonClass: jsonData.form?.submitButton?.buttonClass || "theme-btn style-2",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
74
models/contactSubmission.js
Normal file
74
models/contactSubmission.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
/**
|
||||
* Schema for Contact Form Submissions
|
||||
* Stores user inquiries from the contact form
|
||||
*/
|
||||
const contactSubmissionSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: [true, "Name is required"],
|
||||
trim: true,
|
||||
maxlength: [100, "Name cannot exceed 100 characters"],
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: [true, "Email is required"],
|
||||
trim: true,
|
||||
lowercase: true,
|
||||
match: [/^\S+@\S+\.\S+$/, "Please enter a valid email"],
|
||||
},
|
||||
phone: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
address: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
date: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
enum: ["pending", "read", "replied", "archived"],
|
||||
default: "pending",
|
||||
},
|
||||
notes: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
repliedAt: {
|
||||
type: Date,
|
||||
default: null,
|
||||
},
|
||||
ipAddress: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
userAgent: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Index for faster queries
|
||||
contactSubmissionSchema.index({ status: 1, createdAt: -1 });
|
||||
contactSubmissionSchema.index({ email: 1 });
|
||||
|
||||
module.exports = mongoose.model("ContactSubmission", contactSubmissionSchema);
|
||||
328
models/pricing.js
Normal file
328
models/pricing.js
Normal file
@@ -0,0 +1,328 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
// Clear cache
|
||||
if (mongoose.models.Pricing) {
|
||||
delete mongoose.models.Pricing;
|
||||
}
|
||||
if (mongoose.connection.models.Pricing) {
|
||||
delete mongoose.connection.models.Pricing;
|
||||
}
|
||||
|
||||
// Schema for breadcrumb item
|
||||
const breadcrumbItemSchema = new mongoose.Schema(
|
||||
{
|
||||
text: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
link: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema for hero section
|
||||
const heroSchema = new mongoose.Schema(
|
||||
{
|
||||
title: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "Pricing Plan",
|
||||
},
|
||||
backgroundImage: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "/assets/img/inner-page/breadcrumb.jpg",
|
||||
},
|
||||
shapeImage: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "/assets/img/inner-page/shape.png",
|
||||
},
|
||||
breadcrumb: {
|
||||
type: [breadcrumbItemSchema],
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema for pricing section header
|
||||
const pricingSectionSchema = new mongoose.Schema(
|
||||
{
|
||||
subtitle: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "pricing plan",
|
||||
},
|
||||
heading: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "Flexible Plans to Suit Every Traveler",
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema for individual plan
|
||||
const planSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
trim: true,
|
||||
required: true,
|
||||
},
|
||||
price: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "0",
|
||||
},
|
||||
period: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "mo",
|
||||
},
|
||||
currency: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "$",
|
||||
},
|
||||
buttonText: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "Get Started Today",
|
||||
},
|
||||
buttonLink: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "/pricing",
|
||||
},
|
||||
buttonIcon: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "fa-solid fa-arrow-right",
|
||||
},
|
||||
style: {
|
||||
type: String,
|
||||
trim: true,
|
||||
enum: ["default", "style-2"],
|
||||
default: "default",
|
||||
},
|
||||
features: {
|
||||
type: [String],
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema for plans container
|
||||
const plansSchema = new mongoose.Schema(
|
||||
{
|
||||
monthly: {
|
||||
type: [planSchema],
|
||||
default: [],
|
||||
},
|
||||
yearly: {
|
||||
type: [planSchema],
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema for testimonial item
|
||||
const testimonialItemSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
role: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
rating: {
|
||||
type: Number,
|
||||
min: 1,
|
||||
max: 5,
|
||||
default: 5,
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema for testimonials section
|
||||
const testimonialsSchema = new mongoose.Schema(
|
||||
{
|
||||
subtitle: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "What Our Clients Say",
|
||||
},
|
||||
heading: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "Immigration Success Stories",
|
||||
},
|
||||
buttonText: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "View All Review",
|
||||
},
|
||||
buttonLink: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "/contact",
|
||||
},
|
||||
buttonIcon: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "fa-solid fa-arrow-right",
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
items: {
|
||||
type: [testimonialItemSchema],
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Main Pricing Schema
|
||||
const pricingSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
default: "default",
|
||||
unique: true,
|
||||
},
|
||||
hero: {
|
||||
type: heroSchema,
|
||||
default: () => ({}),
|
||||
},
|
||||
pricingSection: {
|
||||
type: pricingSectionSchema,
|
||||
default: () => ({}),
|
||||
},
|
||||
plans: {
|
||||
type: plansSchema,
|
||||
default: () => ({}),
|
||||
},
|
||||
testimonials: {
|
||||
type: testimonialsSchema,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Migration method to import data from JSON
|
||||
pricingSchema.statics.migrateFromJson = async function (jsonData) {
|
||||
try {
|
||||
// Check if default pricing exists
|
||||
const existingPricing = await this.findOne({ name: "default" });
|
||||
|
||||
// Process data from JSON
|
||||
const processedData = {
|
||||
hero: {
|
||||
title: jsonData.hero?.title || "Pricing Plan",
|
||||
backgroundImage: jsonData.hero?.backgroundImage || "/assets/img/inner-page/breadcrumb.jpg",
|
||||
shapeImage: jsonData.hero?.shapeImage || "/assets/img/inner-page/shape.png",
|
||||
breadcrumb: (jsonData.hero?.breadcrumb || []).map((item) => ({
|
||||
text: item.text || "",
|
||||
link: item.link || "",
|
||||
})),
|
||||
},
|
||||
pricingSection: {
|
||||
subtitle: jsonData.pricingSection?.subtitle || "pricing plan",
|
||||
heading: jsonData.pricingSection?.heading || "Flexible Plans to Suit Every Traveler",
|
||||
description: jsonData.pricingSection?.description || "",
|
||||
},
|
||||
plans: {
|
||||
monthly: (jsonData.plans?.monthly || []).map((plan) => ({
|
||||
name: plan.name || "",
|
||||
price: plan.price || "0",
|
||||
period: plan.period || "mo",
|
||||
currency: plan.currency || "$",
|
||||
buttonText: plan.buttonText || "Get Started Today",
|
||||
buttonLink: plan.buttonLink || "/pricing",
|
||||
buttonIcon: plan.buttonIcon || "fa-solid fa-arrow-right",
|
||||
style: plan.style || "default",
|
||||
features: plan.features || [],
|
||||
})),
|
||||
yearly: (jsonData.plans?.yearly || []).map((plan) => ({
|
||||
name: plan.name || "",
|
||||
price: plan.price || "0",
|
||||
period: plan.period || "mo",
|
||||
currency: plan.currency || "$",
|
||||
buttonText: plan.buttonText || "Get Started Today",
|
||||
buttonLink: plan.buttonLink || "/pricing",
|
||||
buttonIcon: plan.buttonIcon || "fa-solid fa-arrow-right",
|
||||
style: plan.style || "default",
|
||||
features: plan.features || [],
|
||||
})),
|
||||
},
|
||||
testimonials: {
|
||||
subtitle: jsonData.testimonials?.subtitle || "What Our Clients Say",
|
||||
heading: jsonData.testimonials?.heading || "Immigration Success Stories",
|
||||
buttonText: jsonData.testimonials?.buttonText || "View All Review",
|
||||
buttonLink: jsonData.testimonials?.buttonLink || "/contact",
|
||||
buttonIcon: jsonData.testimonials?.buttonIcon || "fa-solid fa-arrow-right",
|
||||
image: jsonData.testimonials?.image || "",
|
||||
items: (jsonData.testimonials?.items || []).map((item) => ({
|
||||
name: item.name || "",
|
||||
role: item.role || "",
|
||||
rating: item.rating || 5,
|
||||
content: item.content || "",
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
if (existingPricing) {
|
||||
// Update existing pricing
|
||||
existingPricing.hero = processedData.hero;
|
||||
existingPricing.pricingSection = processedData.pricingSection;
|
||||
existingPricing.plans = processedData.plans;
|
||||
existingPricing.testimonials = processedData.testimonials;
|
||||
await existingPricing.save();
|
||||
console.log("Pricing data updated successfully");
|
||||
return existingPricing;
|
||||
} else {
|
||||
// Create new pricing
|
||||
const newPricing = await this.create({
|
||||
name: "default",
|
||||
...processedData,
|
||||
});
|
||||
console.log("Pricing data imported successfully");
|
||||
return newPricing;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error migrating pricing data:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = mongoose.model("Pricing", pricingSchema);
|
||||
Reference in New Issue
Block a user