diff --git a/backend/config/db.js b/backend/config/db.js new file mode 100644 index 0000000..fe775cf --- /dev/null +++ b/backend/config/db.js @@ -0,0 +1,16 @@ +const mongoose = require("mongoose"); + +const connectDB = async () => { + try { + await mongoose.connect(process.env.MONGODB_URI, { + useNewUrlParser: true, + useUnifiedTopology: true, + }); + console.log("MongoDB connected"); + } catch (err) { + console.error("MongoDB connection error:", err); + process.exit(1); + } +}; + +module.exports = connectDB; diff --git a/backend/controllers/departmentController.js b/backend/controllers/departmentController.js new file mode 100644 index 0000000..7e752b5 --- /dev/null +++ b/backend/controllers/departmentController.js @@ -0,0 +1,78 @@ +const DepartmentEmail = require("../models/DepartmentEmail"); +const Program = require("../models/Program"); + +exports.getAllDepartmentEmails = async (req, res) => { + try { + const departmentEmails = await DepartmentEmail.find(); + res.json(departmentEmails); + } catch (error) { + console.error("Error fetching department emails:", error); + res.status(500).json({ error: "Error fetching department emails" }); + } +}; + +exports.getDepartmentsByProgram = async (req, res) => { + const program = await Program.findOne({ name: req.params.program }); + res.json(program ? program.departments : []); +}; + +exports.getEmailsByDepartment = async (req, res) => { + const departmentEmails = await DepartmentEmail.findOne({ department: req.params.department }); + res.json(departmentEmails ? { emails: departmentEmails.emails } : { emails: [] }); +}; + +exports.updateDepartmentEmails = async (req, res) => { + const { department } = req.params; + const { emails } = req.body; + + if (!emails || !Array.isArray(emails)) { + return res.status(400).json({ error: "Emails array is required" }); + } + + try { + const updatedDepartment = await DepartmentEmail.findOneAndUpdate( + { department }, + { emails }, + { new: true, upsert: true } + ); + res.json(updatedDepartment); + } catch (error) { + console.error("Error updating department emails:", error); + res.status(500).json({ error: "Error updating department emails" }); + } +}; + +exports.createDepartment = async (req, res) => { + const { department, emails, program } = req.body; + + if (!department || !emails || !Array.isArray(emails) || !program) { + return res.status(400).json({ error: "Department, program, and emails array are required" }); + } + + try { + const newDepartment = new DepartmentEmail({ department, emails }); + await newDepartment.save(); + + await Program.findOneAndUpdate( + { name: program }, + { $addToSet: { departments: department } }, + { upsert: true } + ); + + res.status(201).json(newDepartment); + } catch (error) { + console.error("Error creating department:", error); + res.status(500).json({ error: "Error creating department" }); + } +}; + +exports.deleteDepartment = async (req, res) => { + try { + const { department } = req.params; + await DepartmentEmail.findOneAndDelete({ department }); + res.json({ message: "Department deleted successfully" }); + } catch (error) { + console.error("Error deleting department:", error); + res.status(500).json({ error: "Error deleting department" }); + } +}; diff --git a/backend/controllers/emailController.js b/backend/controllers/emailController.js new file mode 100644 index 0000000..3dec681 --- /dev/null +++ b/backend/controllers/emailController.js @@ -0,0 +1,136 @@ +const nodemailer = require("nodemailer"); +const moment = require("moment"); +const Meeting = require("../models/Meeting"); +const DepartmentEmail = require("../models/DepartmentEmail"); + +const sendEmail = async (req, res) => { + try { + const { program, department, subject, body, agenda, date, startTime, endTime, recipients } = req.body; + const files = req.files; + + console.log({ program, department, subject, body, agenda, date, startTime, endTime, recipients, files }); + + if (!program || !department || !subject || !body || !date || !startTime || !endTime || !recipients) { + return res.status(400).json({ error: "All fields are required!" }); + } + + const departmentEmails = await DepartmentEmail.findOne({ department }); + if (!departmentEmails) { + return res.status(404).json({ error: "Department emails not found" }); + } + + const allRecipients = [...new Set([...departmentEmails.emails, ...recipients])]; + + const conflict = await Meeting.findOne({ + date, + startTime: { $lt: endTime }, + endTime: { $gt: startTime }, + }); + + const formattedDate = moment(date, "YYYY-MM-DD").format("dddd, MMMM Do YYYY"); + const formattedStartTime = moment(startTime, "HH:mm").format("hh:mm A"); + const formattedEndTime = moment(endTime, "HH:mm").format("hh:mm A"); + + const formattedStart = moment(`${date} ${startTime}`, "YYYY-MM-DD HH:mm").utc().format("YYYYMMDDTHHmmss[Z]"); + const formattedEnd = moment(`${date} ${endTime}`, "YYYY-MM-DD HH:mm").utc().format("YYYYMMDDTHHmmss[Z]"); + + const zoomLink = "https://us05web.zoom.us/j/2655616202?pwd=S3d6RjVPNnhmQ3AzTlZsRC9GYmNHQT09"; + const calendarLink = `https://calendar.google.com/calendar/render?action=TEMPLATE&text=${encodeURIComponent( + subject + )}&details=${encodeURIComponent(`${body}\nJoin Zoom Meeting: ${zoomLink}`)}&dates=${formattedStart}/${formattedEnd}`; + + const formattedAgenda = Array.isArray(agenda) && agenda.length > 0 + ? agenda.map((item, index) => `
  • ${index + 1}. ${item}
  • `).join("") + : "
  • No agenda provided
  • "; + + const newMeeting = new Meeting({ + program, + department, + subject, + body, + agenda, + date, + startTime, + endTime, + recipients, + attachments: files.map((file) => ({ filename: file.filename, path: file.path })), + }); + await newMeeting.save(); + + let conflictDetails = null; + + if (conflict) { + conflictDetails = { + department: conflict.department, + date: conflict.date, + startTime: conflict.startTime, + endTime: conflict.endTime, + recipients: conflict.recipients, + subject: conflict.subject, + agenda: conflict.agenda || "No agenda provided", + }; + console.log("Conflict detected! Details:", conflictDetails); + } + + const transporter = nodemailer.createTransport({ + service: "gmail", + auth: { + user: process.env.EMAIL, + pass: process.env.EMAIL_PASSWORD, + }, + }); + + const mailOptions = { + from: process.env.EMAIL, + to: recipients, + subject, + html: ` +

    Respected Board Members,

    +

    Greetings from Somaiya Vidyavihar University !!

    +

    We are glad to invite you to the Board of Studies meeting:

    +

    ${body}

    +

    Program: ${program}

    +

    Department: ${department}

    +

    Date: ${formattedDate}

    +

    Time: ${formattedStartTime} - ${formattedEndTime}

    +

    Zoom Meeting Details:

    +

    Meeting ID: 265 561 6202

    +

    Meeting Password: 123456

    +

    Zoom Meeting Link: Join the Meeting

    +

    Agenda:

    + +

    📅 Click here to add this event to Google Calendar

    + ${ + conflictDetails + ? `

    Conflict detected!

    +

    Conflicting Meeting Details:

    + ` + : "" + } + `, + attachments: files.map((file) => ({ + filename: file.filename, + path: file.path, + })), + }; + + await transporter.sendMail(mailOptions); + + res.status(200).json({ + message: conflictDetails ? "Conflict detected! Email sent successfully." : "Email sent successfully!", + conflictDetails, + calendarLink, + }); + } catch (error) { + console.error("Error sending email:", error); + res.status(500).json({ error: "Error sending email" }); + } +}; + +module.exports = { sendEmail }; diff --git a/backend/controllers/meetingController.js b/backend/controllers/meetingController.js new file mode 100644 index 0000000..1b47f07 --- /dev/null +++ b/backend/controllers/meetingController.js @@ -0,0 +1,18 @@ +const Meeting = require("../models/Meeting"); + +exports.getMeetings = async (req, res) => { + try { + const meetings = await Meeting.find(); + const formattedMeetings = meetings.map((meeting) => { + const formattedAgenda = meeting.agenda + ? meeting.agenda.map((item, index) => `
  • ${index + 1}. ${item}
  • `).join("") + : "
  • No agenda provided
  • "; + return { ...meeting.toObject(), formattedAgenda }; + }); + + res.json(formattedMeetings); + } catch (error) { + console.error("Error fetching meetings:", error); + res.status(500).json({ error: "Error fetching meetings" }); + } +}; diff --git a/backend/middleware/upload.js b/backend/middleware/upload.js new file mode 100644 index 0000000..bb5dce4 --- /dev/null +++ b/backend/middleware/upload.js @@ -0,0 +1,11 @@ +const multer = require("multer"); +const path = require("path"); + +const storage = multer.diskStorage({ + destination: "uploads/", + filename: (req, file, cb) => { + cb(null, Date.now() + path.extname(file.originalname)); + }, +}); + +module.exports = multer({ storage }); diff --git a/backend/models/DepartmentEmail.js b/backend/models/DepartmentEmail.js new file mode 100644 index 0000000..5a3560e --- /dev/null +++ b/backend/models/DepartmentEmail.js @@ -0,0 +1,8 @@ +const mongoose = require("mongoose"); + +const DepartmentEmailSchema = new mongoose.Schema({ + department: String, + emails: [String] +}); + +module.exports = mongoose.model("DepartmentEmail", DepartmentEmailSchema); diff --git a/backend/models/Meeting.js b/backend/models/Meeting.js new file mode 100644 index 0000000..8502761 --- /dev/null +++ b/backend/models/Meeting.js @@ -0,0 +1,16 @@ +const mongoose = require("mongoose"); + +const meetingSchema = new mongoose.Schema({ + program: String, + department: String, + subject: String, + body: String, + agenda: [String], + date: String, + startTime: String, + endTime: String, + recipients: [String], + attachments: [{ filename: String, path: String }], +}); + +module.exports = mongoose.model("Meeting", meetingSchema); diff --git a/backend/models/Program.js b/backend/models/Program.js new file mode 100644 index 0000000..684fc78 --- /dev/null +++ b/backend/models/Program.js @@ -0,0 +1,26 @@ +const express = require("express"); +const { + getAllDepartmentEmails, + getDepartmentsByProgram, + getEmailsByDepartment, + updateDepartmentEmails, + createDepartment, + deleteDepartment, +} = require("../controllers/departmentController"); + +const router = express.Router(); + +router.get("/programs", async (req, res) => { + const Program = require("../models/Program"); + const programs = await Program.find(); + res.json(programs); +}); + +router.get("/departments/:program", getDepartmentsByProgram); +router.get("/department-emails/:department", getEmailsByDepartment); +router.get("/department-emails", getAllDepartmentEmails); +router.put("/department-emails/:department", updateDepartmentEmails); +router.post("/department-emails", createDepartment); +router.delete("/department-emails/:department", deleteDepartment); + +module.exports = router; diff --git a/backend/routes/departmentRoutes.js b/backend/routes/departmentRoutes.js new file mode 100644 index 0000000..684fc78 --- /dev/null +++ b/backend/routes/departmentRoutes.js @@ -0,0 +1,26 @@ +const express = require("express"); +const { + getAllDepartmentEmails, + getDepartmentsByProgram, + getEmailsByDepartment, + updateDepartmentEmails, + createDepartment, + deleteDepartment, +} = require("../controllers/departmentController"); + +const router = express.Router(); + +router.get("/programs", async (req, res) => { + const Program = require("../models/Program"); + const programs = await Program.find(); + res.json(programs); +}); + +router.get("/departments/:program", getDepartmentsByProgram); +router.get("/department-emails/:department", getEmailsByDepartment); +router.get("/department-emails", getAllDepartmentEmails); +router.put("/department-emails/:department", updateDepartmentEmails); +router.post("/department-emails", createDepartment); +router.delete("/department-emails/:department", deleteDepartment); + +module.exports = router; diff --git a/backend/routes/emailRoutes.js b/backend/routes/emailRoutes.js new file mode 100644 index 0000000..35b1299 --- /dev/null +++ b/backend/routes/emailRoutes.js @@ -0,0 +1,9 @@ +const express = require("express"); +const upload = require("../middleware/upload"); +const { sendEmail } = require("../controllers/emailController"); + +const router = express.Router(); + +router.post("/send-email", upload.array("attachments"), sendEmail); + +module.exports = router; diff --git a/backend/routes/meetingRoutes.js b/backend/routes/meetingRoutes.js new file mode 100644 index 0000000..b52bd1d --- /dev/null +++ b/backend/routes/meetingRoutes.js @@ -0,0 +1,8 @@ +const express = require("express"); +const { getMeetings } = require("../controllers/meetingController"); + +const router = express.Router(); + +router.get("/meetings", getMeetings); + +module.exports = router; diff --git a/backend/server.js b/backend/server.js index 0565a0f..2a665f5 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,185 +1,26 @@ -//server.js - require("dotenv").config(); const express = require("express"); -const mongoose = require("mongoose"); -const bodyParser = require("body-parser"); const cors = require("cors"); -const nodemailer = require("nodemailer"); -const multer = require("multer"); +const bodyParser = require("body-parser"); const path = require("path"); -const moment = require("moment"); + +const connectDB = require("./config/db"); +const emailRoutes = require("./routes/emailRoutes"); +const meetingRoutes = require("./routes/meetingRoutes"); +const departmentRoutes = require("./routes/departmentRoutes"); const app = express(); + app.use(cors()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); -app.use("/uploads", express.static("uploads")); +app.use("/uploads", express.static(path.join(__dirname, "uploads"))); -// Multer setup for file uploads -const storage = multer.diskStorage({ - destination: "uploads/", - filename: (req, file, cb) => { - cb(null, Date.now() + path.extname(file.originalname)); - }, -}); -const upload = multer({ storage }); +connectDB(); -// MongoDB connection -mongoose - .connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }) - .then(() => console.log("Connected to MongoDB")) - .catch((err) => console.error("MongoDB Connection Error:", err)); +app.use("/api", emailRoutes); +app.use("/api", meetingRoutes); +app.use("/api", departmentRoutes); -// Meeting Schema -const meetingSchema = new mongoose.Schema({ - program: String, - department: String, - subject: String, - body: String, - agenda: [String], - date: String, - startTime: String, - endTime: String, - recipients: [String], - attachments: [{ filename: String, path: String }], -}); -const Meeting = mongoose.model("Meeting", meetingSchema); - -app.get("/api/meetings", async (req, res) => { - try { - const meetings = await Meeting.find(); // Fetching all meetings - - // Format agenda in HTML for each meeting - const formattedMeetings = meetings.map((meeting) => { - const formattedAgenda = meeting.agenda - ? meeting.agenda.map((item, index) => `
  • ${index + 1}. ${item}
  • `).join("") - : "
  • No agenda provided
  • "; - return { ...meeting.toObject(), formattedAgenda }; // Add formatted agenda to each meeting - }); - - res.json(formattedMeetings); // Send formatted meetings - } catch (error) { - console.error("Error fetching meetings:", error); - res.status(500).json({ error: "Error fetching meetings" }); - } -}); - -// API to send email -app.post("/api/send-email", upload.array("attachments"), async (req, res) => { - try { - const { program, department, subject, body, agenda, date, startTime, endTime, recipients } = req.body; - const files = req.files; - - console.log({ program, department, subject, body, agenda, date, startTime, endTime, recipients, files }); - - if (!program || !department || !subject || !body || !date || !startTime || !endTime || !recipients) { - return res.status(400).json({ error: "All fields are required!" }); - } - - // Check for meeting conflicts - const conflict = await Meeting.findOne({ - date, - startTime: { $lt: endTime }, - endTime: { $gt: startTime }, - }); - - if (conflict) { - // Return the details of the conflicting meeting - const conflictDetails = { - department: conflict.department, - date: conflict.date, - startTime: conflict.startTime, - endTime: conflict.endTime, - recipients: conflict.recipients, - subject: conflict.subject, - }; - - return res.status(409).json({ - error: "Meeting conflict detected! Please choose a different time.", - conflictDetails - }); - } - - // Format date and time properly - const formattedDate = moment(date, "YYYY-MM-DD").format("dddd, MMMM Do YYYY"); - const formattedStartTime = moment(startTime, "HH:mm").format("hh:mm A"); - const formattedEndTime = moment(endTime, "HH:mm").format("hh:mm A"); - - // Format Google Calendar event link - const formattedStart = moment(`${date} ${startTime}`, "YYYY-MM-DD HH:mm").utc().format("YYYYMMDDTHHmmss[Z]"); - const formattedEnd = moment(`${date} ${endTime}`, "YYYY-MM-DD HH:mm").utc().format("YYYYMMDDTHHmmss[Z]"); - const zoomLink = "https://us05web.zoom.us/j/2655616202?pwd=S3d6RjVPNnhmQ3AzTlZsRC9GYmNHQT09"; - const calendarLink = `https://calendar.google.com/calendar/render?action=TEMPLATE&text=${encodeURIComponent( - subject - )}&details=${encodeURIComponent(`${body}\nJoin Zoom Meeting: ${zoomLink}`)}&dates=${formattedStart}/${formattedEnd}`; - - // Format agenda into pointwise list - const formattedAgenda = agenda - ? agenda.map((item, index) => `
  • ${index + 1}. ${item}
  • `).join("") - : "
  • No agenda provided
  • "; - - // Store meeting in DB - const newMeeting = new Meeting({ - program, - department, - subject, - body, - agenda, - date, - startTime, - endTime, - recipients, - attachments: files.map((file) => ({ filename: file.filename, path: file.path })), - }); - await newMeeting.save(); - - // Email transporter - const transporter = nodemailer.createTransport({ - service: "gmail", - auth: { - user: process.env.EMAIL, - pass: process.env.EMAIL_PASSWORD, - }, - }); - - // Email options - const mailOptions = { - from: process.env.EMAIL, - to: recipients, - subject, - html: ` -

    Respected Board Members,

    -

    Greetings from Somaiya Vidyavihar University !!

    -

    We are glad to invite you to the Board of Studies meeting:

    -

    ${body}

    -

    Program: ${program}

    -

    Department: ${department}

    -

    Date: ${formattedDate}

    -

    Time: ${formattedStartTime} - ${formattedEndTime}

    -

    Zoom Meeting Details:

    -

    Meeting ID: 265 561 6202

    -

    Meeting Password: 123456

    -

    Zoom Meeting Link: Join the Meeting

    -

    Agenda:

    - -

    📅 Click here to add this event to Google Calendar

    - `, - attachments: files.map((file) => ({ - filename: file.filename, - path: file.path, - })), - }; - - // Send email - await transporter.sendMail(mailOptions); - res.status(200).json({ message: "Email sent successfully!", calendarLink }); - } catch (error) { - console.error("Error sending email:", error); - res.status(500).json({ error: "Error sending email" }); - } -}); - -// Start server const PORT = process.env.PORT || 5000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); diff --git a/backend/uploads/1743699686010.docx b/backend/uploads/1743699686010.docx new file mode 100644 index 0000000..8b1dc6d Binary files /dev/null and b/backend/uploads/1743699686010.docx differ diff --git a/backend/uploads/1743699709610.docx b/backend/uploads/1743699709610.docx new file mode 100644 index 0000000..8b1dc6d Binary files /dev/null and b/backend/uploads/1743699709610.docx differ diff --git a/backend/uploads/1743699844366.docx b/backend/uploads/1743699844366.docx new file mode 100644 index 0000000..8b1dc6d Binary files /dev/null and b/backend/uploads/1743699844366.docx differ diff --git a/backend/uploads/1748321326875.pdf b/backend/uploads/1748321326875.pdf new file mode 100644 index 0000000..f0bd1bd Binary files /dev/null and b/backend/uploads/1748321326875.pdf differ diff --git a/backend/uploads/1748321328791.pdf b/backend/uploads/1748321328791.pdf new file mode 100644 index 0000000..f0bd1bd Binary files /dev/null and b/backend/uploads/1748321328791.pdf differ diff --git a/frontend/src/App.js b/frontend/src/App.js index ced5cd2..b2a7757 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,22 +1,25 @@ import React from 'react'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; -import Page1 from './Page1'; +import Page1 from './Page1'; import Page2 from './Page2'; -import Page3 from './Page3'; -import Page4 from './Page4'; -import Page5 from './Page5'; -import { GoogleOAuthProvider } from '@react-oauth/google'; +import Page3 from './Page3'; +import Page4 from './Page4'; +import Page5 from './Page5'; +import Page6 from './Page6'; +import { GoogleOAuthProvider } from '@react-oauth/google'; + const App = () => { return ( - + } /> - } /> + } /> } /> } /> } /> + } /> diff --git a/frontend/src/Page1.css b/frontend/src/Page1.css index 772ce85..4d700b3 100644 --- a/frontend/src/Page1.css +++ b/frontend/src/Page1.css @@ -1,3 +1,5 @@ +/*Page1.css*/ + /* General Styles */ * { margin: 0; diff --git a/frontend/src/Page1.js b/frontend/src/Page1.js index 13c8a0c..8fe9858 100644 --- a/frontend/src/Page1.js +++ b/frontend/src/Page1.js @@ -1,3 +1,5 @@ +//Page1.js + import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { GoogleLogin } from '@react-oauth/google'; // Import GoogleLogin component @@ -31,7 +33,7 @@ const Page1 = () => { // Allowed credentials const allowedCredentials = [ - { email: "hodcomp@somaiya.edu", password: "hodcomp123!" }, + { email: "hodcomp@somaiya.edu", password: "hodcomp123" }, { email: "director.kjsse@somaiya.edu", password: "directorkjsse2024" }, { email: "dean.engg@somaiya.edu", password: "deanengg2024" }, { email: "hodextc@somaiya.edu", password: "hodextc2024" }, diff --git a/frontend/src/Page2.css b/frontend/src/Page2.css index 57d4560..8acc6e5 100644 --- a/frontend/src/Page2.css +++ b/frontend/src/Page2.css @@ -1,3 +1,5 @@ +/*Page2.css*/ + /* General Styles */ body { margin: 0; diff --git a/frontend/src/Page2.js b/frontend/src/Page2.js index bf72876..3f104f5 100644 --- a/frontend/src/Page2.js +++ b/frontend/src/Page2.js @@ -1,3 +1,5 @@ +//Page2.js + import React, { useState } from "react"; import { Link } from "react-router-dom"; import './Page2.css'; // CSS File import @@ -30,7 +32,7 @@ const Page2 = () => {
  • Home
  • Schedule
  • Meeting DataBase
  • -
  • Contact
  • +
  • Edit DataBase
  • Log Out
  • diff --git a/frontend/src/Page3.css b/frontend/src/Page3.css index 3e94abc..052e2d3 100644 --- a/frontend/src/Page3.css +++ b/frontend/src/Page3.css @@ -1,4 +1,5 @@ /* Page3.css */ + .container { width: 100%; max-width: 600px; diff --git a/frontend/src/Page3.js b/frontend/src/Page3.js index 43e75d2..1a78451 100644 --- a/frontend/src/Page3.js +++ b/frontend/src/Page3.js @@ -1,3 +1,5 @@ +//Page3.js + import React, { useState } from "react"; import './Page3.css' diff --git a/frontend/src/Page4.css b/frontend/src/Page4.css index 4438c3f..9ef79ae 100644 --- a/frontend/src/Page4.css +++ b/frontend/src/Page4.css @@ -1,3 +1,5 @@ +/*Page4.css*/ + /* Container for the content area */ .content-area { width: 100%; diff --git a/frontend/src/Page4.js b/frontend/src/Page4.js index e51a087..444f9a1 100644 --- a/frontend/src/Page4.js +++ b/frontend/src/Page4.js @@ -1,28 +1,20 @@ +//Page4.js + import React, { useState } from "react"; import { Link } from "react-router-dom"; import axios from "axios"; import './Page2.css'; -import './Page4.css'; // Import the same CSS file for consistent styling -import { FaTimes } from "react-icons/fa"; // Red cross icon for agenda/removal +import './Page4.css'; +import { FaTimes } from "react-icons/fa"; import image from './components/image.png'; import somaiyatrust from './components/somaiyatrust.png'; import redlines from './components/redlines.png'; - -const programs = ["BTech", "MTech", "PhD"]; -const departments = [ - "Artificial Intelligence & Data Science", - "Computer Engineering", - "Computer & Communication Engineering", - "Computer Science & Business Systems", - "Electronics Engineering (VLSI Design & Technology)", - "Electronics & Computer Engineering", - "Electronics & Telecommunication Engineering", - "Information Technology", - "Mechanical Engineering", - "Robotics & Artificial Intelligence", -]; +import { useEffect } from "react"; const Page4 = () => { + const [programs, setPrograms] = useState([]); + const [departments, setDepartments] = useState([]); + const [departmentEmails, setDepartmentEmails] = useState([]); const [program, setProgram] = useState(""); const [department, setDepartment] = useState(""); const [subject, setSubject] = useState(""); @@ -34,6 +26,33 @@ const Page4 = () => { const [recipients, setRecipients] = useState([""]); const [attachments, setAttachments] = useState([]); + useEffect(() => { + axios.get("http://localhost:5000/api/programs") + .then(response => setPrograms(response.data)) + .catch(error => console.error("Error fetching programs:", error)); + }, []); + + useEffect(() => { + if (program) { + axios.get(`http://localhost:5000/api/departments/${program}`) + .then(response => setDepartments(response.data)) + .catch(error => console.error("Error fetching departments:", error)); + } else { + setDepartments([]); + } + }, [program]); + + useEffect(() => { + if (department) { + axios.get(`http://localhost:5000/api/department-emails/${department}`) + .then(response => { + setDepartmentEmails(response.data.emails); + setRecipients([...response.data.emails]); + }) + .catch(error => console.error("Error fetching department emails:", error)); + } + }, [department]); + const addAgenda = () => setAgenda([...agenda, ""]); const handleAgendaChange = (index, value) => { const updatedAgenda = [...agenda]; @@ -86,7 +105,7 @@ const Page4 = () => { } catch (err) { if (err.response?.status === 409) { const conflictDetails = err.response.data.conflictDetails; - alert(`Conflict Detected: + alert(`Conflict Detected : Department: ${conflictDetails.department} Date: ${conflictDetails.date} Time: ${conflictDetails.startTime} - ${conflictDetails.endTime} @@ -114,7 +133,7 @@ const Page4 = () => {
  • Home
  • Schedule
  • Meeting DataBase
  • -
  • Contact
  • +
  • Edit DataBase
  • Log Out
  • @@ -134,13 +153,11 @@ const Page4 = () => { {/* Content Area (Right Side) */}

    BOS Email Management System

    - + diff --git a/frontend/src/Page5.css b/frontend/src/Page5.css index 70c136c..c157270 100644 --- a/frontend/src/Page5.css +++ b/frontend/src/Page5.css @@ -1,141 +1,309 @@ -/* Ensure body has margin 0 and full height for scrolling */ -body { - margin: 0; - padding: 0; - font-family: Arial, sans-serif; - background-color: #f4f4f4; - min-height: 100vh; - overflow-y: auto; /* Ensure scrolling */ +/*Page5.css*/ + +/* Base Styles */ +:root { + --primary-red: #B7202E; + --dark-red: #8a0000; + --light-red: #d32f2f; + --white: #ffffff; + --light-gray: #f5f5f5; + --medium-gray: #e0e0e0; + --dark-gray: #757575; + --black: #212121; + --shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + --transition: all 0.3s ease; +} + +/* Page Container */ +.page-container { + display: flex; + flex-direction: column; + min-height: 100vh; + background-color: #f4f4f4; +} + +html, body { + margin: 0; + padding: 0; + height: auto; /* Let height grow naturally */ + overflow-x: hidden; /* Hide only horizontal scroll */ + overflow-y: auto; /* Allow vertical scroll */ +} + +/* Header Bar */ +.header-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px 20px; + background-color: var(--white); + box-shadow: var(--shadow); + position: sticky; + top: 0; + z-index: 100; +} + +.leftlogo, .rightlogo { + height: 50px; + width: auto; +} + +.college-name { + color: var(--primary-red); + font-size: 1.5rem; + margin: 0; +} + +/* Navigation Bar */ +.navbar { + background-color: var(--primary-red); + padding: 0 20px; +} + +.navbar ul { + list-style-type: none; + margin: 0; + padding: 0; + display: flex; + justify-content: center; + flex-wrap: wrap; +} + +.navbar li { + padding: 15px 20px; +} + +.navbar a { + color: var(--white); + text-decoration: none; + font-weight: 500; + transition: var(--transition); +} + +.navbar a:hover, .navbar a.active { + color: var(--white); + text-decoration: underline; + text-underline-offset: 5px; +} + +/* Main Content */ +.meetings-page-container { + flex: 1; + padding: 30px; + max-width: 1400px; + margin: 40px auto 0 auto; /* 40px top margin to separate from navbar */ + width: 100%; +} + +.page-title { + text-align: center; + color: var(--primary-red); + margin-bottom: 30px; + font-size: 2rem; +} + +.no-meetings { + text-align: center; + color: var(--dark-gray); + font-size: 1.2rem; + margin-top: 40px; +} + +/* Meetings Grid Container */ +.meetings-grid-container { + width: 100%; + overflow: hidden; +} + +.meetings-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); + gap: 25px; + padding: 10px; +} + +/* Meeting Cards */ +.meeting-card { + background-color: var(--white); + border-radius: 8px; + box-shadow: var(--shadow); + border-left: 4px solid var(--primary-red); + overflow: hidden; + transition: var(--transition); + display: flex; + flex-direction: column; + min-height: 150px; +} + +.meeting-card:hover { + transform: translateY(-5px); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15); +} + +.card-summary { + padding: 20px; + cursor: pointer; +} + +.meeting-title { + color: var(--black); + font-size: 1.2rem; + margin: 0 0 10px 0; + line-height: 1.3; +} + +.meeting-meta { + display: flex; + justify-content: space-between; + color: var(--dark-gray); + font-size: 0.9rem; + margin-bottom: 8px; +} + +.meeting-department { + color: var(--primary-red); + font-weight: 500; + font-size: 0.9rem; +} + +.card-details { + padding: 20px; + background-color: var(--light-gray); + border-top: 1px solid var(--medium-gray); + flex: 1; +} + +.detail-row { + display: flex; + margin-bottom: 10px; + line-height: 1.4; +} + +.detail-label { + font-weight: 600; + color: var(--primary-red); + min-width: 100px; +} + +.detail-section { + margin: 20px 0; +} + +.detail-section h3 { + color: var(--primary-red); + font-size: 1.1rem; + margin-bottom: 10px; + border-bottom: 1px solid var(--medium-gray); + padding-bottom: 5px; +} + +.agenda-list, .attachments-list { + padding-left: 20px; + margin: 10px 0; +} + +.agenda-list li, .attachments-list li { + margin-bottom: 8px; + line-height: 1.4; +} + +.attachments-list a { + color: var(--primary-red); + text-decoration: none; + transition: var(--transition); +} + +.attachments-list a:hover { + text-decoration: underline; +} + +.recipients-list { + word-break: break-all; +} + +/* Calendar Button */ +.calendar-button { + display: block; + background-color: var(--primary-red); + color: var(--white) !important; + text-align: center; + padding: 10px; + border-radius: 5px; + margin-top: 20px; + text-decoration: none; + transition: var(--transition); +} + +.calendar-button:hover { + background-color: var(--dark-red); +} + +/* Footer */ +footer { + background-color: var(--primary-red); + color: var(--white); + padding: 20px; + text-align: center; +} + +.terms { + display: flex; + justify-content: center; + align-items: center; + gap: 20px; +} + +.terms a { + color: var(--white); + text-decoration: none; +} + +.footer-image { + height: 30px; +} + +/* Responsive Design */ +@media (max-width: 1024px) { + .meetings-grid { + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } - - /* Main container for the meetings */ - .meetings-container { - background-color: #ffffff; - border-radius: 10px; /* Rounded corners */ - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - border: 1px solid #e0e0e0; /* Light border for the box */ - box-sizing: border-box; - max-width: 1200px; - margin: 20px auto; /* Added margin to ensure some space from top */ - padding: 20px; - } - - /* Heading for the page */ - h1 { - text-align: center; - font-size: 2rem; - margin-bottom: 20px; - } - - /* List of meetings */ - .meetings-list { - display: flex; +} + +@media (max-width: 768px) { + .header-bar { flex-direction: column; - gap: 20px; - } - - /* Styling for each meeting box */ - .meeting-box { - background-color: #ffffff; - padding: 20px; - border-radius: 10px; /* Rounded corners */ - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - border-left: 5px solid #B7202E; /* Changed to the new color */ - overflow: hidden; /* Prevents overflow */ - box-sizing: border-box; - } - - /* Styling for meeting titles */ - .meeting-box h2 { - font-size: 1.5rem; - color: #333; - margin-bottom: 10px; - } - - /* Styling for meeting details like Program, Date, etc. */ - .meeting-box p { - font-size: 1rem; - color: #555; - } - - /* Styling for links like Google Calendar and attachments */ - .meeting-box a { - text-decoration: none; - color: #B7202E; /* Changed to the new color */ - font-weight: bold; - display: inline-block; - margin-top: 10px; - } - - .meeting-box a:hover { - text-decoration: underline; - } - - /* Button for Google Calendar link */ - .google-calendar-link { - margin-top: 10px; - display: inline-block; - padding: 10px 20px; - background-color: #B7202E; /* Changed to the new color */ - color: white; - border-radius: 5px; - text-align: center; - } - - .google-calendar-link:hover { - background-color: #9e1c25; /* Darkened shade of the same color */ - } - - /* Ensure that meetings overflow properly on the page */ - body { - display: flex; - flex-direction: column; - justify-content: flex-start; - overflow-y: auto; - } - - .meeting-box ul { - list-style-type: none; - padding-left: 0; - } - - .meeting-box ul li { - font-size: 1rem; - color: #444; - margin-bottom: 5px; - } - - /* Responsive Design for smaller screens */ - @media (max-width: 768px) { - .meeting-box { - padding: 15px; - } - - .meeting-box h2 { - font-size: 1.2rem; - } - - .meeting-box p, - .meeting-box ul li { - font-size: 0.9rem; - } - - .google-calendar-link { - font-size: 0.9rem; - } + padding: 10px; } - /* Button for Google Calendar link */ -.google-calendar-link { - margin-top: 10px; - display: inline-block; - padding: 10px 20px; - background-color: #B7202E; /* Red color */ - color: white !important; /* Text color set to white */ - border-radius: 5px; - text-align: center; + .college-name { + margin: 10px 0; + font-size: 1.2rem; } - - .google-calendar-link:hover { - background-color: #9e1c25; /* Darkened shade of red on hover */ - } \ No newline at end of file + + .navbar li { + padding: 10px 15px; + } + + .meetings-page-container { + padding: 20px 15px; + } +} + +@media (max-width: 480px) { + .meetings-grid { + grid-template-columns: 1fr; + } + + .detail-row { + flex-direction: column; + } + + .detail-label { + margin-bottom: 5px; + } + + .meeting-meta { + flex-direction: column; + gap: 5px; + } +} \ No newline at end of file diff --git a/frontend/src/Page5.js b/frontend/src/Page5.js index ba72cbc..3b757ec 100644 --- a/frontend/src/Page5.js +++ b/frontend/src/Page5.js @@ -1,83 +1,164 @@ +//Page5.js + import React, { useState, useEffect } from 'react'; +import { Link } from 'react-router-dom'; import axios from 'axios'; import './Page5.css'; +import somaiyatrust from './components/somaiyatrust.png'; +import image from './components/image.png'; +import redlines from './components/redlines.png'; const Page5 = () => { const [meetings, setMeetings] = useState([]); + const [expandedIndex, setExpandedIndex] = useState(null); - // Fetch meetings data from the server useEffect(() => { - axios.get('http://localhost:5000/api/meetings') // Updated to backend URL + axios.get('http://localhost:5000/api/meetings') .then((response) => { - setMeetings(response.data); + // Sort meetings by date (newest first) and time + const sortedMeetings = response.data.sort((a, b) => { + const dateA = new Date(`${a.date}T${a.startTime}`); + const dateB = new Date(`${b.date}T${b.startTime}`); + return dateB - dateA; + }); + setMeetings(sortedMeetings); }) .catch((error) => { console.error('Error fetching meetings:', error); }); }, []); + const toggleExpand = (index) => { + setExpandedIndex(prev => (prev === index ? null : index)); + }; + return ( -
    -

    Meeting Details

    -
    +
    + {/* Header Bar */} +
    + Left Logo +

    Somaiya Scheduler

    + Right Logo +
    + + {/* Navigation Bar */} + + + {/* Main Content */} +
    +

    Meeting Details

    + {meetings.length === 0 ? ( -

    No meetings available

    +

    No meetings available

    ) : ( - meetings.map((meeting, index) => ( -
    -

    {meeting.subject}

    -

    Program: {meeting.program}

    -

    Department: {meeting.department}

    -

    Date: {meeting.date}

    -

    Time: {meeting.startTime} - {meeting.endTime}

    +
    +
    + {meetings.map((meeting, index) => ( +
    +
    toggleExpand(index)}> +

    {meeting.subject}

    +
    + {meeting.date} + {meeting.startTime} - {meeting.endTime} +
    +
    {meeting.department}
    +
    -

    Agenda:

    - {meeting.agenda && meeting.agenda.length > 0 ? ( -
      - {meeting.agenda.map((item, idx) => ( -
    • {item}
    • - ))} -
    - ) : ( -

    No agenda provided

    - )} + {expandedIndex === index && ( +
    +
    + Program: + {meeting.program} +
    -

    Body: {meeting.body}

    +
    +

    Agenda

    + {meeting.agenda && meeting.agenda.length > 0 ? ( +
      + {meeting.agenda.map((item, idx) => ( +
    • {item}
    • + ))} +
    + ) : ( +

    No agenda provided

    + )} +
    -

    Recipients: {meeting.recipients}

    +
    +

    Details

    +

    {meeting.body}

    +
    - {/* Display Attachments if available */} -

    Attachments:

    - {meeting.attachments && meeting.attachments.length > 0 ? ( - - ) : ( -

    No attachments available

    - )} - - - Add to Google Calendar - +
    + )} +
    + ))}
    - )) +
    )}
    + + {/* Footer */} +
    ); }; -export default Page5; +export default Page5; \ No newline at end of file diff --git a/frontend/src/Page6.css b/frontend/src/Page6.css new file mode 100644 index 0000000..53d3724 --- /dev/null +++ b/frontend/src/Page6.css @@ -0,0 +1,307 @@ +/*Page6.css*/ + +/* Root Variables (optional, for consistency) */ +:root { + --primary-red: #B7202E; + --dark-red: #8a0000; + --white: #ffffff; + --light-gray: #f5f5f5; + --medium-gray: #e0e0e0; + --dark-gray: #757575; + --shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + --transition: all 0.3s ease; +} + +/* Page Container */ +.page-container { + display: flex; + flex-direction: column; + min-height: 100vh; + background-color: #f4f4f4; +} + +/* Header Bar */ +.header-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px 20px; + background-color: var(--white); + box-shadow: var(--shadow); + position: sticky; + top: 0; + z-index: 100; +} + +.leftlogo, .rightlogo { + height: 50px; + width: auto; +} + +.college-name { + color: var(--primary-red); + font-size: 1.5rem; + margin: 0; + text-align: center; +} + +/* Navbar */ +.navbar { + background-color: var(--primary-red); + padding: 0 20px; +} + +.navbar ul { + list-style: none; + display: flex; + justify-content: center; + flex-wrap: wrap; + margin: 0; + padding: 0; +} + +.navbar li { + padding: 15px 20px; +} + +.navbar a { + color: var(--white); + text-decoration: none; + font-weight: 500; + transition: var(--transition); +} + +.navbar a:hover, .navbar a.active { + text-decoration: underline; + text-underline-offset: 5px; +} + +/* Main Content */ +.email-management-container { + flex: 1; + padding: 30px; + max-width: 1400px; + margin: 0 auto; + width: 100%; +} + +.email-management-container h1 { + text-align: center; + color: var(--primary-red); + margin-bottom: 30px; + font-size: 2rem; +} + +/* Search Bar */ +.search-bar { + margin-bottom: 20px; +} + +.search-bar input { + width: 100%; + padding: 10px; + border: 1px solid #ccc; + border-radius: 4px; + font-size: 16px; +} + +/* Grid Layout */ +.departments-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); + gap: 25px; + padding: 10px; +} + +/* Department Card Style */ +.department-card { + background-color: var(--white); + border-radius: 8px; + box-shadow: var(--shadow); + border-left: 4px solid var(--primary-red); + padding: 20px; + transition: var(--transition); + display: flex; + flex-direction: column; + justify-content: space-between; + min-height: 150px; +} + +.department-card:hover { + transform: translateY(-5px); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15); +} + +.department-card h3 { + margin-top: 0; + color: var(--primary-red); + font-size: 1.1rem; + border-bottom: 1px solid var(--medium-gray); + padding-bottom: 8px; +} + +.department-card ul { + list-style: none; + padding-left: 0; + margin-bottom: 10px; +} + +.department-card li { + padding: 5px 0; + border-bottom: 1px solid var(--medium-gray); + color: var(--dark-gray); + font-size: 0.95rem; +} + +/* Actions */ +.department-actions { + display: flex; + gap: 10px; + margin-top: 10px; +} + +.edit-btn, .delete-btn, .add-department-btn, .save-btn, .cancel-btn { + display: flex; + align-items: center; + gap: 5px; + padding: 8px 12px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; +} + +.edit-btn { + background-color: #4CAF50; + color: white; +} + +.delete-btn { + background-color: #f44336; + color: white; +} + +.add-department-btn { + background-color: #2196F3; + color: white; + margin-bottom: 20px; +} + +/* Edit Form */ +.edit-form { + background-color: var(--light-gray); + padding: 20px; + border-radius: 8px; + margin-bottom: 20px; +} + +.form-group { + margin-bottom: 15px; +} + +.form-group label { + display: block; + margin-bottom: 5px; + font-weight: bold; +} + +.form-group input { + width: 100%; + padding: 8px; + border: 1px solid var(--medium-gray); + border-radius: 4px; +} + +.email-input-group { + display: flex; + gap: 10px; + margin-bottom: 10px; + align-items: center; +} + +.email-input-group input { + flex: 1; +} + +.remove-email { + background: none; + border: none; + color: #f44336; + cursor: pointer; + font-size: 16px; +} + +.add-email { + background-color: #2196F3; + color: white; + border: none; + padding: 8px 12px; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + gap: 5px; +} + +.form-actions { + display: flex; + gap: 10px; + margin-top: 20px; +} + +/* Footer */ +footer { + background-color: var(--primary-red); + color: var(--white); + padding: 20px; + text-align: center; +} + +.terms { + display: flex; + justify-content: center; + align-items: center; + gap: 20px; +} + +.terms a { + color: var(--white); + text-decoration: none; +} + +.footer-image { + height: 30px; +} + +/* Responsive */ +@media (max-width: 1024px) { + .departments-list { + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + } +} + +@media (max-width: 768px) { + .header-bar { + flex-direction: column; + padding: 10px; + } + + .college-name { + margin: 10px 0; + font-size: 1.2rem; + } + + .navbar li { + padding: 10px 15px; + } + + .email-management-container { + padding: 20px 15px; + } +} + +@media (max-width: 480px) { + .departments-list { + grid-template-columns: 1fr; + } +} diff --git a/frontend/src/Page6.js b/frontend/src/Page6.js new file mode 100644 index 0000000..2be27a0 --- /dev/null +++ b/frontend/src/Page6.js @@ -0,0 +1,281 @@ +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; +import { Link } from 'react-router-dom'; +import { FaEdit, FaTrash, FaPlus, FaSave, FaTimes } from 'react-icons/fa'; +import './Page6.css'; +import image from './components/image.png'; +import somaiyatrust from './components/somaiyatrust.png'; +import redlines from './components/redlines.png'; + +const Page6 = () => { + const [departments, setDepartments] = useState([]); + const [programs, setPrograms] = useState([]); + const [newDepartment, setNewDepartment] = useState(''); + const [newEmails, setNewEmails] = useState(['']); + const [selectedProgram, setSelectedProgram] = useState(''); + const [editingDepartment, setEditingDepartment] = useState(null); + const [isAddingNew, setIsAddingNew] = useState(false); + const [searchTerm, setSearchTerm] = useState(''); + + useEffect(() => { + fetchDepartments(); + fetchPrograms(); + }, []); + + const fetchDepartments = async () => { + try { + const response = await axios.get('http://localhost:5000/api/department-emails'); + setDepartments(response.data); + } catch (error) { + console.error('Error fetching departments:', error); + } + }; + + const fetchPrograms = async () => { + try { + const response = await axios.get('http://localhost:5000/api/programs'); + setPrograms(response.data); + } catch (error) { + console.error('Error fetching programs:', error); + } + }; + + const handleAddEmail = () => { + setNewEmails([...newEmails, '']); + }; + + const handleNewEmailChange = (index, value) => { + const updatedEmails = [...newEmails]; + updatedEmails[index] = value; + setNewEmails(updatedEmails); + }; + + const handleRemoveEmail = (index) => { + const updatedEmails = newEmails.filter((_, i) => i !== index); + setNewEmails(updatedEmails); + }; + + const startEditing = (department) => { + setEditingDepartment(department); + setNewEmails([...department.emails]); + setIsAddingNew(false); + }; + + const cancelEditing = () => { + setEditingDepartment(null); + setIsAddingNew(false); + setNewDepartment(''); + setNewEmails(['']); + setSelectedProgram(''); + }; + + const saveDepartment = async () => { + try { + const emailsToSave = newEmails.filter(email => email.trim() !== ''); + + if (emailsToSave.length === 0) { + alert('At least one email is required'); + return; + } + + if (isAddingNew) { + if (!newDepartment.trim()) { + alert('Department name is required'); + return; + } + if (!selectedProgram) { + alert('Please select a program'); + return; + } + + await axios.post('http://localhost:5000/api/department-emails', { + department: newDepartment, + emails: emailsToSave, + program: selectedProgram, + }); + } else { + await axios.put(`http://localhost:5000/api/department-emails/${editingDepartment.department}`, { + emails: emailsToSave + }); + } + + fetchDepartments(); + cancelEditing(); + } catch (error) { + console.error('Error saving department:', error); + alert('Error saving department. Please try again.'); + } + }; + + const deleteDepartment = async (departmentName) => { + if (window.confirm(`Are you sure you want to delete ${departmentName}?`)) { + try { + await axios.delete(`http://localhost:5000/api/department-emails/${departmentName}`); + fetchDepartments(); + } catch (error) { + console.error('Error deleting department:', error); + alert('Error deleting department. Please try again.'); + } + } + }; + + const filteredDepartments = departments.filter(dept => + dept.department.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + return ( +
    + {/* Header Bar */} +
    + Left Logo +

    Somaiya Scheduler

    + Right Logo +
    + + {/* Navigation Bar */} + + + {/* Main Content */} +
    +

    Department Email Management

    + +
    + setSearchTerm(e.target.value)} + /> +
    + + {editingDepartment || isAddingNew ? ( +
    +

    {isAddingNew ? 'Add New Department' : `Editing: ${editingDepartment.department}`}

    + + {isAddingNew && ( + <> +
    + + +
    + +
    + + setNewDepartment(e.target.value)} + placeholder="Enter department name" + /> +
    + + )} + +
    + + {newEmails.map((email, index) => ( +
    + handleNewEmailChange(index, e.target.value)} + placeholder="Enter email" + /> + {newEmails.length > 1 && ( + + )} +
    + ))} + +
    + +
    + + +
    +
    + ) : ( + <> + + +
    + {filteredDepartments.length === 0 ? ( +

    No departments found

    + ) : ( + filteredDepartments.map((dept) => ( +
    +

    {dept.department}

    +
      + {dept.emails.map((email, idx) => ( +
    • {email}
    • + ))} +
    +
    + + +
    +
    + )) + )} +
    + + )} +
    + + {/* Footer */} + +
    + ); +}; + +export default Page6;