feat: Implement core admin panel functionalities including appointment, contact, and pricing management with associated models, controllers, views, and routes.

This commit is contained in:
LNHA
2026-02-03 14:58:00 +07:00
parent d1b931d547
commit df8e1f9665
25 changed files with 4574 additions and 659 deletions

206
models/appointment.js Normal file
View 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);