diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..5a007a8
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,45 @@
+# Email Configuration for Production Deployment
+# ==============================================
+
+# Gmail SMTP Configuration (recommended for production)
+SMTP_HOST=smtp.gmail.com
+SMTP_PORT=587
+SMTP_SECURE=false
+EMAIL_USER=your-gmail-address@gmail.com
+# Use App Password, NOT your regular Gmail password
+# Generate at: https://myaccount.google.com/apppasswords
+EMAIL_PASS=your-app-password-here
+
+# Advanced SMTP Settings (optional, defaults are optimized)
+SMTP_MAX_CONNECTIONS=3
+SMTP_MAX_MESSAGES=50
+
+# Environment
+NODE_ENV=production
+
+# Alternative Email Providers (uncomment to use)
+# ================================================
+
+# Outlook/Hotmail
+# SMTP_HOST=smtp-mail.outlook.com
+# SMTP_PORT=587
+# SMTP_SECURE=false
+
+# Yahoo Mail
+# SMTP_HOST=smtp.mail.yahoo.com
+# SMTP_PORT=587
+# SMTP_SECURE=false
+
+# SendGrid (Recommended for high-volume production)
+# SMTP_HOST=smtp.sendgrid.net
+# SMTP_PORT=587
+# SMTP_SECURE=false
+# EMAIL_USER=apikey
+# EMAIL_PASS=your-sendgrid-api-key
+
+# Mailgun
+# SMTP_HOST=smtp.mailgun.org
+# SMTP_PORT=587
+# SMTP_SECURE=false
+# EMAIL_USER=your-mailgun-smtp-username
+# EMAIL_PASS=your-mailgun-smtp-password
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2eea525
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.env
\ No newline at end of file
diff --git a/EMAIL_SETUP_GUIDE.md b/EMAIL_SETUP_GUIDE.md
new file mode 100644
index 0000000..f928a1e
--- /dev/null
+++ b/EMAIL_SETUP_GUIDE.md
@@ -0,0 +1,136 @@
+# Email Configuration Guide for Production Deployment
+
+## The Problem
+Your application works in localhost but fails to send emails in production (Render) due to SMTP connection timeouts. This is a common issue when deploying to cloud platforms.
+
+## Root Cause
+1. **Port Configuration**: Many cloud platforms block port 465 (SMTP over SSL)
+2. **Connection Timeouts**: Production environments have stricter timeout settings
+3. **Gmail Security**: Gmail requires App Passwords for production applications
+4. **Network Restrictions**: Some cloud providers have firewall restrictions
+
+## Solutions Implemented
+
+### 1. Updated SMTP Configuration
+- Changed default port from 465 to 587 (STARTTLS)
+- Added production-optimized timeout settings
+- Implemented connection pooling with rate limiting
+- Added proper TLS configuration
+
+### 2. Added Retry Mechanism
+- Automatic retry with exponential backoff
+- Better error logging for debugging
+- Non-blocking email failures (won't crash the application)
+
+### 3. Environment-Specific Settings
+- Different configurations for development vs production
+- Comprehensive error logging
+- Connection health checks
+
+## Setup Instructions for Render
+
+### Step 1: Configure Gmail App Password
+1. Go to [Google Account Settings](https://myaccount.google.com)
+2. Enable 2-Factor Authentication if not already enabled
+3. Go to [App Passwords](https://myaccount.google.com/apppasswords)
+4. Generate an App Password for your application
+5. Use this App Password in your environment variables (NOT your regular password)
+
+### Step 2: Set Environment Variables in Render
+In your Render dashboard, add these environment variables:
+
+```bash
+SMTP_HOST=smtp.gmail.com
+SMTP_PORT=587
+SMTP_SECURE=false
+EMAIL_USER=your-gmail-address@gmail.com
+EMAIL_PASS=your-app-password-here
+NODE_ENV=production
+```
+
+### Step 3: Alternative Email Providers (if Gmail still fails)
+
+#### SendGrid (Recommended for Production)
+```bash
+SMTP_HOST=smtp.sendgrid.net
+SMTP_PORT=587
+SMTP_SECURE=false
+EMAIL_USER=apikey
+EMAIL_PASS=your-sendgrid-api-key
+```
+
+#### Mailgun
+```bash
+SMTP_HOST=smtp.mailgun.org
+SMTP_PORT=587
+SMTP_SECURE=false
+EMAIL_USER=your-mailgun-smtp-username
+EMAIL_PASS=your-mailgun-smtp-password
+```
+
+### Step 4: Test the Configuration
+Add this test endpoint to verify email functionality:
+
+```javascript
+// Add to your routes
+app.get('/test-email', async (req, res) => {
+ try {
+ await sendEmail(
+ 'test@example.com',
+ 'Test Email',
+ 'This is a test email from production'
+ );
+ res.json({ success: true, message: 'Email sent successfully' });
+ } catch (error) {
+ res.status(500).json({
+ success: false,
+ error: error.message,
+ code: error.code
+ });
+ }
+});
+```
+
+## Troubleshooting
+
+### Common Issues and Solutions
+
+1. **Connection Timeout (ETIMEDOUT)**
+ - Switch to port 587 instead of 465
+ - Check if your hosting provider blocks SMTP ports
+ - Try alternative email providers like SendGrid
+
+2. **Authentication Failed**
+ - Ensure you're using App Password, not regular password
+ - Verify EMAIL_USER and EMAIL_PASS are correctly set
+ - Check if Less Secure Apps is enabled (not recommended)
+
+3. **TLS/SSL Issues**
+ - Use SMTP_SECURE=false with port 587
+ - Set proper TLS configuration in code
+
+4. **Rate Limiting**
+ - Implemented automatic rate limiting (5 emails per second)
+ - Added retry mechanism for failed sends
+
+### Debug Steps
+1. Check the email health endpoint: `GET /api/email-health`
+2. Monitor application logs for detailed error messages
+3. Test with a simple email first
+4. Verify all environment variables are set correctly
+
+## Best Practices for Production
+
+1. **Use Dedicated Email Services**: Consider SendGrid, Mailgun, or AWS SES for production
+2. **Monitor Email Delivery**: Set up logging and monitoring for email failures
+3. **Implement Email Queues**: For high-volume applications, use a queue system
+4. **Error Handling**: Never let email failures crash your application
+5. **Security**: Always use App Passwords or API keys, never regular passwords
+
+## Code Changes Made
+
+1. **Enhanced SMTP Configuration**: Added timeout settings, rate limiting, and TLS configuration
+2. **Retry Logic**: Automatic retry with exponential backoff for failed emails
+3. **Async/Await**: Converted all email calls to async/await with proper error handling
+4. **Better Logging**: Comprehensive error logging for debugging
+5. **Non-blocking**: Email failures won't block the application flow
\ No newline at end of file
diff --git a/README.md b/README.md
index 1747334..e8d9ec9 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
+# Fork Details
+- Forked from Outpass Management System
+- To Modify to convert it into an Institute Forms Portal
+- Details of original project below
+
# Outpass Management System
## Project Overview
diff --git a/backend/.dockerignore b/backend/.dockerignore
new file mode 100644
index 0000000..e34d45e
--- /dev/null
+++ b/backend/.dockerignore
@@ -0,0 +1,11 @@
+node_modules
+npm-debug.log
+.env
+.git
+.gitignore
+README.md
+Dockerfile
+.dockerignore
+coverage
+.nyc_output
+.log
\ No newline at end of file
diff --git a/backend/.env b/backend/.env
deleted file mode 100644
index 83624a0..0000000
--- a/backend/.env
+++ /dev/null
@@ -1,5 +0,0 @@
-PORT= 4001
-MongoDBURI="mongodb+srv://prajwalkoppad30:sWiDnWaAcpFA9GYC@cluster0.qen37.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"
-JWT_SECRET=sleepyboiswinsleeplesscodingsaga
-EMAIL_USER=prajwalkoppad30@gmail.com
-EMAIL_PASS=mfst dgwr wtwp jslf
\ No newline at end of file
diff --git a/backend/Dockerfile b/backend/Dockerfile
new file mode 100644
index 0000000..07a579b
--- /dev/null
+++ b/backend/Dockerfile
@@ -0,0 +1,23 @@
+# Use official Node.js LTS (Long Term Support) image
+FROM node:22-alpine
+
+# Set working directory
+WORKDIR /app
+
+# Copy package.json and package-lock.json (if available)
+COPY package*.json ./
+
+# Install dependencies
+RUN npm ci --only=production
+
+# Copy the rest of the application code
+COPY . .
+
+# Set the port for the container
+ENV PORT=5000
+
+# Expose the port your app runs on (adjust if different)
+EXPOSE 5000
+
+# Command to run the application
+CMD ["npm", "start"]
\ No newline at end of file
diff --git a/backend/controller/event.controller.js b/backend/controller/event.controller.js
new file mode 100644
index 0000000..50d38d4
--- /dev/null
+++ b/backend/controller/event.controller.js
@@ -0,0 +1,1071 @@
+import EventApproval from "../models/event.model.js";
+import User from "../models/user.model.js";
+import nodemailer from "nodemailer";
+import dotenv from "dotenv";
+
+dotenv.config();
+
+// Utility function to determine semester and academic year based on date
+const getSemesterInfo = (date) => {
+ const eventDate = new Date(date);
+ const month = eventDate.getMonth(); // 0-11
+ const year = eventDate.getFullYear();
+
+ let semester, academicYear;
+
+ // Assuming academic year starts in August and ends in July next year
+ // Fall semester: August - December
+ // Spring semester: January - July
+
+ if (month >= 7) { // August (7) to December (11)
+ semester = "Autumn";
+ academicYear = `${year}-${year + 1}`;
+ } else { // January (0) to July (6)
+ semester = "Spring";
+ academicYear = `${year - 1}-${year}`;
+ }
+
+ return {
+ semester: `${semester} ${academicYear.split('-')[semester === 'Autumn' ? 0 : 1]}`,
+ academicYear
+ };
+};
+
+// Configure nodemailer
+const transporter = nodemailer.createTransport({
+ service: 'gmail',
+ auth: {
+ user: process.env.EMAIL_USER,
+ pass: process.env.EMAIL_PASS
+ }
+});
+
+
+const sendEmail = async (to, subject, text, retries = 3) => {
+ const mailOptions = {
+ from: process.env.EMAIL_USER,
+ to,
+ subject,
+ text
+ };
+
+ console.log('Attempting to send email to:', to, 'with', retries, 'retries remaining');
+
+ transporter.sendMail(mailOptions, (error, info) => {
+ if (error) {
+ console.error('Error sending email:', error);
+ } else {
+ console.log('Email sent:', info.response);
+ }
+ });
+};
+
+
+//emails of all members
+const roleEmails = [
+ { role: "general-secretary-technical", email: "gstech@iitdh.ac.in" },
+ { role: "general-secretary-cultural", email: "nidhishadoshi05@gmail.com" },
+ { role: "general-secretary-sports", email: "sports.secretary@example.com" },
+ { role: "treasurer", email: "cs23bt009@iitdh.ac.in" },
+ { role: "president", email: "cs23bt009@iitdh.ac.in" },
+ { role: "faculty-in-charge", email: "nidhishadoshi05@gmail.com" },
+ { role: "associate-dean", email: "cs23bt009@iitdh.ac.in" },
+];
+
+const getEmailForRole = (role) => {
+ const match = roleEmails.find((entry) => entry.role === role);
+ return match ? match.email : null;
+};
+const getEmailForCategory = (category) => {
+ const role = `general-secretary-${category.toLowerCase()}`;
+ const match = roleEmails.find((entry) => entry.role === role);
+ return match ? match.email : null;
+};
+
+
+// Apply for Event approval
+
+export const applyForEventApproval = async (req, res) => {
+ try {
+ const {
+ userID,
+ eventName,
+ partOfGymkhanaCalendar,
+ clubName,
+ startDate,
+ endDate,
+ eventVenue,
+ sourceOfBudget,
+ estimatedBudget,
+ nameOfTheOrganizer,
+ designation,
+ email,
+ phoneNumber,
+ requirements,
+ anyAdditionalAmenities,
+ eventDescription,
+ internalParticipants,
+ externalParticipants,
+ listOfCollaboratingOrganizations,
+ } = req.body;
+
+ console.log("Incoming Payload:", req.body);
+
+ const userID_ = req.body.userID; // Ensure this is retrieved correctly (e.g., from the request or session).
+
+ // Fetch user details to ensure they exist
+ const user = await User.findById(userID_);
+ if (!user) {
+ return res.status(404).json({ message: "User not found. Please log in again." });
+ }
+
+ // Set eventType based on user's type if club-secretary, else fallback to req.body.eventType
+ let eventType = req.body.eventType;
+ if (user.role === "club-secretary") {
+ eventType = user.type;
+ }
+
+ const category = eventType;
+ const categoryEmail = getEmailForCategory(category);
+
+ // Check for any existing event approval in progress for this user
+ const existingEvent = await EventApproval.findOne({
+ userID_,
+ "approvals.status": { $in: ["Pending"] },
+ });
+
+ if (existingEvent) {
+ return res.status(400).json({ message: "You already have a pending event approval request." });
+ }
+
+ // Determine semester and academic year based on start date
+ const semesterInfo = getSemesterInfo(startDate);
+
+ // Create the initial approvals array
+ const approvals = [
+ { role: "club-secretary", status: "Approved", comment: "" },
+ { role: "general-secretary", status: "Pending", comment: "" },
+ { role: "treasurer", status: "Pending", comment: "" },
+ { role: "president", status: "Pending", comment: "" },
+ { role: "faculty-in-charge", status: "Pending", comment: "" },
+ { role: "associate-dean", status: "Pending", comment: "" },
+ ];
+
+ // Create a new event approval request
+ const newEventApproval = new EventApproval({
+ userID,
+ eventName,
+ partOfGymkhanaCalendar,
+ eventType, // Use the determined eventType
+ clubName,
+ startDate,
+ endDate,
+ semester: semesterInfo.semester,
+ academicYear: semesterInfo.academicYear,
+ eventVenue,
+ sourceOfBudget,
+ estimatedBudget,
+ nameOfTheOrganizer,
+ designation,
+ email,
+ phoneNumber,
+ requirements,
+ anyAdditionalAmenities,
+ eventDescription,
+ internalParticipants,
+ externalParticipants,
+ listOfCollaboratingOrganizations,
+ approvals,
+ });
+
+ // Save the new approval
+ const savedApproval = await newEventApproval.save();
+
+ // Update the user's `eventApproval` field with the new approval ID
+ user.eventApproval = savedApproval._id;
+ await user.save();
+ if (categoryEmail) {
+ try {
+ await sendEmail(
+ categoryEmail,
+ `Event Approval Needed: ${eventName}`,
+ `A new ${category} event approval request has been submitted. Please review it at your earliest convenience.`
+ );
+ console.log(`Email sent successfully to ${categoryEmail} for ${category} event approval.`);
+ } catch (emailError) {
+ console.error(`Failed to send email to ${categoryEmail}:`, emailError.message);
+ // Don't fail the entire request due to email issues
+ }
+ } else {
+ console.error(`No email found for category: ${category}`);
+ }
+
+
+ res.status(201).json({
+ message: "Event approval request submitted successfully.",
+ eventApproval: newEventApproval,
+ });
+ } catch (error) {
+ if (error.name === "ValidationError") {
+ console.error("Validation Error:", error.errors);
+ return res.status(400).json({ message: "Validation error", errors: error.errors });
+ }
+ console.error("Error submitting event approval request:", error.message);
+ res.status(500).json({ message: "Internal server error" });
+ }
+};
+
+export const getUserEvents = async (req, res) => {
+ const { userID } = req.body;
+
+ try {
+ // Find events associated with the user's ID
+ const events = await EventApproval.find({ userID });
+ if (!events || events.length === 0) {
+ return res.status(404).json({ message: "No events found for this user." });
+ }
+
+ res.status(200).json({ events });
+ } catch (error) {
+ console.error("Error fetching user events:", error.message);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+//get pending approvals list
+//put in staff dashboard Pending section
+
+const roleHierarchy = ["club-secretary", "general-secretary", "treasurer", "president", "faculty-in-charge", "associate-dean"];
+
+export const getPendingApprovals = async (req, res) => {
+ const { role, category } = req.body;
+
+ try {
+ if (!role) {
+ return res.status(400).json({ message: "Role is required." });
+ }
+
+ const roleIndex = roleHierarchy.indexOf(role);
+ if (roleIndex === -1) {
+ return res.status(400).json({ message: "Invalid role." });
+ }
+
+ // Find all applications with the specified role
+ let pendingApprovals = await EventApproval.find({
+ "approvals.role": role,
+ });
+
+ // If no applications are found, return a response and exit
+ if (pendingApprovals.length === 0) {
+ return res.status(200).json({ message: "No applications found." });
+ }
+
+ // Filter out those with a status of 'Pending' or 'Query'
+ pendingApprovals = pendingApprovals.filter((approval) => {
+ const approvalStatus = approval.approvals.find(
+ (app) => app.role === role
+ );
+ return approvalStatus && (approvalStatus.status === "Pending" || approvalStatus.status === "Query");
+ });
+
+ // Ensure previous roles in the hierarchy are approved
+ pendingApprovals = pendingApprovals.filter((approval) => {
+ return roleHierarchy.slice(0, roleIndex).every((prevRole) => {
+ const prevApproval = approval.approvals.find((app) => app.role === prevRole);
+ return prevApproval && prevApproval.status === "Approved";
+ });
+ });
+
+ // If 'general-secretary', filter by event category
+ if (role === "general-secretary" && category) {
+ pendingApprovals = pendingApprovals.filter(
+ (approval) => approval.eventType === category
+ );
+ }
+
+ // Return filtered pending approvals
+ res.status(200).json(pendingApprovals);
+ } catch (error) {
+ console.error("Error fetching pending approvals:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// Function to fetch event details by ID
+export const getEventById = async (req, res) => {
+ const { id } = req.params;
+
+ try {
+ // Find the event by ID
+ const event = await EventApproval.findById(id);
+
+ if (!event) {
+ return res.status(404).json({ message: "Event not found." });
+ }
+
+ res.status(200).json(event);
+ } catch (error) {
+ console.error("Error fetching event details:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+
+export const getApprovedApplications = async (req, res) => {
+ const { role, category, status} = req.body;
+
+ console.log("Received role:", role);
+ console.log("Received category:", category);
+
+ try {
+ if (!role) {
+ return res.status(400).json({ message: "Role is required." });
+ }
+
+ // Fetch only events with matching role and approved status
+ let approvedApplications = await EventApproval.find({
+ "approvals": {
+ $elemMatch: {
+ role: role,
+ status: "Approved"
+ }
+ }
+ });
+
+ console.log("Initial approved applications:", approvedApplications);
+
+ if (approvedApplications.length === 0) {
+ return res.status(200).json([]);
+ }
+
+ // Filter by category if role is 'general-secretary'
+ if (role === "general-secretary" && category) {
+ approvedApplications = approvedApplications.filter(
+ (approval) => approval.eventType === category
+ );
+ }
+
+ // Filter out applications with `endDate` before the current date
+ const currentDate = new Date();
+ approvedApplications = approvedApplications.filter((approval) => {
+ const endDate = new Date(approval.endDate);
+ return currentDate <= endDate;
+ });
+
+ console.log("Final approved applications:", approvedApplications);
+ res.status(200).json(approvedApplications);
+ } catch (error) {
+ console.error("Error fetching approved applications:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// Get Rejected Event Applications
+export const getRejectedApplications = async (req, res) => {
+ const { role, category } = req.body;
+
+ console.log("Received role:", role);
+ console.log("Received category:", category);
+
+ try {
+ if (!role) {
+ return res.status(400).json({ message: "Role is required." });
+ }
+
+ // Fetch only events with matching role and rejected status
+ let rejectedApplications = await EventApproval.find({
+ "approvals": {
+ $elemMatch: {
+ role: role,
+ status: "Rejected"
+ }
+ }
+ });
+
+ console.log("Initial rejected applications:", rejectedApplications);
+
+ if (rejectedApplications.length === 0) {
+ return res.status(200).json([]);
+ }
+
+ // Filter by category if role is 'general-secretary'
+ if (role === "general-secretary" && category) {
+ rejectedApplications = rejectedApplications.filter(
+ (approval) => approval.eventType === category
+ );
+ }
+
+ // Filter out applications with `endDate` before the current date (optional)
+ const currentDate = new Date();
+ rejectedApplications = rejectedApplications.filter((approval) => {
+ const endDate = new Date(approval.endDate);
+ return currentDate <= endDate; // Only show future rejected events (optional logic)
+ });
+
+ console.log("Final rejected applications:", rejectedApplications);
+ res.status(200).json(rejectedApplications);
+ } catch (error) {
+ console.error("Error fetching rejected applications:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+//approve an event function
+
+// Function to approve an application based on the role
+export const approveApplication = async (req, res) => {
+ const { applicationId, role } = req.body;
+
+ try {
+ // Check if the role is valid
+ if (!role || !roleHierarchy.includes(role)) {
+ return res.status(400).json({ message: "Invalid or missing role." });
+ }
+
+ // Find the event approval by applicationId
+ const eventApproval = await EventApproval.findById(applicationId);
+ if (!eventApproval) {
+ return res.status(404).json({ message: "Event approval not found." });
+ }
+
+ // Find the index of the approval object corresponding to the given role
+ const approvalIndex = eventApproval.approvals.findIndex(
+ (approval) => approval.role === role && approval.status === "Pending"
+ );
+
+ if (approvalIndex === -1) {
+ return res.status(400).json({ message: "No pending approval found for this role." });
+ }
+
+ // Update the status of the approval to "Approved"
+ eventApproval.approvals[approvalIndex].status = "Approved";
+ const nextRoleIndex = roleHierarchy.indexOf(role) + 1;
+ if (nextRoleIndex < roleHierarchy.length) {
+ const nextRole = roleHierarchy[nextRoleIndex];
+
+ sendEmail(
+ `${getEmailForRole(nextRole)}`, // Replace with actual email
+ `Event Approval Needed: ${eventApproval.eventName}`,
+ `The event "${eventApproval.eventName}" has been approved by ${role}. It is now pending your review and approval.`
+ );
+ }
+
+ // Save the updated event approval document
+ await eventApproval.save();
+
+ // Optionally, you can also send a notification email or take further actions here
+ res.status(200).json({ message: `${role} approved the application successfully.` });
+ } catch (error) {
+ console.error("Error approving application:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// In your event.controller.js file
+
+export const handleApprovalStatus = async (req, res) => {
+ const { applicationId, role, status, comment } = req.body;
+
+ try {
+ console.log("Received request:", { applicationId, role, status, comment }); // Debug log
+
+ if (!role || !['Approved', 'Rejected', 'Query'].includes(status)) {
+ console.log("Invalid role or status"); // Debug log
+ return res.status(400).json({ message: "Invalid role or status." });
+ }
+
+ const eventApproval = await EventApproval.findById(applicationId);
+
+ if (!eventApproval) {
+ console.log("Event approval not found"); // Debug log
+ return res.status(404).json({ message: "Event approval not found." });
+ }
+
+ const approvalIndex = eventApproval.approvals.findIndex(
+ (app) => app.role === role && app.status === "Pending"
+ );
+
+ if (approvalIndex === -1) {
+ console.log("No pending approval found for this role"); // Debug log
+ return res.status(400).json({ message: "No pending approval found for this role." });
+ }
+
+ eventApproval.approvals[approvalIndex].status = status;
+ eventApproval.approvals[approvalIndex].comment = comment || "";
+
+ if(status === "Rejected"){
+ try {
+ await sendEmail(
+ eventApproval.email,
+ `Event Rejected: ${eventApproval.eventName}`,
+ `Your event "${eventApproval.eventName}" has been rejected by ${role}. Reason: ${comment || "No reason provided."}`
+ );
+ console.log(`Rejection email sent to organizer: ${eventApproval.email}`);
+ } catch (emailError) {
+ console.error(`Failed to send rejection email to organizer:`, emailError.message);
+ }
+ }
+ else if(status === "Approved"){
+ const nextRoleIndex = roleHierarchy.indexOf(role) + 1;
+ if (nextRoleIndex < roleHierarchy.length) {
+ const nextRole = roleHierarchy[nextRoleIndex];
+ const nextRoleEmail = getEmailForRole(nextRole);
+
+ if (nextRoleEmail) {
+ try {
+ await sendEmail(
+ nextRoleEmail,
+ `Event Approval Needed: ${eventApproval.eventName}`,
+ `The event "${eventApproval.eventName}" has been approved by ${role}. It is now pending your review and approval.`
+ );
+ console.log(`Notification email sent to ${nextRole} at ${nextRoleEmail}`);
+ } catch (emailError) {
+ console.error(`Failed to send notification email to ${nextRole}:`, emailError.message);
+ }
+ } else {
+ console.error(`No email found for next role: ${nextRole}`);
+ }
+ } else if (nextRoleIndex === roleHierarchy.length) {
+ try {
+ await sendEmail(
+ eventApproval.email,
+ `Event Fully Approved: ${eventApproval.eventName}`,
+ `Congratulations! Your event "${eventApproval.eventName}" has been fully approved by all authorities.
+ Event Details:
+ - Event Name: ${eventApproval.eventName}
+ - Event Type: ${eventApproval.eventType}
+ - Date: ${new Date(eventApproval.startDate).toLocaleDateString()} to ${new Date(eventApproval.endDate).toLocaleDateString()}
+ - Venue: ${eventApproval.eventVenue}
+ - Organizer: ${eventApproval.nameOfTheOrganizer}
+
+ Your event is now ready to proceed. Please ensure all arrangements are made as per the approved proposal.
+
+ Best regards,
+ Event Approval Committee`
+ );
+ console.log(`Final approval notification sent to organizer: ${eventApproval.email}`);
+ } catch (emailError) {
+ console.error(`Failed to send final approval email to organizer:`, emailError.message);
+ }
+ }
+}
+ await eventApproval.save();
+
+ console.log("Application updated successfully:", { applicationId, status }); // Debug log
+ res.status(200).json({ message: `Application ${status} successfully.` });
+ } catch (error) {
+ console.error("Error updating application status:", error); // Log full error
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// Raise a query for an event application
+export const raiseQuery = async (req, res) => {
+ const { applicationId, role, queryText } = req.body;
+
+ try {
+ if (!applicationId || !role || !queryText) {
+ return res.status(400).json({ message: "Application ID, role, and query text are required." });
+ }
+
+ const eventApproval = await EventApproval.findById(applicationId);
+ if (!eventApproval) {
+ return res.status(404).json({ message: "Event approval not found." });
+ }
+
+ // Check if the role can raise queries (not club-secretary)
+ if (role === "club-secretary") {
+ return res.status(403).json({ message: "Club secretary cannot raise queries." });
+ }
+
+ // Check if there's a pending approval for this role
+ const approvalIndex = eventApproval.approvals.findIndex(
+ (app) => app.role === role && app.status === "Pending"
+ );
+
+ if (approvalIndex === -1) {
+ return res.status(400).json({ message: "No pending approval found for this role." });
+ }
+
+ // Update the approval status to "Query"
+ eventApproval.approvals[approvalIndex].status = "Query";
+ eventApproval.approvals[approvalIndex].comment = `Query raised: ${queryText}`;
+
+ // Add the query to the queries array
+ const newQuery = {
+ askerRole: role,
+ queryText,
+ responderEmail: eventApproval.email,
+ status: "Pending",
+ raisedAt: new Date(),
+ };
+
+ eventApproval.queries.push(newQuery);
+ await eventApproval.save();
+
+ // Send email notification to the organizer
+ try {
+ await sendEmail(
+ eventApproval.email,
+ `Query Raised for Event: ${eventApproval.eventName}`,
+ `A query has been raised for your event "${eventApproval.eventName}" by ${role}.
+
+Query: ${queryText}
+
+Please log into the application to respond to this query.
+
+Event Details:
+- Event Name: ${eventApproval.eventName}
+- Event Type: ${eventApproval.eventType}
+- Date: ${new Date(eventApproval.startDate).toLocaleDateString()} to ${new Date(eventApproval.endDate).toLocaleDateString()}
+
+Please respond at your earliest convenience.
+
+Best regards,
+Event Approval Committee`
+ );
+ console.log(`Query notification email sent to organizer: ${eventApproval.email}`);
+ } catch (emailError) {
+ console.error(`Failed to send query notification email to organizer:`, emailError.message);
+ }
+
+ res.status(200).json({ message: "Query raised successfully.", query: newQuery });
+ } catch (error) {
+ console.error("Error raising query:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// Get all queries for an event
+export const getEventQueries = async (req, res) => {
+ const { eventId } = req.params;
+
+ try {
+ const eventApproval = await EventApproval.findById(eventId, 'queries');
+ if (!eventApproval) {
+ return res.status(404).json({ message: "Event not found." });
+ }
+
+ res.status(200).json({ queries: eventApproval.queries });
+ } catch (error) {
+ console.error("Error fetching queries:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// Reply to a query (only for club-secretary or organizer)
+export const replyToQuery = async (req, res) => {
+ const { eventId, queryId, response, userRole, userEmail } = req.body;
+
+ try {
+ if (!eventId || !queryId || !response) {
+ return res.status(400).json({ message: "Event ID, query ID, and response are required." });
+ }
+
+ const eventApproval = await EventApproval.findById(eventId);
+ if (!eventApproval) {
+ return res.status(404).json({ message: "Event not found." });
+ }
+
+ // Find the query
+ const queryIndex = eventApproval.queries.findIndex(
+ (query) => query.queryId.toString() === queryId && query.status === "Pending"
+ );
+
+ if (queryIndex === -1) {
+ return res.status(404).json({ message: "Query not found or already answered." });
+ }
+
+ const query = eventApproval.queries[queryIndex];
+
+ // Check if the user is authorized to reply (only club-secretary)
+ if (userRole !== "club-secretary") {
+ return res.status(403).json({ message: "Only club-secretary can reply to queries." });
+ }
+
+ // Update the query with response
+ eventApproval.queries[queryIndex].response = response;
+ eventApproval.queries[queryIndex].status = "Answered";
+ eventApproval.queries[queryIndex].answeredAt = new Date();
+
+ // Reset the approval status back to Pending for the role that raised the query
+ const approvalIndex = eventApproval.approvals.findIndex(
+ (approval) => approval.role === query.askerRole
+ );
+
+ if (approvalIndex !== -1) {
+ eventApproval.approvals[approvalIndex].status = "Pending";
+ eventApproval.approvals[approvalIndex].comment = "";
+ }
+
+ await eventApproval.save();
+
+ // Send email notification to the role that raised the query
+ const roleEmail = getEmailForRole(query.askerRole);
+ if (roleEmail) {
+ try {
+ await sendEmail(
+ roleEmail,
+ `Query Response Received: ${eventApproval.eventName}`,
+ `Your query for event "${eventApproval.eventName}" has been responded to.
+
+Original Query: ${query.queryText}
+Response: ${response}
+
+You can now review the event application again and take appropriate action.
+
+Best regards,
+Event Approval Committee`
+ );
+ console.log(`Query response notification sent to ${query.askerRole} at ${roleEmail}`);
+ } catch (emailError) {
+ console.error(`Failed to send query response notification to ${query.askerRole}:`, emailError.message);
+ }
+ } else {
+ console.error(`No email found for role: ${query.askerRole}`);
+ }
+
+ res.status(200).json({ message: "Query response submitted successfully." });
+ } catch (error) {
+ console.error("Error replying to query:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// Get all unique semesters and academic years for filtering
+export const getSemesterOptions = async (req, res) => {
+ try {
+ const { role, category } = req.query;
+
+ let matchQuery = {};
+
+ // Add role-based filtering if needed
+ if (role && role !== 'club-secretary') {
+ matchQuery[`approvals.role`] = role;
+ }
+
+ // Add category filtering for general-secretary
+ if (role === 'general-secretary' && category) {
+ matchQuery.eventType = category;
+ }
+
+ const semesterOptions = await EventApproval.aggregate([
+ { $match: matchQuery },
+ {
+ $group: {
+ _id: {
+ semester: "$semester",
+ academicYear: "$academicYear"
+ }
+ }
+ },
+ {
+ $sort: { "_id.academicYear": -1, "_id.semester": 1 }
+ }
+ ]);
+
+ const formattedOptions = semesterOptions.map(option => ({
+ semester: option._id.semester,
+ academicYear: option._id.academicYear,
+ display: option._id.semester || `${option._id.academicYear} Academic Year`
+ }));
+
+ res.status(200).json(formattedOptions);
+ } catch (error) {
+ console.error("Error fetching semester options:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// Enhanced function to get approved applications with semester filtering and search
+export const getApprovedApplicationsWithFilters = async (req, res) => {
+ const { role, category, semester, academicYear, search, page = 1, limit = 10 } = req.body;
+
+ try {
+ if (!role) {
+ return res.status(400).json({ message: "Role is required." });
+ }
+
+ // Base query for approved applications
+ let query = {
+ "approvals": {
+ $elemMatch: {
+ role: role,
+ status: "Approved"
+ }
+ }
+ };
+
+ // Add semester filtering
+ if (semester) {
+ query.semester = semester;
+ }
+
+ // Add academic year filtering
+ if (academicYear) {
+ query.academicYear = academicYear;
+ }
+
+ // Add category filtering for general-secretary
+ if (role === "general-secretary" && category) {
+ query.eventType = category;
+ }
+
+ // Add search functionality
+ if (search && search.trim()) {
+ const searchRegex = new RegExp(search.trim(), 'i');
+ query.$or = [
+ { eventName: searchRegex },
+ { clubName: searchRegex },
+ { nameOfTheOrganizer: searchRegex },
+ { eventVenue: searchRegex },
+ { eventDescription: searchRegex }
+ ];
+ }
+
+ // Filter out past events
+ const currentDate = new Date();
+ query.endDate = { $gte: currentDate };
+
+ // Calculate pagination
+ const skip = (page - 1) * limit;
+
+ // Execute query with pagination
+ const approvedApplications = await EventApproval.find(query)
+ .sort({ startDate: -1 }) // Sort by start date, newest first
+ .skip(skip)
+ .limit(parseInt(limit));
+
+ // Get total count for pagination
+ const totalCount = await EventApproval.countDocuments(query);
+
+ // Group by semester for better organization
+ const groupedBySemester = approvedApplications.reduce((groups, app) => {
+ const semesterKey = app.semester || `${app.academicYear} Academic Year`;
+ if (!groups[semesterKey]) {
+ groups[semesterKey] = [];
+ }
+ groups[semesterKey].push(app);
+ return groups;
+ }, {});
+
+ res.status(200).json({
+ applications: approvedApplications,
+ groupedBySemester,
+ pagination: {
+ currentPage: parseInt(page),
+ totalPages: Math.ceil(totalCount / limit),
+ totalCount,
+ hasNext: skip + approvedApplications.length < totalCount,
+ hasPrev: page > 1
+ }
+ });
+ } catch (error) {
+ console.error("Error fetching approved applications with filters:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+// Enhanced function to get pending applications with semester filtering and search
+export const getPendingApprovalsWithFilters = async (req, res) => {
+ const { role, category, semester, academicYear, search, page = 1, limit = 10 } = req.body;
+
+ try {
+ if (!role) {
+ return res.status(400).json({ message: "Role is required." });
+ }
+
+ const roleIndex = roleHierarchy.indexOf(role);
+ if (roleIndex === -1) {
+ return res.status(400).json({ message: "Invalid role." });
+ }
+
+ // Base query for pending applications
+ let query = {
+ "approvals.role": role,
+ };
+
+ // Add semester filtering
+ if (semester) {
+ query.semester = semester;
+ }
+
+ // Add academic year filtering
+ if (academicYear) {
+ query.academicYear = academicYear;
+ }
+
+ // Add category filtering for general-secretary
+ if (role === "general-secretary" && category) {
+ query.eventType = category;
+ }
+
+ // Add search functionality
+ if (search && search.trim()) {
+ const searchRegex = new RegExp(search.trim(), 'i');
+ query.$or = [
+ { eventName: searchRegex },
+ { clubName: searchRegex },
+ { nameOfTheOrganizer: searchRegex },
+ { eventVenue: searchRegex },
+ { eventDescription: searchRegex }
+ ];
+ }
+
+ // Find all applications matching the base criteria
+ let pendingApprovals = await EventApproval.find(query);
+
+ if (pendingApprovals.length === 0) {
+ return res.status(200).json({
+ applications: [],
+ groupedBySemester: {},
+ pagination: {
+ currentPage: 1,
+ totalPages: 0,
+ totalCount: 0,
+ hasNext: false,
+ hasPrev: false
+ }
+ });
+ }
+
+ // Filter for pending or query status
+ pendingApprovals = pendingApprovals.filter((approval) => {
+ const approvalStatus = approval.approvals.find(
+ (app) => app.role === role
+ );
+ return approvalStatus && (approvalStatus.status === "Pending" || approvalStatus.status === "Query");
+ });
+
+ // Ensure previous roles in the hierarchy are approved
+ pendingApprovals = pendingApprovals.filter((approval) => {
+ return roleHierarchy.slice(0, roleIndex).every((prevRole) => {
+ const prevApproval = approval.approvals.find((app) => app.role === prevRole);
+ return prevApproval && prevApproval.status === "Approved";
+ });
+ });
+
+ // Apply pagination
+ const totalCount = pendingApprovals.length;
+ const skip = (page - 1) * limit;
+ const paginatedApprovals = pendingApprovals
+ .sort((a, b) => new Date(a.startDate) - new Date(b.startDate))
+ .slice(skip, skip + parseInt(limit));
+
+ // Group by semester
+ const groupedBySemester = paginatedApprovals.reduce((groups, app) => {
+ const semesterKey = app.semester || `${app.academicYear} Academic Year`;
+ if (!groups[semesterKey]) {
+ groups[semesterKey] = [];
+ }
+ groups[semesterKey].push(app);
+ return groups;
+ }, {});
+
+ res.status(200).json({
+ applications: paginatedApprovals,
+ groupedBySemester,
+ pagination: {
+ currentPage: parseInt(page),
+ totalPages: Math.ceil(totalCount / limit),
+ totalCount,
+ hasNext: skip + paginatedApprovals.length < totalCount,
+ hasPrev: page > 1
+ }
+ });
+ } catch (error) {
+ console.error("Error fetching pending approvals with filters:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+
+
+// Edit all event details (only allowed by club-secretary and only if approvals are still pending at general-secretary)
+export const editEventDetails = async (req, res) => {
+ const { eventId, userID, updates } = req.body;
+
+ try {
+ // Find the event
+ const event = await EventApproval.findById(eventId);
+ if (!event) {
+ return res.status(404).json({ message: "Event not found." });
+ }
+
+ const user = await User.findById(userID);
+ if (!user || user.role !== "club-secretary") {
+ return res.status(403).json({ message: "Only club-secretary can edit event details." });
+ }
+
+ if (event.userID.toString() !== userID.toString()) {
+ return res.status(403).json({ message: "You are not authorized to edit this event." });
+ }
+
+
+ // List of fields that can be updated
+ const editableFields = [
+ "eventName", "partOfGymkhanaCalendar", "eventType", "clubName", "startDate", "endDate",
+ "eventVenue", "sourceOfBudget", "estimatedBudget", "nameOfTheOrganizer", "designation",
+ "email", "phoneNumber", "requirements", "anyAdditionalAmenities", "eventDescription",
+ "internalParticipants", "externalParticipants", "listOfCollaboratingOrganizations"
+ ];
+
+ // Update only allowed fields
+ editableFields.forEach(field => {
+ if (updates[field] !== undefined) {
+ event[field] = updates[field];
+ }
+ });
+
+ // If startDate changed, update semester/academicYear
+ if (updates.startDate) {
+ const semesterInfo = getSemesterInfo(updates.startDate);
+ event.semester = semesterInfo.semester;
+ event.academicYear = semesterInfo.academicYear;
+ }
+
+ // Reset approvals after club-secretary to Pending
+ event.approvals = event.approvals.map(a => {
+ if (a.role !== "club-secretary") {
+ return { ...a, status: "Edited"};
+ }
+ return a;
+ });
+
+ await event.save();
+
+ res.status(200).json({ message: "Event details updated and approval pipeline reset.", event });
+ } catch (error) {
+ console.error("Error editing event details:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
+
+export const closeEvent = async (req, res) => {
+ const { eventId, userID, closerName } = req.body;
+
+ try {
+ // Find the user and check role
+ const user = await User.findById(userID);
+ if (!user || !["ARSW", "associate-dean", "dean"].includes(user.role)) {
+ return res.status(403).json({ message: "Only ARSW, associate-dean or dean can close events." });
+ }
+
+ // Find the event
+ const event = await EventApproval.findById(eventId);
+ if (!event) {
+ return res.status(404).json({ message: "Event not found." });
+ }
+
+ // Set status to Closed and record who closed it
+ event.status = "Closed";
+ event.closedBy = closerName || user.name || "Unknown";
+
+ await event.save();
+
+ res.status(200).json({ message: "Event closed successfully.", event });
+ } catch (error) {
+ console.error("Error closing event:", error);
+ res.status(500).json({ message: "Internal server error." });
+ }
+};
\ No newline at end of file
diff --git a/backend/controller/leave.controller.js b/backend/controller/leave.controller.js
deleted file mode 100644
index db492b3..0000000
--- a/backend/controller/leave.controller.js
+++ /dev/null
@@ -1,225 +0,0 @@
-import LeaveApplication from "../models/leave.model.js";
-import User from "../models/user.model.js";
-import nodemailer from "nodemailer";
-import dotenv from "dotenv";
-
-dotenv.config();
-
-// Configure nodemailer
-const transporter = nodemailer.createTransport({
- service: 'gmail',
- auth: {
- user: process.env.EMAIL_USER,
- pass: process.env.EMAIL_PASS
- }
-});
-
-
-const sendEmail = (to, subject, text) => {
- const mailOptions = {
- from: process.env.EMAIL_USER,
- to,
- subject,
- text
- };
-
- console.log('Attempting to send email to:', to);
-
- transporter.sendMail(mailOptions, (error, info) => {
- if (error) {
- console.error('Error sending email:', error);
- } else {
- console.log('Email sent:', info.response);
- }
- });
-};
-
-
-// Apply for Leave
-export const applyForLeave = async (req, res) => {
- try {
- const { placeOfVisit, reason, dateOfLeaving, arrivalDate, emergencyContact } = req.body;
- const userID = req.body.userID; // Ensure you get this from local storage
-
- // Fetch user details to check if required fields are filled
- const user = await User.findById(userID);
-
- // Check if required user details are filled
- if (!user.phnumber || !user.roomNumber || !user.year || !user.course || !user.hostel) {
- return res.status(400).json({ message: "Please complete your profile with phone number, room number, year, and course before applying for leave." });
- }
-
- // Check for pending leave applications for the user
- const existingApplication = await LeaveApplication.findOne({
- userID,
- status: 'Pending'
- });
-
- if (existingApplication) {
- return res.status(400).json({ message: "You already have a pending leave application." });
- }
-
- // If no pending leave application, proceed to create a new leave application
- const newApplication = new LeaveApplication({
- userID,
- placeOfVisit,
- reason,
- dateOfLeaving,
- arrivalDate,
- emergencyContact
- });
-
- await User.findByIdAndUpdate(userID, { leaveApplication: newApplication._id });
-
- await newApplication.save();
- res.status(201).json({
- message: "Leave application submitted successfully.",
- application: newApplication
- });
- } catch (error) {
- console.log("error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
-
-// Get Leave Status for a User
-export const getLeaveStatus = async (req, res) => {
- try {
- const { userID } = req.body; // Ensure you're getting userID correctly
-
- // Use findOne to get only one leave application for the user
- const leaveApplication = await LeaveApplication.findOne({ userID });
-
- if (!leaveApplication) {
- return res.status(404).json({ message: "No leave applications found" });
- }
-
- res.status(200).json(leaveApplication); // Send the single leave application as a JSON response
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
-
-
-
-// Warden approval
-export const updateLeaveStatus = async (req, res) => {
- try {
- const { applicationId } = req.params; // Get applicationId from request parameters takes leave id
- const { status } = req.body; // Get status from request body
-
- // Validate the status
- if (!['Pending', 'Approved', 'Rejected'].includes(status)) {
- return res.status(400).json({ message: "Invalid status. Must be either 'Pending', 'Approved', or 'Rejected'." });
- }
-
- // Find the leave application and update the status
- const updatedApplication = await LeaveApplication.findByIdAndUpdate(
- applicationId,
- { status },
- { new: true } // Return the updated document
- );
-
- if (!updatedApplication) {
- return res.status(404).json({ message: "Leave application not found" });
- }
-
- // If status is approved, send email to the user
- if (status === 'Approved') {
- const user = await User.findById(updatedApplication.userID);
- const subject = "Your Leave Application has been Approved";
- const text = `Dear ${user.name},\n\nYour leave application for ${updatedApplication.placeOfVisit} has been approved.\n\nBest regards,\nYour College`;
- await sendEmail(user.email, subject, text);
- }
-
- res.status(200).json({
- message: "Leave application status updated successfully.",
- application: updatedApplication
- });
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
-
-// Leave extension
-export const updateLeaveExtension = async (req, res) => {
- try {
- const { applicationId } = req.params;
- const { newArrivalDate } = req.body;
-
- const leaveApplication = await LeaveApplication.findById(applicationId);
-
- if (!leaveApplication) {
- return res.status(404).json({ message: "Leave application not found" });
- }
-
- // Update the arrival date and mark the status as 'Extension'
- leaveApplication.arrivalDate = newArrivalDate;
- leaveApplication.status = 'Extension';
-
- await leaveApplication.save();
-
- res.status(200).json({
- message: "Leave extension requested successfully.",
- application: leaveApplication
- });
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
-
-// All leave applications for warden
-export const getAllLeaveApplications = async (req, res) => {
- try {
- const applications = await LeaveApplication.find().populate("userID", "name rollNumber email");
- res.status(200).json(applications);
- } catch (error) {
- console.error("Error fetching leave applications:", error);
- res.status(500).json({ message: "Server error" });
- }
-};
-
-// Scan leave application
-export const scanLeaveApplication = async (req, res) => {
- try {
- const { applicationId } = req.params; // Get applicationId from request parameters
- const leaveApplication = await LeaveApplication.findById(applicationId);
-
- if (!leaveApplication) {
- return res.status(404).json({ message: "Leave application not found" });
- }
-
- // Update the scanned field with the current date and time
- leaveApplication.scanned = new Date();
- await leaveApplication.save();
-
- res.status(200).json({
- message: "Leave application scanned successfully.",
- application: leaveApplication
- });
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
-
-export const deleteLeaveApplication = async (req, res) => {
- try {
- const { id } = req.params; // Get applicationId from request parameters
- const leaveApplication = await LeaveApplication.findByIdAndDelete(id);
-
- if (!leaveApplication) {
- return res.status(404).json({ message: "Leave application not found" });
- }
-
- res.status(200).json({
- message: "Leave application deleted successfully.",
- });
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
\ No newline at end of file
diff --git a/backend/controller/outing.controller.js b/backend/controller/outing.controller.js
deleted file mode 100644
index 292524e..0000000
--- a/backend/controller/outing.controller.js
+++ /dev/null
@@ -1,123 +0,0 @@
-import OutingRequest from "../models/outing.model.js";
-import User from "../models/user.model.js";
-
-// Apply for Outing
-export const applyForOuting = async (req, res) => {
- try {
- const { placeOfVisit, reason, emergencyContact } = req.body;
- const userID = req.body.userID; // will be fetched from local storage on frontend
-
- // Check if the user already has an approved outing request
- const existingApplication = await OutingRequest.findOne({
- userID,
- status: 'Approved'
- });
-
- if (existingApplication) {
- return res.status(400).json({ message: "You already have an existing outing application." });
- }
-
- // If no existing approved application, create a new outing request
- const newApplication = new OutingRequest({
- userID,
- placeOfVisit,
- reason,
- outTime: new Date(), // Set outTime to the current date and time
- inTime: "", // You can also set a default value for inTime if needed
- emergencyContact
- });
-
- // Save the outing request ID to the user's document
- await User.findByIdAndUpdate(userID, { outingRequest: newApplication._id });
-
- await newApplication.save();
- res.status(201).json({
- message: "Outing application submitted successfully.",
- application: newApplication
- });
- } catch (error) {
- console.log("error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
-
-// Get Outing Status
-export const getOutingStatus = async (req, res) => {
- try {
- const { userID } = req.body; // Ensure you're getting userID correctly
-
- // Use findOne to get only one outing request for the user
- const outingRequest = await OutingRequest.findOne({ userID })
-
- if (!outingRequest) {
- return res.status(404).json({ message: "No outing application found." });
- }
-
- // Return the single outing request
- res.status(200).json({
- outingRequest
- });
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error." });
- }
-};
-
-
-export const getAllOutings = async (req, res) => {
- try {
- // Fetch all outing requests from the database
- const allOutings = await OutingRequest.find();
-
- if (allOutings.length === 0) {
- return res.status(404).json({ message: "No outing applications found." });
- }
-
- // Return the list of all outing requests
- res.status(200).json(allOutings);
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error." });
- }
-};
-
-export const scanOutingApplication = async (req, res) => {
- try {
- const { applicationId } = req.params; // Get applicationId from request parameters
- const outingApplication = await OutingRequest.findById(applicationId);
-
- if (!outingApplication) {
- return res.status(404).json({ message: "Outing application not found" });
- }
-
- // Update the scanned field with the current date and time
- outingApplication.scanned = new Date();
- await outingApplication.save();
-
- res.status(200).json({
- message: "Outing application scanned successfully.",
- application: outingApplication
- });
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
-
-export const deleteOutingRequest = async (req, res) => {
- try {
- const { applicationId } = req.params; // Get applicationId from request parameters
- const outingRequest = await OutingRequest.findByIdAndDelete(applicationId);
-
- if (!outingRequest) {
- return res.status(404).json({ message: "outing request not found" });
- }
-
- res.status(200).json({
- message: "outing request deleted successfully.",
- });
- } catch (error) {
- console.log("Error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
-};
\ No newline at end of file
diff --git a/backend/controller/user.controller.js b/backend/controller/user.controller.js
index fe5553f..1262ce5 100644
--- a/backend/controller/user.controller.js
+++ b/backend/controller/user.controller.js
@@ -1,93 +1,130 @@
import User from "../models/user.model.js";
import bcryptjs from 'bcryptjs';
import jwt from "jsonwebtoken";
+import { oauth2Client } from "../googleClient.js";
+import axios from "axios";
-export const signup = async (req, res) => {
- try {
- const { email, password, rollNumber } = req.body;
+// export const signup = async (req, res) => {
+// try {
+// const { email, password, category } = req.body;
- // Check if the user already exists
- const existingUser = await User.findOne({ email });
- if (existingUser) {
- return res.status(400).json({ message: "User already exists" });
- }
+// // Check if the user already exists
+// const existingUser = await User.findOne({ email });
+// if (existingUser) {
+// return res.status(400).json({ message: "User already exists" });
+// }
+
+// // Hash the password and create a new user
+// const hashPassword = await bcryptjs.hash(password, 8);
+// const newUser = new User({
+// email,
+// password: hashPassword,
+// name: "",
+// category,
+// eventApproval: "",
+// phnumber: "",
+// });
+
+// await newUser.save();
+// const token = jwt.sign(
+// { userID: newUser._id, role: newUser.role },
+// process.env.JWT_SECRET,
+// { expiresIn: "1h" } // Set your preferred token expiry time
+// );
+// res.status(201).json({
+// message: "User created successfully",
+// token,
+// user: { _id: newUser._id, name: newUser.name, email: newUser.email, role: newUser.role, category: newUser.category },
+// });
+
+// } catch (error) {
+// console.log("error:", error.message);
+// res.status(500).json({ message: "Internal server error" });
+// }
+// };
+
+// //login function
+
+// export const login = async (req, res) => {
+// try {
+// const { email, password } = req.body;
+
+// const user = await User.findOne({ email });
+// if (!user) {
+// return res.status(400).json({ message: "User not found" });
+// }
+
+// const isMatch = await bcryptjs.compare(password, user.password);
+// if (!isMatch) {
+// return res.status(400).json({ message: "Invalid credentials" });
+// }
+
+// // Create a JWT token
+// const token = jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET, {
+// expiresIn: '1h',
+// });
+
+// res.status(200).json({
+// message: "Login successful",
+// token,
+// user: { _id: user._id, name: user.name, email: user.email, role: user.role },
+// });
+// } catch (error) {
+// console.log("error:", error.message);
+// res.status(500).json({ message: "Internal server error" });
+// }
+// };
+
+//Google login function
- // Hash the password and create a new user
- const hashPassword = await bcryptjs.hash(password, 8);
- const newUser = new User({
- email,
- password: hashPassword,
- name: "",
- rollNumber,
- leaveApplication: "",
- outingRequest: "",
- roomNumber:"",
- branch:"",
- year: "",
- course: ""
+export const googleLogin = async (req, res) => {
+ const { token } = req.body; // JWT sent from the frontend
+
+ try {
+ // Verify the JWT
+ const ticket = await oauth2Client.verifyIdToken({
+ idToken: token,
+ audience: process.env.GOOGLE_CLIENT_ID, // Replace with your client ID
});
- await newUser.save();
- const token = jwt.sign(
- { userID: newUser._id, role: newUser.role },
+ const payload = ticket.getPayload();
+ const { email, name, picture } = payload;
+
+ // Find or create a user in the database
+ let user = await User.findOne({ email });
+ if (!user) {
+ return res.status(404).json({ message: "User not found" });
+ }
+
+ // Generate a JWT token for your application
+ const appToken = jwt.sign(
+ { userID: user._id, role: user.role },
process.env.JWT_SECRET,
- { expiresIn: "1h" } // Set your preferred token expiry time
+ { expiresIn: "1h" }
);
- res.status(201).json({
- message: "User created successfully",
- token,
- user: { _id: newUser._id, name: newUser.name, email: newUser.email, role: newUser.role },
+
+ res.status(200).json({
+ message: "success",
+ token: appToken,
+ user,
});
-
} catch (error) {
- console.log("error:", error.message);
- res.status(500).json({ message: "Internal server error" });
+ console.error("Google Login Error:", error);
+ res.status(500).json({ message: "Google Login failed" });
}
};
-//login function
-
-export const login = async (req, res) => {
- try {
- const { email, password } = req.body;
-
- const user = await User.findOne({ email });
- if (!user) {
- return res.status(400).json({ message: "User not found" });
- }
-
- const isMatch = await bcryptjs.compare(password, user.password);
- if (!isMatch) {
- return res.status(400).json({ message: "Invalid credentials" });
- }
-
- // Create a JWT token
- const token = jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET, {
- expiresIn: '1h',
- });
-
- res.status(200).json({
- message: "Login successful",
- token,
- user: { _id: user._id, name: user.name, email: user.email, role: user.role },
- });
- } catch (error) {
- console.log("error:", error.message);
- res.status(500).json({ message: "Internal server error" });
- }
- };
-
export const getUserDetails = async (req, res) => {
try {
- const { userId, rollNumber } = req.body; // Destructure both userId and rollNumber from request body
+ const { userId, email } = req.body; // Destructure both userId and rollNumber from request body
let user;
// If userId is provided, find by userId; otherwise, find by rollNumber
if (userId) {
- user = await User.findById(userId, "leaveApplication outingRequest name rollNumber email phnumber hostel roomNumber course branch year");
- } else if (rollNumber) {
- user = await User.findOne({ rollNumber }, "name rollNumber email"); // Find by rollNumber
+ user = await User.findById(userId, "eventApproval name email phnumber category");
+ } else if (email) {
+ user = await User.findOne({ email }, "name eventApproval phnumber category");
}
// Check if user was found
@@ -108,7 +145,7 @@ export const login = async (req, res) => {
const { userId, ...updates } = req.body; // Destructure userId and the rest as updates
// Ensure only permitted fields can be updated
- const allowedFields = ["name", "roomNumber", "branch", "year", "course", "hostel", "phnumber"];
+ const allowedFields = ["name", "category", "phnumber"];
// Retrieve the existing user data
const user = await User.findById(userId);
diff --git a/backend/googleClient.js b/backend/googleClient.js
new file mode 100644
index 0000000..2ee6bcb
--- /dev/null
+++ b/backend/googleClient.js
@@ -0,0 +1,13 @@
+import { google } from 'googleapis'
+import dotenv from "dotenv"
+
+dotenv.config();
+
+const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID;
+const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET;
+
+export const oauth2Client = new google.auth.OAuth2(
+ GOOGLE_CLIENT_ID,
+ GOOGLE_CLIENT_SECRET,
+ 'postmessage'
+);
\ No newline at end of file
diff --git a/backend/index.js b/backend/index.js
index ebf2059..66fb856 100644
--- a/backend/index.js
+++ b/backend/index.js
@@ -4,8 +4,8 @@ import mongoose from "mongoose"
import cors from "cors"
import userRoute from "./route/user.route.js"
-import leaveRoute from "./route/leave.route.js"
-import outRoute from "./route/outing.route.js"
+import eventRoute from "./route/event.route.js"
+
const app = express()
@@ -17,18 +17,15 @@ app.use(express.json());
const PORT= process.env.PORT || 4000;
const URI = process.env.MongoDBURI;
-mongoose.connect(URI, {
- useNewUrlParser: true,
- useUnifiedTopology: true
-}).then(() => {
+mongoose.connect(URI).then(() => {
console.log("Connected to MongoDB");
}).catch((error) => {
console.log("error:", error);
});
-app.use("/user", userRoute);
-app.use("/leave", leaveRoute);
-app.use("/out", outRoute);
+ app.use("/user", userRoute);
+ app.use("/event", eventRoute);
+
diff --git a/backend/models/event.model.js b/backend/models/event.model.js
new file mode 100644
index 0000000..e000cc7
--- /dev/null
+++ b/backend/models/event.model.js
@@ -0,0 +1,93 @@
+import mongoose from "mongoose";
+
+const Schema = mongoose.Schema;
+
+const eventApprovalSchema = new Schema(
+ {
+ userID: { type: String, required: true },
+ eventName: { type: String, required: true },
+ partOfGymkhanaCalendar: { type: String, required: true },
+ eventType: { type: String }, // Optional field for tracking event type
+ clubName: { type: String, required: true },
+ startDate: { type: Date, required: true },
+ endDate: { type: Date, required: true },
+ semester: { type: String, required: false }, // Semester field (e.g., "Fall 2024", "Spring 2025")
+ academicYear: { type: String, required: false }, // Academic year (e.g., "2024-2025")
+ eventVenue: { type: String, required: true },
+ sourceOfBudget: { type: String, required: true },
+ estimatedBudget: { type: Number, required: true },
+ nameOfTheOrganizer: { type: String, required: true },
+ designation: { type: String, required: true },
+ email: { type: String, required: true },
+ phoneNumber: { type: String, required: true },
+ requirements: { type: [String], required: false },
+ anyAdditionalAmenities: { type: String },
+ eventDescription: { type: String, required: true },
+ internalParticipants: { type: Number, required: true },
+ externalParticipants: { type: Number, required: true },
+ listOfCollaboratingOrganizations: { type: String, default: "N/A" },
+ approvals: [
+ {
+ role: {
+ type: String,
+ enum: [
+ "club-secretary",
+ "general-secretary",
+ "treasurer",
+ "president",
+ "faculty-in-charge",
+ "associate-dean",
+ ],
+ required: true,
+ },
+ status: {
+ type: String,
+ enum: [
+ "Pending",
+ "Approved",
+ "Rejected",
+ "Query",
+ "Edited",
+ "Closed",
+ ],
+ default: "Pending",
+ },
+ comment: { type: String, required: false }, // Optional comment for feedback
+ },
+ ],
+ queries: [
+ {
+ queryId: {
+ type: mongoose.Schema.Types.ObjectId,
+ default: () => new mongoose.Types.ObjectId(),
+ },
+ askerRole: {
+ type: String,
+ enum: [
+ "general-secretary",
+ "treasurer",
+ "president",
+ "faculty-in-charge",
+ "associate-dean",
+ ],
+ required: true,
+ },
+ queryText: { type: String, required: true },
+ responderEmail: { type: String, required: true }, // Email of the organizer who should respond
+ response: { type: String, required: false },
+ status: {
+ type: String,
+ enum: ["Pending", "Answered"],
+ default: "Pending",
+ },
+ raisedAt: { type: Date, default: Date.now },
+ answeredAt: { type: Date, required: false },
+ },
+ ],
+ closedBy: { type: String, required: false }, // Name of the person who closed the event
+ },
+ { timestamps: true }
+);
+
+const EventApproval = mongoose.model("EventApproval", eventApprovalSchema);
+export default EventApproval;
diff --git a/backend/models/leave.model.js b/backend/models/leave.model.js
deleted file mode 100644
index c415606..0000000
--- a/backend/models/leave.model.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import mongoose from "mongoose";
-
-const Schema = mongoose.Schema;
-
-const leaveApplicationSchema = new Schema({
- userID: { type: String, required: true },
- placeOfVisit: { type: String, required: true },
- reason: { type: String, required: true },
- proofOfTravel: { type: String, required: false },
- dateOfLeaving: { type: Date, required: true },
- arrivalDate: { type: Date, required: true },
- emergencyContact: { type: String, required: true },
- status: { type: String, default: 'Pending', enum: ['Pending', 'Approved', 'Rejected', 'Extension'] }, // Default status
- scanned: { type: Date, default: null },
-}, {
-});
-
-const LeaveApplication = mongoose.model('LeaveApplication', leaveApplicationSchema);
-export default LeaveApplication;
diff --git a/backend/models/outing.model.js b/backend/models/outing.model.js
deleted file mode 100644
index f2b97ab..0000000
--- a/backend/models/outing.model.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import mongoose from "mongoose";
-
-const Schema = mongoose.Schema;
-
-const outingRequestSchema = new Schema({
- userID: { type: String, required: true },
- placeOfVisit: { type: String, required: true },
- reason: { type: String, required: true },
- outTime: { type: Date, required: false },
- inTime: { type: Date, required: false },
- emergencyContact: {type: String, required: true},
- status: { type: String, default: 'Approved'},
- scanned: { type: Date, default: null }
-},
-);
-
-const OutingRequest = mongoose.model('OutingRequest', outingRequestSchema);
-export default OutingRequest;
\ No newline at end of file
diff --git a/backend/models/user.model.js b/backend/models/user.model.js
index fc6fe5b..c0b0e12 100644
--- a/backend/models/user.model.js
+++ b/backend/models/user.model.js
@@ -16,18 +16,21 @@ const userSchema = new Schema({
message: 'Email must have the suffix "iitdh.ac.in"',
},
},
- password: {type: String, required: true},
+ password: {type: String, required: false},
name: { type: String, required: false },
- rollNumber: { type: String, required: false },
- role: {type: String, default: "student",enum: ["student", "warden","security"]},
- phnumber: {type:String, default: "", required:false},
- leaveApplication: {type: String, default: "",required: false},
- outingRequest: {type: String, default: "",required: false},
- hostel: {type: String, default: "", required:false},
- roomNumber: {type: String, required: false},
- branch: {type: String, required: false},
- year: {type: String, required: false},
- course: {type: String, required: false}
+ role: {type: String, default: "club-secretary",enum: ["club-secretary", "general-secretary", "treasurer", "vice-president", "ARSW", "associate-dean", "Dean-SW"]},
+ type: {
+ type: String,
+ enum: ["Technical", "Cultural", "Sports"],
+ required: function () {
+ return this.role === "club-secretary";
+ },
+ default: undefined
+ },
+ eventApproval: {type: String, default: "",required: false},
+ category: {type: String, default: "",required: false},
+ phnumber: {type: String, default: "", required:false},
+ image: {type: String, required: false},
},
);
diff --git a/backend/package-lock.json b/backend/package-lock.json
index 3965836..0b37cff 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -5,10 +5,12 @@
"packages": {
"": {
"dependencies": {
+ "axios": "^1.7.9",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.1",
+ "googleapis": "^144.0.0",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.7.3",
"nodemailer": "^6.9.16",
@@ -48,6 +50,14 @@
"node": ">= 0.6"
}
},
+ "node_modules/agent-base": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+ "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -65,16 +75,58 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
+ "node_modules/axios": {
+ "version": "1.7.9",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
+ "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/bcryptjs": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
"integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
},
+ "node_modules/bignumber.js": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
+ "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -130,9 +182,9 @@
}
},
"node_modules/bson": {
- "version": "6.9.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-6.9.0.tgz",
- "integrity": "sha512-X9hJeyeM0//Fus+0pc5dSUMhhrrmWwQUtdavaQeF3Ta6m69matZkGWV/MrBcnwUeLC8W9kwwc2hfkZgUuCX3Ig==",
+ "version": "6.10.1",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz",
+ "integrity": "sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==",
"engines": {
"node": ">=16.20.1"
}
@@ -191,6 +243,17 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -264,6 +327,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -346,9 +417,9 @@
}
},
"node_modules/express": {
- "version": "4.21.1",
- "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
- "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
+ "version": "4.21.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+ "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
@@ -369,7 +440,7 @@
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
- "path-to-regexp": "0.1.10",
+ "path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"range-parser": "~1.2.1",
@@ -384,8 +455,17 @@
},
"engines": {
"node": ">= 0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -414,6 +494,38 @@
"node": ">= 0.8"
}
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.9",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+ "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
+ "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -451,6 +563,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/gaxios": {
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
+ "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
+ "dependencies": {
+ "extend": "^3.0.2",
+ "https-proxy-agent": "^7.0.1",
+ "is-stream": "^2.0.0",
+ "node-fetch": "^2.6.9",
+ "uuid": "^9.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
@@ -480,6 +607,81 @@
"node": ">= 6"
}
},
+ "node_modules/google-auth-library": {
+ "version": "9.15.0",
+ "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.0.tgz",
+ "integrity": "sha512-7ccSEJFDFO7exFbO6NRyC+xH8/mZ1GZGG2xxx9iHxZWcjUjJpjWxIMw3cofAKcueZ6DATiukmmprD7yavQHOyQ==",
+ "dependencies": {
+ "base64-js": "^1.3.0",
+ "ecdsa-sig-formatter": "^1.0.11",
+ "gaxios": "^6.1.1",
+ "gcp-metadata": "^6.1.0",
+ "gtoken": "^7.0.0",
+ "jws": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/google-auth-library/node_modules/gcp-metadata": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz",
+ "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==",
+ "dependencies": {
+ "gaxios": "^6.0.0",
+ "json-bigint": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/google-auth-library/node_modules/jwa": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
+ "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/google-auth-library/node_modules/jws": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
+ "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
+ "dependencies": {
+ "jwa": "^2.0.0",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/googleapis": {
+ "version": "144.0.0",
+ "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-144.0.0.tgz",
+ "integrity": "sha512-ELcWOXtJxjPX4vsKMh+7V+jZvgPwYMlEhQFiu2sa9Qmt5veX8nwXPksOWGGN6Zk4xCiLygUyaz7xGtcMO+Onxw==",
+ "dependencies": {
+ "google-auth-library": "^9.0.0",
+ "googleapis-common": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/googleapis-common": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.2.0.tgz",
+ "integrity": "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA==",
+ "dependencies": {
+ "extend": "^3.0.2",
+ "gaxios": "^6.0.3",
+ "google-auth-library": "^9.7.0",
+ "qs": "^6.7.0",
+ "url-template": "^2.0.8",
+ "uuid": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
@@ -491,6 +693,37 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/gtoken": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
+ "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
+ "dependencies": {
+ "gaxios": "^6.0.0",
+ "jws": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/gtoken/node_modules/jwa": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
+ "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/gtoken/node_modules/jws": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
+ "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
+ "dependencies": {
+ "jwa": "^2.0.0",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@@ -558,6 +791,39 @@
"node": ">= 0.8"
}
},
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/debug": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -625,6 +891,25 @@
"node": ">=0.12.0"
}
},
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/json-bigint": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
+ "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
+ "dependencies": {
+ "bignumber.js": "^9.0.0"
+ }
+ },
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
@@ -784,12 +1069,12 @@
}
},
"node_modules/mongodb": {
- "version": "6.9.0",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz",
- "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==",
+ "version": "6.12.0",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.12.0.tgz",
+ "integrity": "sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==",
"dependencies": {
- "@mongodb-js/saslprep": "^1.1.5",
- "bson": "^6.7.0",
+ "@mongodb-js/saslprep": "^1.1.9",
+ "bson": "^6.10.1",
"mongodb-connection-string-url": "^3.0.0"
},
"engines": {
@@ -797,7 +1082,7 @@
},
"peerDependencies": {
"@aws-sdk/credential-providers": "^3.188.0",
- "@mongodb-js/zstd": "^1.1.0",
+ "@mongodb-js/zstd": "^1.1.0 || ^2.0.0",
"gcp-metadata": "^5.2.0",
"kerberos": "^2.0.1",
"mongodb-client-encryption": ">=6.0.0 <7",
@@ -838,13 +1123,13 @@
}
},
"node_modules/mongoose": {
- "version": "8.7.3",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.7.3.tgz",
- "integrity": "sha512-Xl6+dzU5ZpEcDoJ8/AyrIdAwTY099QwpolvV73PIytpK13XqwllLq/9XeVzzLEQgmyvwBVGVgjmMrKbuezxrIA==",
+ "version": "8.9.3",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.3.tgz",
+ "integrity": "sha512-G50GNPdMqhoiRAJ/24GYAzg13yxXDD3FOOFeYiFwtHmHpAJem3hxbYIxAhLJGWbYEiUZL0qFMu2LXYkgGAmo+Q==",
"dependencies": {
- "bson": "^6.7.0",
+ "bson": "^6.10.1",
"kareem": "2.6.3",
- "mongodb": "6.9.0",
+ "mongodb": "~6.12.0",
"mpath": "0.9.0",
"mquery": "5.0.0",
"ms": "2.1.3",
@@ -916,6 +1201,44 @@
"node": ">= 0.6"
}
},
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-fetch/node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "node_modules/node-fetch/node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/node-fetch/node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/nodemailer": {
"version": "6.9.16",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz",
@@ -1019,9 +1342,9 @@
}
},
"node_modules/path-to-regexp": {
- "version": "0.1.10",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
- "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -1046,6 +1369,11 @@
"node": ">= 0.10"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
@@ -1335,6 +1663,11 @@
"node": ">= 0.8"
}
},
+ "node_modules/url-template": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
+ "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
+ },
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -1343,6 +1676,18 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/uuid": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+ "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
diff --git a/backend/package.json b/backend/package.json
index db07454..b9995bf 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,9 +1,11 @@
{
"dependencies": {
+ "axios": "^1.7.9",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.1",
+ "googleapis": "^144.0.0",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.7.3",
"nodemailer": "^6.9.16",
diff --git a/backend/route/event.route.js b/backend/route/event.route.js
new file mode 100644
index 0000000..33c24ed
--- /dev/null
+++ b/backend/route/event.route.js
@@ -0,0 +1,68 @@
+import express from "express";
+import {
+ applyForEventApproval,
+ getUserEvents,
+ approveApplication,
+ getApprovedApplications,
+ editEventDetails,
+ getPendingApprovals,
+ getRejectedApplications,
+ getEventById,
+ handleApprovalStatus, // Import the updated controller
+ raiseQuery,
+ getEventQueries,
+ replyToQuery,
+ getSemesterOptions,
+ getApprovedApplicationsWithFilters,
+ closeEvent,
+ getPendingApprovalsWithFilters,
+} from "../controller/event.controller.js";
+
+const router = express.Router();
+
+// Apply for event approval (POST)
+router.post("/apply", applyForEventApproval);
+
+// Get all events for a user (POST)
+router.post("/user-events", getUserEvents);
+
+// Get all pending event applications (POST)
+router.post("/pending", getPendingApprovals);
+
+// Get all approved event applications (POST)
+router.post("/approved", getApprovedApplications);
+
+// Get all rejected event applications (POST)
+router.post("/rejected", getRejectedApplications);
+
+// Approve or reject an event application based on the status (PATCH)
+router.patch("/:applicationId/status", handleApprovalStatus);
+
+// Get event details by ID (GET)
+router.get("/:id", getEventById);
+
+// Raise a query for an event application (POST)
+router.post("/raise-query", raiseQuery);
+
+// Get all queries for an event (GET)
+router.get("/:eventId/queries", getEventQueries);
+
+// Reply to a query (POST)
+router.post("/reply-query", replyToQuery);
+
+//Close an event (PATCH)
+router.patch("/close", closeEvent);
+
+// Edit all event details (PATCH)
+router.patch("/edit", editEventDetails);
+
+// Get semester options for filtering (GET)
+router.get("/semesters/options", getSemesterOptions);
+
+// Get approved applications with filters and search (POST)
+router.post("/approved/filtered", getApprovedApplicationsWithFilters);
+
+// Get pending applications with filters and search (POST)
+router.post("/pending/filtered", getPendingApprovalsWithFilters);
+
+export default router;
\ No newline at end of file
diff --git a/backend/route/leave.route.js b/backend/route/leave.route.js
deleted file mode 100644
index f5083e1..0000000
--- a/backend/route/leave.route.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import express from "express";
-import { applyForLeave, getAllLeaveApplications, getLeaveStatus, updateLeaveExtension, updateLeaveStatus,scanLeaveApplication, deleteLeaveApplication } from '../controller/leave.controller.js'
-
-
-
-const router = express.Router();
-
-router.post("/apply", applyForLeave);
-router.post("/status",getLeaveStatus);
-router.put("/update/:applicationId", updateLeaveStatus);
-router.put("/extension/:applicationId", updateLeaveExtension);
-router.get("/all", getAllLeaveApplications);
-router.patch('/scan/:applicationId', scanLeaveApplication);
-router.delete('/delete/:id', deleteLeaveApplication);
-
-
-export default router;
diff --git a/backend/route/outing.route.js b/backend/route/outing.route.js
deleted file mode 100644
index 372135c..0000000
--- a/backend/route/outing.route.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// outing.routes.js
-
-import express from "express";
-import { applyForOuting, getOutingStatus, getAllOutings,scanOutingApplication, deleteOutingRequest } from "../controller/outing.controller.js";
-import { deleteModel } from "mongoose";
-
-const router = express.Router();
-
-// Route to apply for an outing
-router.post("/outapply", applyForOuting);
-
-// Route to get the status of outing applications for a specific user
-router.post('/status', getOutingStatus);
-
-// Route to get all outing applications
-router.get('/all', getAllOutings); // New route for getting all outings
-router.patch('/scan/:applicationId', scanOutingApplication);
-router.delete('/delete/:applicationId', deleteOutingRequest);
-export default router;
diff --git a/backend/route/user.route.js b/backend/route/user.route.js
index 5f12be6..d0c536b 100644
--- a/backend/route/user.route.js
+++ b/backend/route/user.route.js
@@ -1,11 +1,11 @@
import express from "express";
-import { editUserDetails, getUserDetails, login, signup } from "../controller/user.controller.js";
+import { editUserDetails, getUserDetails, googleLogin } from "../controller/user.controller.js";
+
const router = express.Router();
-router.post("/signup", signup);
-router.post("/login", login);
+router.post("/google-login", googleLogin);
router.post("/details", getUserDetails);
router.put("/edit", editUserDetails);
-
+router.get("/google", googleLogin)
export default router;
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..48eeadd
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,49 @@
+services:
+ backend:
+ build:
+ context: ./backend
+ dockerfile: Dockerfile
+ container_name: event-approval-backend
+ ports:
+ - "4001:5000"
+ environment:
+ - NODE_ENV=production
+ volumes:
+ - ./backend:/app
+ - /app/node_modules
+ depends_on:
+ - mongo
+ networks:
+ - app-network
+
+ frontend:
+ build:
+ context: ./frontend
+ dockerfile: Dockerfile
+ container_name: event-approval-frontend
+ ports:
+ - "5173:80"
+ depends_on:
+ - backend
+ networks:
+ - app-network
+
+ mongo:
+ image: mongo:5.0
+ container_name: event-approval-mongo
+ ports:
+ - "27017:27017"
+ volumes:
+ - mongo_data:/data/db
+ environment:
+ - MONGO_INITDB_ROOT_USERNAME=admin
+ - MONGO_INITDB_ROOT_PASSWORD=password
+ networks:
+ - app-network
+
+networks:
+ app-network:
+ driver: bridge
+
+volumes:
+ mongo_data:
\ No newline at end of file
diff --git a/frontend/.dockerignore b/frontend/.dockerignore
new file mode 100644
index 0000000..d64256b
--- /dev/null
+++ b/frontend/.dockerignore
@@ -0,0 +1,13 @@
+node_modules
+npm-debug.log
+.env
+.git
+.gitignore
+README.md
+Dockerfile
+.dockerignore
+coverage
+.nyc_output
+dist
+build
+.log
\ No newline at end of file
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
new file mode 100644
index 0000000..c9a8ae3
--- /dev/null
+++ b/frontend/Dockerfile
@@ -0,0 +1,37 @@
+# Multi-stage build for React app
+
+# Stage 1: Build the React app
+FROM node:22-alpine AS build
+
+# Set working directory
+WORKDIR /app
+
+# Copy package.json and package-lock.json
+COPY package*.json ./
+
+# Install dependencies
+RUN npm ci
+
+# Copy source code
+COPY . .
+
+# Set environment variables for production build
+ENV NODE_ENV=production
+
+# Build the app with more memory and debugging
+RUN npm run build 2>&1 || (echo "Build failed, checking files:" && ls -la && exit 1)
+
+# Stage 2: Serve the built app
+FROM nginx:alpine
+
+# Copy built files from previous stage
+COPY --from=build /app/dist /usr/share/nginx/html
+
+# Copy custom nginx configuration if needed (optional)
+# COPY nginx.conf /etc/nginx/nginx.conf
+
+# Expose port 80
+EXPOSE 5173
+
+# Start nginx
+CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
diff --git a/frontend/index.html b/frontend/index.html
index 0c589ec..731472d 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -4,7 +4,8 @@
-
Vite + React
+ Event Permissions
+
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index a34aadc..c15f273 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -1,23 +1,26 @@
{
- "name": "scs2-0",
+ "name": "event-approvals",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "scs2-0",
+ "name": "event-approvals",
"version": "0.0.0",
"dependencies": {
+ "@react-oauth/google": "^0.12.1",
"@zxing/library": "^0.21.3",
"axios": "^1.7.7",
"bootstrap": "^5.3.3",
"chart.js": "^4.4.5",
+ "jspdf": "^3.0.3",
"jwt-decode": "^4.0.0",
"react": "^18.3.1",
"react-bootstrap": "^2.10.5",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1",
+ "react-icons": "^5.5.0",
"react-modal": "^3.16.1",
"react-router-dom": "^6.27.0"
},
@@ -31,65 +34,48 @@
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.13",
"globals": "^15.11.0",
- "vite": "^5.4.9"
- }
- },
- "node_modules/@ampproject/remapping": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
- "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.3.5",
- "@jridgewell/trace-mapping": "^0.3.24"
- },
- "engines": {
- "node": ">=6.0.0"
+ "vite": "^7.1.6"
}
},
"node_modules/@babel/code-frame": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz",
- "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/helper-validator-identifier": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.27.1",
"js-tokens": "^4.0.0",
- "picocolors": "^1.0.0"
+ "picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/compat-data": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz",
- "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
+ "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz",
- "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.26.0",
- "@babel/generator": "^7.26.0",
- "@babel/helper-compilation-targets": "^7.25.9",
- "@babel/helper-module-transforms": "^7.26.0",
- "@babel/helpers": "^7.26.0",
- "@babel/parser": "^7.26.0",
- "@babel/template": "^7.25.9",
- "@babel/traverse": "^7.25.9",
- "@babel/types": "^7.26.0",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
+ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.3",
+ "@babel/helper-compilation-targets": "^7.27.2",
+ "@babel/helper-module-transforms": "^7.28.3",
+ "@babel/helpers": "^7.28.4",
+ "@babel/parser": "^7.28.4",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.4",
+ "@babel/types": "^7.28.4",
+ "@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -105,16 +91,15 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz",
- "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
+ "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/parser": "^7.26.0",
- "@babel/types": "^7.26.0",
- "@jridgewell/gen-mapping": "^0.3.5",
- "@jridgewell/trace-mapping": "^0.3.25",
+ "@babel/parser": "^7.28.3",
+ "@babel/types": "^7.28.2",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
},
"engines": {
@@ -122,14 +107,13 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz",
- "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==",
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+ "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/compat-data": "^7.25.9",
- "@babel/helper-validator-option": "^7.25.9",
+ "@babel/compat-data": "^7.27.2",
+ "@babel/helper-validator-option": "^7.27.1",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
@@ -138,30 +122,37 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-module-imports": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
- "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+ "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/traverse": "^7.25.9",
- "@babel/types": "^7.25.9"
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
- "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
+ "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/helper-module-imports": "^7.25.9",
- "@babel/helper-validator-identifier": "^7.25.9",
- "@babel/traverse": "^7.25.9"
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/traverse": "^7.28.3"
},
"engines": {
"node": ">=6.9.0"
@@ -171,67 +162,61 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz",
- "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
- "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
- "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-option": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
- "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz",
- "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
+ "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/template": "^7.25.9",
- "@babel/types": "^7.26.0"
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
- "version": "7.26.1",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz",
- "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
+ "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/types": "^7.26.0"
+ "@babel/types": "^7.28.4"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -241,13 +226,12 @@
}
},
"node_modules/@babel/plugin-transform-react-jsx-self": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz",
- "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.25.9"
+ "@babel/helper-plugin-utils": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
@@ -257,13 +241,12 @@
}
},
"node_modules/@babel/plugin-transform-react-jsx-source": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz",
- "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.25.9"
+ "@babel/helper-plugin-utils": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
@@ -273,472 +256,479 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
- "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
- "license": "MIT",
- "dependencies": {
- "regenerator-runtime": "^0.14.0"
- },
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
+ "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
- "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.25.9",
- "@babel/parser": "^7.25.9",
- "@babel/types": "^7.25.9"
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.2",
+ "@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz",
- "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
+ "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.25.9",
- "@babel/generator": "^7.25.9",
- "@babel/parser": "^7.25.9",
- "@babel/template": "^7.25.9",
- "@babel/types": "^7.25.9",
- "debug": "^4.3.1",
- "globals": "^11.1.0"
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.3",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.4",
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.4",
+ "debug": "^4.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
- "node_modules/@babel/traverse/node_modules/globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/@babel/types": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz",
- "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
+ "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/helper-string-parser": "^7.25.9",
- "@babel/helper-validator-identifier": "^7.25.9"
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
- "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
+ "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
"cpu": [
"ppc64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
- "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
+ "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
"cpu": [
"arm"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
- "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
+ "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
- "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
+ "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
- "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
+ "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
- "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
+ "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
- "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
- "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
+ "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
- "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
+ "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
"cpu": [
"arm"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
- "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
+ "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
- "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
+ "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
"cpu": [
"ia32"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
- "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
+ "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
"cpu": [
"loong64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
- "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
+ "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
"cpu": [
"mips64el"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
- "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
+ "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
"cpu": [
"ppc64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
- "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
+ "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
"cpu": [
"riscv64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
- "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
+ "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
"cpu": [
"s390x"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
- "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
+ "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
- "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
+ "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
- "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
+ "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
+ "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
- "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
+ "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
- "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
+ "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
- "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
+ "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
"cpu": [
"ia32"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
- "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
+ "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
- "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
+ "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
"dev": true,
- "license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
},
@@ -757,7 +747,6 @@
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
- "license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -766,23 +755,21 @@
}
},
"node_modules/@eslint-community/regexpp": {
- "version": "4.11.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.2.tgz",
- "integrity": "sha512-2WwyTYNVaMNUWPZTOJdkax9iqTdirrApgTbk+Qoq5EPX6myqZvG8QGFRgdKmkjKVG6/G/a565vpPauHk0+hpBA==",
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
"node_modules/@eslint/config-array": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz",
- "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==",
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
+ "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
"dev": true,
- "license": "Apache-2.0",
"dependencies": {
- "@eslint/object-schema": "^2.1.4",
+ "@eslint/object-schema": "^2.1.6",
"debug": "^4.3.1",
"minimatch": "^3.1.2"
},
@@ -790,22 +777,32 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz",
+ "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==",
+ "dev": true,
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/@eslint/core": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz",
- "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==",
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz",
+ "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==",
"dev": true,
- "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/eslintrc": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
- "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
+ "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
@@ -829,7 +826,6 @@
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=18"
},
@@ -838,32 +834,33 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.13.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz",
- "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==",
+ "version": "9.35.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz",
+ "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==",
"dev": true,
- "license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
}
},
"node_modules/@eslint/object-schema": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz",
- "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==",
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
+ "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
"dev": true,
- "license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz",
- "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==",
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz",
+ "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==",
"dev": true,
- "license": "Apache-2.0",
"dependencies": {
+ "@eslint/core": "^0.15.2",
"levn": "^0.4.1"
},
"engines": {
@@ -871,24 +868,22 @@
}
},
"node_modules/@humanfs/core": {
- "version": "0.19.0",
- "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz",
- "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==",
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
"dev": true,
- "license": "Apache-2.0",
"engines": {
"node": ">=18.18.0"
}
},
"node_modules/@humanfs/node": {
- "version": "0.16.5",
- "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz",
- "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==",
+ "version": "0.16.7",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+ "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
"dev": true,
- "license": "Apache-2.0",
"dependencies": {
- "@humanfs/core": "^0.19.0",
- "@humanwhocodes/retry": "^0.3.0"
+ "@humanfs/core": "^0.19.1",
+ "@humanwhocodes/retry": "^0.4.0"
},
"engines": {
"node": ">=18.18.0"
@@ -909,11 +904,10 @@
}
},
"node_modules/@humanwhocodes/retry": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
- "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
"dev": true,
- "license": "Apache-2.0",
"engines": {
"node": ">=18.18"
},
@@ -923,18 +917,23 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
- "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@jridgewell/set-array": "^1.2.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
- },
- "engines": {
- "node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
@@ -942,34 +941,21 @@
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/set-array": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
- "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
- "dev": true,
- "license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
- "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
- "dev": true,
- "license": "MIT"
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.25",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
- "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
@@ -1006,6 +992,15 @@
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0"
}
},
+ "node_modules/@react-oauth/google": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.12.1.tgz",
+ "integrity": "sha512-qagsy22t+7UdkYAiT5ZhfM4StXi9PPNvw0zuwNmabrWyMKddczMtBIOARflbaIj+wHiQjnMAsZmzsUYuXeyoSg==",
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
"node_modules/@remix-run/router": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz",
@@ -1057,225 +1052,280 @@
"react": ">=16.14.0"
}
},
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
- "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz",
+ "integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==",
"cpu": [
"arm"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
- "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz",
+ "integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
- "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz",
+ "integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
- "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz",
+ "integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz",
+ "integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz",
+ "integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
- "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz",
+ "integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==",
"cpu": [
"arm"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
- "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz",
+ "integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==",
"cpu": [
"arm"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
- "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz",
+ "integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
- "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz",
+ "integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
- "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
- "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz",
+ "integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz",
+ "integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==",
"cpu": [
"ppc64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
- "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz",
+ "integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz",
+ "integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==",
"cpu": [
"riscv64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
- "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz",
+ "integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==",
"cpu": [
"s390x"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
- "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz",
+ "integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
- "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz",
+ "integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz",
+ "integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
- "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz",
+ "integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
- "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz",
+ "integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==",
"cpu": [
"ia32"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
- "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz",
+ "integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1336,11 +1386,10 @@
}
},
"node_modules/@types/estree": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
- "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
- "dev": true,
- "license": "MIT"
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true
},
"node_modules/@types/json-schema": {
"version": "7.0.15",
@@ -1349,12 +1398,23 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/pako": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
+ "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw=="
+ },
"node_modules/@types/prop-types": {
"version": "15.7.13",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
"license": "MIT"
},
+ "node_modules/@types/raf": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
+ "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
+ "optional": true
+ },
"node_modules/@types/react": {
"version": "18.3.12",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
@@ -1384,6 +1444,12 @@
"@types/react": "*"
}
},
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "optional": true
+ },
"node_modules/@types/warning": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
@@ -1391,23 +1457,23 @@
"license": "MIT"
},
"node_modules/@vitejs/plugin-react": {
- "version": "4.3.3",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz",
- "integrity": "sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==",
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@babel/core": "^7.25.2",
- "@babel/plugin-transform-react-jsx-self": "^7.24.7",
- "@babel/plugin-transform-react-jsx-source": "^7.24.7",
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
"@types/babel__core": "^7.20.5",
- "react-refresh": "^0.14.2"
+ "react-refresh": "^0.17.0"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"peerDependencies": {
- "vite": "^4.2.0 || ^5.0.0"
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
"node_modules/@zxing/library": {
@@ -1431,11 +1497,10 @@
"optional": true
},
"node_modules/acorn": {
- "version": "8.13.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz",
- "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==",
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
- "license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -1448,7 +1513,6 @@
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
- "license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
@@ -1458,7 +1522,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
- "license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -1490,8 +1553,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true,
- "license": "Python-2.0"
+ "dev": true
},
"node_modules/array-buffer-byte-length": {
"version": "1.0.1",
@@ -1652,12 +1714,12 @@
}
},
"node_modules/axios": {
- "version": "1.7.7",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
- "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
+ "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"dependencies": {
"follow-redirects": "^1.15.6",
- "form-data": "^4.0.0",
+ "form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
@@ -1668,6 +1730,24 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/base64-arraybuffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+ "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz",
+ "integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==",
+ "dev": true,
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
"node_modules/bootstrap": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
@@ -1688,20 +1768,19 @@
}
},
"node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/browserslist": {
- "version": "4.24.2",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz",
- "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==",
+ "version": "4.26.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
+ "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
"dev": true,
"funding": [
{
@@ -1717,12 +1796,12 @@
"url": "https://github.com/sponsors/ai"
}
],
- "license": "MIT",
"dependencies": {
- "caniuse-lite": "^1.0.30001669",
- "electron-to-chromium": "^1.5.41",
- "node-releases": "^2.0.18",
- "update-browserslist-db": "^1.1.1"
+ "baseline-browser-mapping": "^2.8.3",
+ "caniuse-lite": "^1.0.30001741",
+ "electron-to-chromium": "^1.5.218",
+ "node-releases": "^2.0.21",
+ "update-browserslist-db": "^1.1.3"
},
"bin": {
"browserslist": "cli.js"
@@ -1751,20 +1830,31 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001671",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001671.tgz",
- "integrity": "sha512-jocyVaSSfXg2faluE6hrWkMgDOiULBMca4QLtDT39hw1YxaIPHWc1CcTCKkPmHgGH6tKji6ZNbMSmUAvENf2/A==",
+ "version": "1.0.30001743",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz",
+ "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==",
"dev": true,
"funding": [
{
@@ -1779,8 +1869,32 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
- ],
- "license": "CC-BY-4.0"
+ ]
+ },
+ "node_modules/canvg": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
+ "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
+ "optional": true,
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "@types/raf": "^3.4.0",
+ "core-js": "^3.8.3",
+ "raf": "^3.4.1",
+ "regenerator-runtime": "^0.13.7",
+ "rgbcolor": "^1.0.1",
+ "stackblur-canvas": "^2.0.0",
+ "svg-pathdata": "^6.0.3"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/canvg/node_modules/regenerator-runtime": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+ "optional": true
},
"node_modules/chalk": {
"version": "4.1.2",
@@ -1859,15 +1973,24 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true,
- "license": "MIT"
+ "dev": true
+ },
+ "node_modules/core-js": {
+ "version": "3.39.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz",
+ "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==",
+ "hasInstallScript": true,
+ "optional": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@@ -1877,6 +2000,15 @@
"node": ">= 8"
}
},
+ "node_modules/css-line-break": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
+ "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+ "optional": true,
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -2038,12 +2170,33 @@
"csstype": "^3.0.2"
}
},
+ "node_modules/dompurify": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz",
+ "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==",
+ "optional": true,
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/electron-to-chromium": {
- "version": "1.5.47",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.47.tgz",
- "integrity": "sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==",
- "dev": true,
- "license": "ISC"
+ "version": "1.5.222",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.222.tgz",
+ "integrity": "sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==",
+ "dev": true
},
"node_modules/es-abstract": {
"version": "1.23.3",
@@ -2107,14 +2260,9 @@
}
},
"node_modules/es-define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
- "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "get-intrinsic": "^1.2.4"
- },
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"engines": {
"node": ">= 0.4"
}
@@ -2123,7 +2271,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -2156,11 +2303,9 @@
}
},
"node_modules/es-object-atoms": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
- "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
- "dev": true,
- "license": "MIT",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dependencies": {
"es-errors": "^1.3.0"
},
@@ -2169,15 +2314,14 @@
}
},
"node_modules/es-set-tostringtag": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
- "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
- "dev": true,
- "license": "MIT",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dependencies": {
- "get-intrinsic": "^1.2.4",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
- "hasown": "^2.0.1"
+ "hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -2212,42 +2356,44 @@
}
},
"node_modules/esbuild": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
- "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
+ "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
"dev": true,
"hasInstallScript": true,
- "license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
- "node": ">=12"
+ "node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.21.5",
- "@esbuild/android-arm": "0.21.5",
- "@esbuild/android-arm64": "0.21.5",
- "@esbuild/android-x64": "0.21.5",
- "@esbuild/darwin-arm64": "0.21.5",
- "@esbuild/darwin-x64": "0.21.5",
- "@esbuild/freebsd-arm64": "0.21.5",
- "@esbuild/freebsd-x64": "0.21.5",
- "@esbuild/linux-arm": "0.21.5",
- "@esbuild/linux-arm64": "0.21.5",
- "@esbuild/linux-ia32": "0.21.5",
- "@esbuild/linux-loong64": "0.21.5",
- "@esbuild/linux-mips64el": "0.21.5",
- "@esbuild/linux-ppc64": "0.21.5",
- "@esbuild/linux-riscv64": "0.21.5",
- "@esbuild/linux-s390x": "0.21.5",
- "@esbuild/linux-x64": "0.21.5",
- "@esbuild/netbsd-x64": "0.21.5",
- "@esbuild/openbsd-x64": "0.21.5",
- "@esbuild/sunos-x64": "0.21.5",
- "@esbuild/win32-arm64": "0.21.5",
- "@esbuild/win32-ia32": "0.21.5",
- "@esbuild/win32-x64": "0.21.5"
+ "@esbuild/aix-ppc64": "0.25.10",
+ "@esbuild/android-arm": "0.25.10",
+ "@esbuild/android-arm64": "0.25.10",
+ "@esbuild/android-x64": "0.25.10",
+ "@esbuild/darwin-arm64": "0.25.10",
+ "@esbuild/darwin-x64": "0.25.10",
+ "@esbuild/freebsd-arm64": "0.25.10",
+ "@esbuild/freebsd-x64": "0.25.10",
+ "@esbuild/linux-arm": "0.25.10",
+ "@esbuild/linux-arm64": "0.25.10",
+ "@esbuild/linux-ia32": "0.25.10",
+ "@esbuild/linux-loong64": "0.25.10",
+ "@esbuild/linux-mips64el": "0.25.10",
+ "@esbuild/linux-ppc64": "0.25.10",
+ "@esbuild/linux-riscv64": "0.25.10",
+ "@esbuild/linux-s390x": "0.25.10",
+ "@esbuild/linux-x64": "0.25.10",
+ "@esbuild/netbsd-arm64": "0.25.10",
+ "@esbuild/netbsd-x64": "0.25.10",
+ "@esbuild/openbsd-arm64": "0.25.10",
+ "@esbuild/openbsd-x64": "0.25.10",
+ "@esbuild/openharmony-arm64": "0.25.10",
+ "@esbuild/sunos-x64": "0.25.10",
+ "@esbuild/win32-arm64": "0.25.10",
+ "@esbuild/win32-ia32": "0.25.10",
+ "@esbuild/win32-x64": "0.25.10"
}
},
"node_modules/escalade": {
@@ -2255,7 +2401,6 @@
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -2274,32 +2419,32 @@
}
},
"node_modules/eslint": {
- "version": "9.13.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz",
- "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.11.0",
- "@eslint/config-array": "^0.18.0",
- "@eslint/core": "^0.7.0",
- "@eslint/eslintrc": "^3.1.0",
- "@eslint/js": "9.13.0",
- "@eslint/plugin-kit": "^0.2.0",
- "@humanfs/node": "^0.16.5",
+ "version": "9.35.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz",
+ "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.0",
+ "@eslint/config-helpers": "^0.3.1",
+ "@eslint/core": "^0.15.2",
+ "@eslint/eslintrc": "^3.3.1",
+ "@eslint/js": "9.35.0",
+ "@eslint/plugin-kit": "^0.3.5",
+ "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
- "@humanwhocodes/retry": "^0.3.1",
+ "@humanwhocodes/retry": "^0.4.2",
"@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
+ "cross-spawn": "^7.0.6",
"debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^8.1.0",
- "eslint-visitor-keys": "^4.1.0",
- "espree": "^10.2.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
"esquery": "^1.5.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@@ -2313,8 +2458,7 @@
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "text-table": "^0.2.0"
+ "optionator": "^0.9.3"
},
"bin": {
"eslint": "bin/eslint.js"
@@ -2391,11 +2535,10 @@
}
},
"node_modules/eslint-scope": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz",
- "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==",
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
"dev": true,
- "license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
@@ -2408,11 +2551,10 @@
}
},
"node_modules/eslint-visitor-keys": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz",
- "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==",
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
"dev": true,
- "license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -2421,15 +2563,14 @@
}
},
"node_modules/espree": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz",
- "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==",
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
"dev": true,
- "license": "BSD-2-Clause",
"dependencies": {
- "acorn": "^8.12.0",
+ "acorn": "^8.15.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.1.0"
+ "eslint-visitor-keys": "^4.2.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2456,7 +2597,6 @@
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
- "license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -2493,15 +2633,13 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true,
- "license": "MIT"
+ "dev": true
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true,
- "license": "MIT"
+ "dev": true
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
@@ -2510,6 +2648,38 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-png": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz",
+ "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==",
+ "dependencies": {
+ "@types/pako": "^2.0.3",
+ "iobuffer": "^5.3.2",
+ "pako": "^2.1.0"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fflate": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
+ "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="
+ },
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -2591,12 +2761,14 @@
}
},
"node_modules/form-data": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
- "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@@ -2609,7 +2781,6 @@
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -2622,7 +2793,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -2662,23 +2832,25 @@
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/get-intrinsic": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
- "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
- "dev": true,
- "license": "MIT",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
- "has-proto": "^1.0.1",
- "has-symbols": "^1.0.3",
- "hasown": "^2.0.0"
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -2687,6 +2859,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/get-symbol-description": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
@@ -2758,13 +2942,11 @@
}
},
"node_modules/gopd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
- "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "get-intrinsic": "^1.1.3"
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -2817,11 +2999,9 @@
}
},
"node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "dev": true,
- "license": "MIT",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"engines": {
"node": ">= 0.4"
},
@@ -2833,7 +3013,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@@ -2849,7 +3028,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -2858,22 +3036,33 @@
"node": ">= 0.4"
}
},
+ "node_modules/html2canvas": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+ "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+ "optional": true,
+ "dependencies": {
+ "css-line-break": "^2.1.0",
+ "text-segmentation": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
@@ -2919,6 +3108,11 @@
"loose-envify": "^1.0.0"
}
},
+ "node_modules/iobuffer": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
+ "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA=="
+ },
"node_modules/is-array-buffer": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
@@ -3316,7 +3510,6 @@
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -3325,11 +3518,10 @@
}
},
"node_modules/jsesc": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
- "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"dev": true,
- "license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
},
@@ -3348,8 +3540,7 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true,
- "license": "MIT"
+ "dev": true
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -3363,7 +3554,6 @@
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
- "license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
@@ -3371,6 +3561,22 @@
"node": ">=6"
}
},
+ "node_modules/jspdf": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.3.tgz",
+ "integrity": "sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.26.9",
+ "fast-png": "^6.2.0",
+ "fflate": "^0.8.1"
+ },
+ "optionalDependencies": {
+ "canvg": "^3.0.11",
+ "core-js": "^3.6.0",
+ "dompurify": "^3.2.4",
+ "html2canvas": "^1.0.0-rc.5"
+ }
+ },
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -3459,11 +3665,18 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dev": true,
- "license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
}
},
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -3504,9 +3717,9 @@
"license": "MIT"
},
"node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
@@ -3514,7 +3727,6 @@
"url": "https://github.com/sponsors/ai"
}
],
- "license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -3530,11 +3742,10 @@
"license": "MIT"
},
"node_modules/node-releases": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
- "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
- "dev": true,
- "license": "MIT"
+ "version": "2.0.21",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz",
+ "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==",
+ "dev": true
},
"node_modules/object-assign": {
"version": "4.1.1",
@@ -3689,12 +3900,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/pako": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
+ "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
- "license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
},
@@ -3729,12 +3944,29 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+ "optional": true
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
- "license": "ISC"
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
},
"node_modules/possible-typed-array-names": {
"version": "1.0.0",
@@ -3747,9 +3979,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.47",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
- "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"dev": true,
"funding": [
{
@@ -3765,10 +3997,9 @@
"url": "https://github.com/sponsors/ai"
}
],
- "license": "MIT",
"dependencies": {
- "nanoid": "^3.3.7",
- "picocolors": "^1.1.0",
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
@@ -3819,11 +4050,19 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6"
}
},
+ "node_modules/raf": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+ "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+ "optional": true,
+ "dependencies": {
+ "performance-now": "^2.1.0"
+ }
+ },
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@@ -3905,6 +4144,15 @@
"react-dom": ">=16"
}
},
+ "node_modules/react-icons": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
+ "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -3936,11 +4184,10 @@
}
},
"node_modules/react-refresh": {
- "version": "0.14.2",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
- "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -4015,12 +4262,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/regenerator-runtime": {
- "version": "0.14.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
- "license": "MIT"
- },
"node_modules/regexp.prototype.flags": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
@@ -4063,19 +4304,26 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=4"
}
},
+ "node_modules/rgbcolor": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
+ "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.8.15"
+ }
+ },
"node_modules/rollup": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
- "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
+ "version": "4.50.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz",
+ "integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@types/estree": "1.0.6"
+ "@types/estree": "1.0.8"
},
"bin": {
"rollup": "dist/bin/rollup"
@@ -4085,22 +4333,27 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.24.0",
- "@rollup/rollup-android-arm64": "4.24.0",
- "@rollup/rollup-darwin-arm64": "4.24.0",
- "@rollup/rollup-darwin-x64": "4.24.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
- "@rollup/rollup-linux-arm-musleabihf": "4.24.0",
- "@rollup/rollup-linux-arm64-gnu": "4.24.0",
- "@rollup/rollup-linux-arm64-musl": "4.24.0",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.24.0",
- "@rollup/rollup-linux-s390x-gnu": "4.24.0",
- "@rollup/rollup-linux-x64-gnu": "4.24.0",
- "@rollup/rollup-linux-x64-musl": "4.24.0",
- "@rollup/rollup-win32-arm64-msvc": "4.24.0",
- "@rollup/rollup-win32-ia32-msvc": "4.24.0",
- "@rollup/rollup-win32-x64-msvc": "4.24.0",
+ "@rollup/rollup-android-arm-eabi": "4.50.2",
+ "@rollup/rollup-android-arm64": "4.50.2",
+ "@rollup/rollup-darwin-arm64": "4.50.2",
+ "@rollup/rollup-darwin-x64": "4.50.2",
+ "@rollup/rollup-freebsd-arm64": "4.50.2",
+ "@rollup/rollup-freebsd-x64": "4.50.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.50.2",
+ "@rollup/rollup-linux-arm-musleabihf": "4.50.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.50.2",
+ "@rollup/rollup-linux-arm64-musl": "4.50.2",
+ "@rollup/rollup-linux-loong64-gnu": "4.50.2",
+ "@rollup/rollup-linux-ppc64-gnu": "4.50.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.50.2",
+ "@rollup/rollup-linux-riscv64-musl": "4.50.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.50.2",
+ "@rollup/rollup-linux-x64-gnu": "4.50.2",
+ "@rollup/rollup-linux-x64-musl": "4.50.2",
+ "@rollup/rollup-openharmony-arm64": "4.50.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.50.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.50.2",
+ "@rollup/rollup-win32-x64-msvc": "4.50.2",
"fsevents": "~2.3.2"
}
},
@@ -4241,11 +4494,19 @@
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
- "license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
+ "node_modules/stackblur-canvas": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
+ "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.1.14"
+ }
+ },
"node_modules/string.prototype.matchall": {
"version": "4.0.11",
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
@@ -4341,7 +4602,6 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=8"
},
@@ -4375,12 +4635,39 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "node_modules/svg-pathdata": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
+ "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
+ "optional": true,
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/text-segmentation": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
+ "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+ "optional": true,
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
- "license": "MIT"
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
},
"node_modules/ts-custom-error": {
"version": "3.3.1",
@@ -4518,9 +4805,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
- "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
"dev": true,
"funding": [
{
@@ -4536,10 +4823,9 @@
"url": "https://github.com/sponsors/ai"
}
],
- "license": "MIT",
"dependencies": {
"escalade": "^3.2.0",
- "picocolors": "^1.1.0"
+ "picocolors": "^1.1.1"
},
"bin": {
"update-browserslist-db": "cli.js"
@@ -4553,27 +4839,37 @@
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
- "license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
},
+ "node_modules/utrie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
+ "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+ "optional": true,
+ "dependencies": {
+ "base64-arraybuffer": "^1.0.2"
+ }
+ },
"node_modules/vite": {
- "version": "5.4.10",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz",
- "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.6.tgz",
+ "integrity": "sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "esbuild": "^0.21.3",
- "postcss": "^8.4.43",
- "rollup": "^4.20.0"
+ "esbuild": "^0.25.0",
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.15"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
- "node": "^18.0.0 || >=20.0.0"
+ "node": "^20.19.0 || >=22.12.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
@@ -4582,19 +4878,25 @@
"fsevents": "~2.3.3"
},
"peerDependencies": {
- "@types/node": "^18.0.0 || >=20.0.0",
- "less": "*",
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
"lightningcss": "^1.21.0",
- "sass": "*",
- "sass-embedded": "*",
- "stylus": "*",
- "sugarss": "*",
- "terser": "^5.4.0"
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
+ "jiti": {
+ "optional": true
+ },
"less": {
"optional": true
},
@@ -4615,6 +4917,12 @@
},
"terser": {
"optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
}
}
},
@@ -4740,8 +5048,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
- "dev": true,
- "license": "ISC"
+ "dev": true
},
"node_modules/yocto-queue": {
"version": "0.1.0",
diff --git a/frontend/package.json b/frontend/package.json
index f587a57..85c00f9 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,5 +1,5 @@
{
- "name": "scs2-0",
+ "name": "event-approvals",
"private": true,
"version": "0.0.0",
"type": "module",
@@ -10,16 +10,19 @@
"preview": "vite preview"
},
"dependencies": {
+ "@react-oauth/google": "^0.12.1",
"@zxing/library": "^0.21.3",
"axios": "^1.7.7",
"bootstrap": "^5.3.3",
"chart.js": "^4.4.5",
+ "jspdf": "^3.0.3",
"jwt-decode": "^4.0.0",
"react": "^18.3.1",
"react-bootstrap": "^2.10.5",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1",
+ "react-icons": "^5.5.0",
"react-modal": "^3.16.1",
"react-router-dom": "^6.27.0"
},
@@ -33,6 +36,6 @@
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.13",
"globals": "^15.11.0",
- "vite": "^5.4.9"
+ "vite": "^7.1.6"
}
}
diff --git a/frontend/public/form_header.png b/frontend/public/form_header.png
new file mode 100644
index 0000000..4d53d61
Binary files /dev/null and b/frontend/public/form_header.png differ
diff --git a/frontend/public/library_image.jpg b/frontend/public/library_image.jpg
new file mode 100644
index 0000000..70b7630
Binary files /dev/null and b/frontend/public/library_image.jpg differ
diff --git a/frontend/public/staff.png b/frontend/public/staff.png
new file mode 100644
index 0000000..30da8a1
Binary files /dev/null and b/frontend/public/staff.png differ
diff --git a/frontend/public/student.png b/frontend/public/student.png
new file mode 100644
index 0000000..d4c8129
Binary files /dev/null and b/frontend/public/student.png differ
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index b32765c..e5819f4 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,41 +1,50 @@
-import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
-import Home from './Pages/Home/Home.jsx';
-import Security from './Pages/Security/Security.jsx';
-import ProtectedRoute from './Components/ProtectedRoute/ProtectedRoute.jsx';
-import StudentDashboard from './Pages/Student DashBoard/StudentDashboard.jsx';
-import WardenDashboard from './Pages/WardenDashboard/WardenDashboard.jsx';
+import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
+import Home from "./Pages/Home/Home.jsx";
+import ProtectedRoute from "./Components/ProtectedRoute/ProtectedRoute.jsx";
+import StudentDashboard from "./Pages/Student DashBoard/StudentDashboard.jsx";
+import StaffDashboard from "./Pages/Staff Dashboard/StaffDashboard.jsx";
+import EventDetails from "./Pages/Event Details/EventDetails.jsx"; // Import EventDetails component
+import { Toaster } from "react-hot-toast"; // Import the Toaster component
+import PageNotFound from "./Pages/Page Not Found/PageNotFound.jsx";
+import { GoogleOAuthProvider } from "@react-oauth/google"; // Import GoogleOAuthProvider
function App() {
+ const GOOGLE_CLIENT_ID ="126283465709-v64j607pjhd396kjsrn7qprhk2dns9ou.apps.googleusercontent.com";
+
return (
-
-
- } />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
+
+
+
+ } />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+ } />
+
+ {/* Render the Toaster */}
+
+
);
}
diff --git a/frontend/src/Components/ApplyLeave/ApplyLeave.css b/frontend/src/Components/ApplyLeave/ApplyLeave.css
deleted file mode 100644
index e24e894..0000000
--- a/frontend/src/Components/ApplyLeave/ApplyLeave.css
+++ /dev/null
@@ -1,57 +0,0 @@
-.leave-container {
- display: flex;
- justify-content: center; /* Center horizontally */
- align-items: center; /* Center vertically */
- height: 100%; /* Take full height of the parent */
- padding: 20px; /* Add some padding */
- background-color: #f9f9f9; /* Light background color */
- }
-
- .leave-form {
- background-color: white; /* White background for the form */
- padding: 30px; /* Inner padding */
- border-radius: 15px; /* Rounded corners */
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* Soft shadow */
- width: 100%; /* Full width */
- max-width: 400px; /* Max width for form */
- transition: transform 0.3s ease; /* Smooth transition on hover */
- }
-
- .form-title {
- font-size: 24px; /* Title font size */
- margin-bottom: 20px; /* Space below title */
- text-align: center; /* Center the title text */
- }
-
- .form-input {
- width: 100%; /* Full width */
- padding: 10px; /* Inner padding */
- margin: 10px 0; /* Space between inputs */
- border: 1px solid #ddd; /* Light border */
- border-radius: 5px; /* Rounded corners */
- font-size: 16px; /* Font size */
- transition: border-color 0.3s; /* Smooth border color change */
- }
-
- .form-input:focus {
- border-color: #007bff; /* Change border color on focus */
- outline: none; /* Remove default outline */
- }
-
- .form-button {
- width: 100%; /* Full width */
- padding: 10px; /* Inner padding */
- margin-top: 20px; /* Space above button */
- border: none; /* Remove border */
- border-radius: 5px; /* Rounded corners */
- background-color: #007bff; /* Blue background */
- color: white; /* White text */
- font-size: 16px; /* Font size */
- cursor: pointer; /* Pointer on hover */
- transition: background-color 0.3s; /* Smooth background color change */
- }
-
- .form-button:hover {
- background-color: #0056b3; /* Darker blue on hover */
- }
-
\ No newline at end of file
diff --git a/frontend/src/Components/ApplyLeave/ApplyLeave.jsx b/frontend/src/Components/ApplyLeave/ApplyLeave.jsx
deleted file mode 100644
index 0b1d31b..0000000
--- a/frontend/src/Components/ApplyLeave/ApplyLeave.jsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import React, { useState } from 'react';
-import axios from 'axios';
-import './ApplyLeave.css';
-import toast, { Toaster } from "react-hot-toast";
-
-function ApplyLeave() {
- const [formData, setFormData] = useState({
- placeOfVisit: '',
- reason: '',
- dateOfLeaving: '',
- arrivalDate: '',
- emergencyContact: ''
- });
-
- const handleChange = (e) => {
- const { name, value } = e.target;
- setFormData({ ...formData, [name]: value });
- };
-
- // Get today’s date in YYYY-MM-DD format for validation
- const today = new Date().toISOString().split('T')[0];
-
- const handleDateValidation = () => {
- const { dateOfLeaving, arrivalDate } = formData;
-
- // Validate that dateOfLeaving is not in the past
- if (dateOfLeaving && new Date(dateOfLeaving) < new Date(today)) {
- toast.error("Date of leaving cannot be in the past.");
- setFormData({ ...formData, dateOfLeaving: '' });
- return;
- }
-
- // Validate that arrivalDate is not before dateOfLeaving
- if (arrivalDate && dateOfLeaving && new Date(arrivalDate) < new Date(dateOfLeaving)) {
- toast.error("Arrival date cannot be before the date of leaving.");
- setFormData({ ...formData, arrivalDate: '' });
- }
- };
-
- const handleSubmit = async (e) => {
- e.preventDefault();
- const token = localStorage.getItem('token');
- const userID = localStorage.getItem('userID');
- try {
- await axios.post('http://localhost:4001/leave/apply', { ...formData, userID }, {
- headers: { Authorization: `Bearer ${token}` },
- });
- toast.success('Leave application submitted!');
- setFormData({
- placeOfVisit: '',
- reason: '',
- dateOfLeaving: '',
- arrivalDate: '',
- emergencyContact: ''
- });
- } catch (error) {
- console.error(error);
- toast.error(error.response?.data?.message || 'Error applying for leave.');
- }
- };
-
- return (
-
-
-
-
- );
-}
-
-export default ApplyLeave;
diff --git a/frontend/src/Components/ApplyOuting/ApplyOuting.css b/frontend/src/Components/ApplyOuting/ApplyOuting.css
deleted file mode 100644
index 4d8bcc2..0000000
--- a/frontend/src/Components/ApplyOuting/ApplyOuting.css
+++ /dev/null
@@ -1,57 +0,0 @@
-.outing-container {
- display: flex;
- justify-content: center; /* Center horizontally */
- align-items: center; /* Center vertically */
- height: 100%; /* Take full height of the parent */
- padding: 20px; /* Add some padding */
- background-color: #f9f9f9; /* Light background color */
- }
-
- .outing-form {
- background-color: white; /* White background for the form */
- padding: 30px; /* Inner padding */
- border-radius: 15px; /* Rounded corners */
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* Soft shadow */
- width: 100%; /* Full width */
- max-width: 400px; /* Max width for form */
- transition: transform 0.3s ease; /* Smooth transition on hover */
- }
-
- .form-title {
- font-size: 24px; /* Title font size */
- margin-bottom: 20px; /* Space below title */
- text-align: center; /* Center the title text */
- }
-
- .form-input {
- width: 100%; /* Full width */
- padding: 10px; /* Inner padding */
- margin: 10px 0; /* Space between inputs */
- border: 1px solid #ddd; /* Light border */
- border-radius: 5px; /* Rounded corners */
- font-size: 16px; /* Font size */
- transition: border-color 0.3s; /* Smooth border color change */
- }
-
- .form-input:focus {
- border-color: #007bff; /* Change border color on focus */
- outline: none; /* Remove default outline */
- }
-
- .form-button {
- width: 100%; /* Full width */
- padding: 10px; /* Inner padding */
- margin-top: 20px; /* Space above button */
- border: none; /* Remove border */
- border-radius: 5px; /* Rounded corners */
- background-color: #007bff; /* Blue background */
- color: white; /* White text */
- font-size: 16px; /* Font size */
- cursor: pointer; /* Pointer on hover */
- transition: background-color 0.3s; /* Smooth background color change */
- }
-
- .form-button:hover {
- background-color: #0056b3; /* Darker blue on hover */
- }
-
\ No newline at end of file
diff --git a/frontend/src/Components/ApplyOuting/ApplyOuting.jsx b/frontend/src/Components/ApplyOuting/ApplyOuting.jsx
deleted file mode 100644
index 2f50038..0000000
--- a/frontend/src/Components/ApplyOuting/ApplyOuting.jsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import React, { useState } from 'react';
-import axios from 'axios';
-import './ApplyOuting.css'; // Import the CSS for styling
-import toast, { Toaster } from "react-hot-toast";
-
-function ApplyOuting() {
- const [outingData, setOutingData] = useState({
- placeOfVisit: '',
- reason: '',
- emergencyContact: ''
- });
-
- const handleChange = (e) => {
- const { name, value } = e.target;
- setOutingData({ ...outingData, [name]: value });
- };
-
- const handleSubmit = async (e) => {
- e.preventDefault();
- const token = localStorage.getItem('token');
- const userID = localStorage.getItem('userID'); // Get userID from local storage
- try {
- await axios.post('http://localhost:4001/out/outapply', { ...outingData, userID }, { // Include userID in the request body
- headers: { Authorization: `Bearer ${token}` },
- });
- toast.success('Outing application submitted!'); // Use toast for success notification
- // Reset form data after submission
- setOutingData({
- placeOfVisit: '',
- reason: '',
- emergencyContact: ''
- });
- } catch (error) {
- console.error(error);
- toast.error("Error: " + error.response.data.message);
- }
- };
-
- return (
-
- {/* Add the Toaster component here */}
-
-
- );
-}
-
-export default ApplyOuting;
diff --git a/frontend/src/Components/BarCodeScanner/BarCodeScanner.jsx b/frontend/src/Components/BarCodeScanner/BarCodeScanner.jsx
deleted file mode 100644
index b0a4eec..0000000
--- a/frontend/src/Components/BarCodeScanner/BarCodeScanner.jsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { BrowserMultiFormatReader, BarcodeFormat } from "@zxing/library";
-
-const BarcodeScanner = ({ onScan, onScanAgain }) => {
- const [result, setResult] = useState(null);
- const [videoDevice, setVideoDevice] = useState(null);
- const [scanning, setScanning] = useState(true); // Track scanning state
-
- useEffect(() => {
- const reader = new BrowserMultiFormatReader();
-
- async function init() {
- try {
- const videoDevices = await reader.listVideoInputDevices();
-
- if (videoDevices.length > 0) {
- setVideoDevice(videoDevices[0]); // Use the first available video device
- }
- } catch (error) {
- console.error("Error listing video devices:", error);
- }
- }
-
- init();
-
- // Cleanup function for reader
- return () => {
- reader.reset(); // Ensure that the reader is reset when the component unmounts
- };
- }, []);
-
- useEffect(() => {
- const videoElement = document.getElementById('video');
- const reader = new BrowserMultiFormatReader();
-
- if (videoDevice && scanning) {
- reader.decodeFromVideoDevice(videoDevice.deviceId, videoElement, (result) => {
- if (result) {
- // Check if the result format is a barcode format
- if (
- result.format === BarcodeFormat.CODE_39 ||
- result.format === BarcodeFormat.CODE_128 ||
- result.format === BarcodeFormat.EAN_13 ||
- result.format === BarcodeFormat.EAN_8 ||
- result.format === BarcodeFormat.UPC_A ||
- result.format === BarcodeFormat.UPC_E ||
- result.format === BarcodeFormat.ITF
- ) {
- setResult(result.text);
- onScan(result.text); // Send the scanned result to the parent component
- setScanning(false); // Stop scanning after a successful scan
- reader.reset(); // Stop the reader
- }
- }
- }, {
- // Set the formats to only decode the desired barcode formats
- formats: [
- BarcodeFormat.CODE_39,
- BarcodeFormat.CODE_128,
- BarcodeFormat.EAN_13,
- BarcodeFormat.EAN_8,
- BarcodeFormat.UPC_A,
- BarcodeFormat.UPC_E,
- BarcodeFormat.ITF,
- ],
- });
-
- // Cleanup function to stop the video stream when the videoDevice changes or scanning stops
- return () => {
- reader.reset(); // Stop the reader when cleaning up
- };
- }
- }, [videoDevice, scanning]);
-
- const handleScanAgain = () => {
- setResult(null); // Reset the result
- setScanning(true); // Start scanning again
- onScanAgain(); // Call the scan again function from props
- };
-
- return (
-
- {result ? (
-
-
Scanned Code: {result}
-
{/* Button to scan again */}
-
- ) : (
-
Scanning...
- )}
-
-
- );
-};
-
-export default BarcodeScanner;
diff --git a/frontend/src/Components/EventForm/EventForm.css b/frontend/src/Components/EventForm/EventForm.css
new file mode 100644
index 0000000..b76c258
--- /dev/null
+++ b/frontend/src/Components/EventForm/EventForm.css
@@ -0,0 +1,90 @@
+/* Container styling for the form */
+.event-form-container {
+ max-width: 850px;
+ background-color: #ffffff;
+ padding: 2rem;
+ border-radius: 8px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+}
+
+.event-form-container h2 {
+ font-weight: 600;
+ color: #343a40;
+}
+
+.event-form-container h4 {
+ color: #007bff;
+ border-bottom: 2px solid #007bff;
+ padding-bottom: 0.5rem;
+ margin-top: 2rem;
+}
+
+.form-label {
+ font-weight: 500;
+ color: #495057;
+}
+
+.form-control:focus,
+.form-select:focus {
+ border-color: #80bdff;
+ box-shadow: 0 0 0 0.25rem rgba(0, 123, 255, 0.25);
+}
+
+.btn {
+ padding: 0.5rem 1.5rem;
+ font-size: 1rem;
+ font-weight: 500;
+ border-radius: 0.25rem;
+ transition: all 0.2s ease-in-out;
+}
+
+.btn-primary {
+ background-color: #007bff;
+ border-color: #007bff;
+}
+
+.btn-primary:hover {
+ background-color: #0056b3;
+ border-color: #0056b3;
+ transform: translateY(-2px);
+}
+
+.btn-success {
+ background-color: #28a745;
+ border-color: #28a745;
+}
+
+.btn-success:hover {
+ background-color: #1e7e34;
+ border-color: #1e7e34;
+ transform: translateY(-2px);
+ }
+
+.btn:disabled {
+ cursor: not-allowed;
+ opacity: 0.65;
+}
+
+.form-check-label {
+ line-height: 1.5;
+ color: #333;
+}
+
+.form-check-input {
+ margin-top: 0.4em;
+}
+
+@media (max-width: 576px) {
+ .event-form-container {
+ padding: 1.5rem;
+ }
+
+ .btn {
+ width: 100%;
+ margin-bottom: 0.5rem;
+ }
+
+ .d-flex.justify-content-start {
+ flex-direction: column;
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/Components/EventForm/EventForm.jsx b/frontend/src/Components/EventForm/EventForm.jsx
new file mode 100644
index 0000000..4c54c36
--- /dev/null
+++ b/frontend/src/Components/EventForm/EventForm.jsx
@@ -0,0 +1,568 @@
+import { useState } from "react";
+import { jsPDF } from "jspdf"; // Assuming this is used within generatePDF
+import "bootstrap/dist/css/bootstrap.min.css";
+import toast, { Toaster } from "react-hot-toast";
+import API from '/src/api/api';
+import { generatePDF } from "../../utils/pdfGenerator";
+import StudentDashboard from "../StudentDashboard/EventDashboard.jsx";
+import "./EventForm.css";
+
+const EventForm = () => {
+ const [formData, setFormData] = useState(
+
+ //Event Details:
+ eventName: "", //1a (index no as in official form)
+ partOfGymkhanaCalendar: "",//1b
+ eventType: "", //extra variable: Not in official form, just to track type of event
+ clubName: "", //2
+ startDate: "", //3a
+ endDate: "", //3b
+ eventVenue: "", //3c
+ sourceOfBudget: "", //4a
+ othersSourceOfBudget: "", //4b
+ estimatedBudget: 0, //5 - Set initial value to 0
+ budgetBreakup: [{ expenseHead: "", estimatedAmount: "" }], //array to hold the data of the "Budget Breakup" Table's rows
+
+ //Organizer Details:
+ nameOfTheOrganizer: "", //1
+ designation: "", //2
+ email: "", //3
+ phoneNumber: "", //4
+
+ //Requirements
+ requirements: [],
+ anyAdditionalAmenities: "",
+ // Event Description
+ eventDescription: "",
+ // Participants
+ internalParticipants: "",
+ externalParticipants: "",
+ listOfCollaboratingOrganizations: ""
+ });
+
+ const [isAgreementChecked, setisAgreementChecked] = useState(false);
+ const [isFormSubmitted, setIsFormSubmitted] = useState(false);
+
+ // Get today's date in YYYY-MM-DD format for min attribute in date inputs
+ const today = new Date().toISOString().split("T")[0];
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData({ ...formData, [name]: value });
+ };
+
+ const handleCheckboxChange = (e) => {
+ const { value, checked } = e.target;
+ setFormData((prevData) => ({
+ ...prevData,
+ requirements: checked
+ ? [...prevData.requirements, value]
+ : prevData.requirements.filter((item) => item !== value),
+ }));
+ };
+
+ const handleDateValidation = () => {
+ // Validate that endDate is not before startDate
+ if (formData.startDate && formData.endDate && new Date(formData.endDate) < new Date(formData.startDate)) {
+ toast.error("End Date cannot be before the Start Date.");
+ setFormData({ ...formData, endDate: "" });
+ }
+ };
+
+ const validateForm = () => {
+ const requiredFields = [
+ "eventName", "partOfGymkhanaCalendar", "eventType", "clubName", "startDate", "endDate",
+ "eventVenue", "sourceOfBudget", "estimatedBudget", "nameOfTheOrganizer", "designation",
+ "email", "phoneNumber", "eventDescription", "externalParticipants", "internalParticipants"
+ ];
+
+ if (requiredFields.some(field => !formData[field])) {
+ return false;
+ }
+
+ // Conditionally require listOfCollaboratingOrganizations
+ if (Number(formData.externalParticipants) > 0 && !formData.listOfCollaboratingOrganizations) {
+ return false;
+ }
+
+ return true;
+ };
+
+ // Handlers for the Budget Breakup Table
+ const handleBudgetChange = (index, e) => {
+ const { name, value } = e.target;
+ const list = [...formData.budgetBreakup];
+ list[index][name] = value;
+
+ // Recalculate the total budget
+ const total = list.reduce((acc, curr) => acc + Number(curr.estimatedAmount || 0), 0);
+
+ setFormData({ ...formData, budgetBreakup: list, estimatedBudget: total });
+ };
+
+ const handleAddRow = () => {
+ setFormData({
+ ...formData,
+ budgetBreakup: [...formData.budgetBreakup, { expenseHead: "", estimatedAmount: "" }],
+ });
+ };
+
+ const handleRemoveRow = (index) => {
+ const list = [...formData.budgetBreakup];
+ list.splice(index, 1);
+
+ // Recalculate the total budget
+ const total = list.reduce((acc, curr) => acc + Number(curr.estimatedAmount || 0), 0);
+
+ setFormData({ ...formData, budgetBreakup: list, estimatedBudget: total });
+ };
+
+ const handleSubmit = async () => {
+ if (!validateForm()) {
+ toast.error("Please fill out all required fields.");
+ return;
+ }
+
+ const userID = localStorage.getItem("userID");
+ const requestData = { ...formData, userID };
+
+ try {
+ const response = await API.post("/event/apply", requestData);
+ toast.success(response.data.message || "Event proposal submitted successfully!");
+ setTimeout(() => {
+ setIsFormSubmitted(true);
+ }, 1200);
+ } catch (error) {
+ console.error("Error submitting event:", error);
+ toast.error(error.response?.data?.message || "Failed to submit the proposal.");
+ }
+ };
+
+ if (isFormSubmitted) {
+ return ;
+ }
+
+ return (
+
+
+
Event Proposal Form
+
+
+
+
+ );
+};
+
+export default EventForm;
\ No newline at end of file
diff --git a/frontend/src/Components/Footer/Footer.css b/frontend/src/Components/Footer/Footer.css
index 1dfb166..63560b0 100644
--- a/frontend/src/Components/Footer/Footer.css
+++ b/frontend/src/Components/Footer/Footer.css
@@ -1,8 +1,39 @@
-footer{
- background-color: #291334;
+footer {
+ /* background-color: #000000 !important; Ensure black background */
color: #FFFFFF;
+ width: 100%;
}
+
+.full-width-footer {
+ width: 100%;
+ margin: 0; /* Remove default margins */
+ padding: 0; /* Adjust padding if needed */
+ background-color: #291334; /* Ensure consistent background color */
+}
+
+.full-width-footer .container {
+ max-width: 100%; /* Override Bootstrap's default max-width */
+ padding: 0; /* Remove container padding for full-width effect */
+}
+
+.full-width-footer {
+ overflow-x: hidden;
+}
+
+
+footer.container {
+ max-width: 100%;
+ padding: 0;
+ border: 2px solid #F2911B; /* Optional: Add a border for separation */
+
+}
+.footer-main {
+ background-color: #291334; /* Change to black */
+ color: #FFFFFF; /* Text color */
+ padding: 20px; /* Optional: Add padding */
+}
+
.foot-link{
font-weight: 500;
position: relative;
@@ -45,3 +76,8 @@ hr{
p{
margin-bottom: 0;
}
+
+div.copyright {
+ background-color: #291334; /* Change to black */
+ padding: 10px;
+}
\ No newline at end of file
diff --git a/frontend/src/Components/Footer/Footer.jsx b/frontend/src/Components/Footer/Footer.jsx
index e326771..c2b864b 100644
--- a/frontend/src/Components/Footer/Footer.jsx
+++ b/frontend/src/Components/Footer/Footer.jsx
@@ -4,9 +4,8 @@ import "./Footer.css"
const Footer = () => {
return (
-