const AppointmentSubmission = require("../models/appointmentSubmission"); const Appointment = require("../models/appointment"); // ==================== CMS ADMIN FUNCTIONS ==================== // Render admin page for appointment management exports.index = async (req, res) => { try { let appointment = await Appointment.findOne({ name: "default" }); // If no data in DB, try to load from JSON file if (!appointment) { const fs = require("fs"); const path = require("path"); const jsonPath = path.join(__dirname, "../data/appointment.json"); if (fs.existsSync(jsonPath)) { const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); appointment = await Appointment.migrateFromJson(jsonData); } else { // Create default appointment appointment = await Appointment.create({ name: "default", hero: { title: "Make Appointment", backgroundImage: "", subtitle: "", heading: "", description: "", }, visaOptions: [], form: { heading: "Request Appointment", fields: [], submitButton: { text: "Request Appointment", icon: "fa-solid fa-arrow-right", buttonClass: "theme-btn", }, }, }); } } const { startDate, endDate } = req.query; const query = {}; if (startDate || endDate) { query.createdAt = {}; if (startDate) { query.createdAt.$gte = new Date(startDate); } if (endDate) { // Set end date to end of day const end = new Date(endDate); end.setHours(23, 59, 59, 999); query.createdAt.$lte = end; } } const submissions = await AppointmentSubmission.find(query).sort({ createdAt: -1 }).limit(50); res.render("admin/appointment/index", { layout: "layouts/main", title: "Appointment Management", data: appointment, submissions, startDate, endDate, user: req.session.user, frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000", }); } catch (err) { console.error("Error loading appointment admin page:", err); req.flash("error", "Error loading appointment data"); res.redirect("/admin/dashboard"); } }; // Update appointment data exports.update = async (req, res) => { try { const { hero, visaOptions, form } = req.body; // Parse JSON strings if needed const heroData = typeof hero === "string" ? JSON.parse(hero) : hero; const visaOptionsData = typeof visaOptions === "string" ? JSON.parse(visaOptions) : visaOptions; const formData = typeof form === "string" ? JSON.parse(form) : form; let appointment = await Appointment.findOne({ name: "default" }); if (appointment) { appointment.hero = heroData; appointment.visaOptions = visaOptionsData; appointment.form = formData; await appointment.save(); } else { appointment = await Appointment.create({ name: "default", hero: heroData, visaOptions: visaOptionsData, form: formData, }); } req.flash("success", "Appointment data updated successfully"); res.redirect("/admin/appointment"); } catch (err) { console.error("Error updating appointment:", err); req.flash("error", "Error updating appointment data"); res.redirect("/admin/appointment"); } }; // API to get appointment data exports.getAppointmentData = async (req, res) => { try { let appointment = await Appointment.findOne({ name: "default" }); if (!appointment) { const fs = require("fs"); const path = require("path"); const jsonPath = path.join(__dirname, "../data/appointment.json"); if (fs.existsSync(jsonPath)) { const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); appointment = await Appointment.migrateFromJson(jsonData); } } res.json({ success: true, data: appointment, }); } catch (err) { console.error("Error getting appointment data:", err); res.status(500).json({ success: false, error: "Error loading appointment data", }); } }; // Public API to get appointment page data (for frontend) exports.api = async (req, res) => { try { let appointment = await Appointment.findOne({ name: "default" }); if (!appointment) { const fs = require("fs"); const path = require("path"); const jsonPath = path.join(__dirname, "../data/appointment.json"); if (fs.existsSync(jsonPath)) { const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8")); appointment = await Appointment.migrateFromJson(jsonData); } } if (!appointment) { return res.status(404).json({ success: false, error: "Appointment data not found", }); } res.json({ success: true, data: { hero: appointment.hero, visaOptions: appointment.visaOptions, form: appointment.form, }, }); } catch (err) { console.error("Error getting appointment API data:", err); res.status(500).json({ success: false, error: "Error loading appointment data", }); } }; // ==================== APPOINTMENT SUBMISSIONS API ==================== // API để submit appointment form (từ frontend) exports.submitAppointment = async (req, res) => { try { const { name, email, phone, address, appointmentDate, message, visaTypes } = req.body; // Validation if (!name || !email) { return res.status(400).json({ success: false, error: "Name and email are required", }); } // Create new submission const submission = new AppointmentSubmission({ name: name.trim(), email: email.trim().toLowerCase(), phone: phone?.trim() || "", address: address?.trim() || "", appointmentDate: appointmentDate?.trim() || "", message: message?.trim() || "", visaTypes: Array.isArray(visaTypes) ? visaTypes : [], ipAddress: req.ip || req.connection?.remoteAddress || "", userAgent: req.get("User-Agent") || "", }); await submission.save(); res.status(201).json({ success: true, message: "Thank you! Your appointment request has been submitted. We will contact you soon.", data: { id: submission._id, name: submission.name, email: submission.email, appointmentDate: submission.appointmentDate, }, }); } catch (err) { console.error("Error submitting appointment:", err); // Handle validation errors if (err.name === "ValidationError") { const errors = Object.values(err.errors).map((e) => e.message); return res.status(400).json({ success: false, error: errors.join(", "), }); } res.status(500).json({ success: false, error: "Error submitting appointment. Please try again later.", }); } }; // API để lấy danh sách appointments (cho admin) exports.getAppointments = async (req, res) => { try { const { status, page = 1, limit = 20 } = req.query; const query = {}; if (status && ["pending", "confirmed", "completed", "cancelled"].includes(status)) { query.status = status; } const skip = (parseInt(page) - 1) * parseInt(limit); const [appointments, total] = await Promise.all([ AppointmentSubmission.find(query) .sort({ createdAt: -1 }) .skip(skip) .limit(parseInt(limit)), AppointmentSubmission.countDocuments(query), ]); res.json({ success: true, data: appointments, pagination: { page: parseInt(page), limit: parseInt(limit), total, totalPages: Math.ceil(total / parseInt(limit)), }, }); } catch (err) { console.error("Error getting appointments:", err); res.status(500).json({ success: false, error: "Error loading appointments", }); } }; // API để cập nhật status của appointment exports.updateAppointmentStatus = async (req, res) => { try { const { id } = req.params; const { status, notes } = req.body; const validStatuses = ["pending", "confirmed", "completed", "cancelled"]; if (!validStatuses.includes(status)) { return res.status(400).json({ success: false, error: "Invalid status", }); } const updateData = { status }; if (notes !== undefined) updateData.notes = notes; if (status === "confirmed") updateData.confirmedAt = new Date(); if (status === "completed") updateData.completedAt = new Date(); const appointment = await AppointmentSubmission.findByIdAndUpdate( id, updateData, { new: true } ); if (!appointment) { return res.status(404).json({ success: false, error: "Appointment not found", }); } res.json({ success: true, data: appointment, }); } catch (err) { console.error("Error updating appointment:", err); res.status(500).json({ success: false, error: "Error updating appointment", }); } }; // API để lấy chi tiết một appointment exports.getAppointmentById = async (req, res) => { try { const { id } = req.params; const appointment = await AppointmentSubmission.findById(id); if (!appointment) { return res.status(404).json({ success: false, error: "Appointment not found", }); } res.json({ success: true, data: appointment, }); } catch (err) { console.error("Error getting appointment:", err); res.status(500).json({ success: false, error: "Error loading appointment", }); } }; // API để xóa appointment exports.deleteAppointment = async (req, res) => { try { const { id } = req.params; const appointment = await AppointmentSubmission.findByIdAndDelete(id); if (!appointment) { return res.status(404).json({ success: false, error: "Appointment not found", }); } res.json({ success: true, message: "Appointment deleted successfully", }); } catch (err) { console.error("Error deleting appointment:", err); res.status(500).json({ success: false, error: "Error deleting appointment", }); } };