diff --git a/Backend/.gitignore b/Backend/.gitignore
deleted file mode 100644
index cd5d2a9..0000000
--- a/Backend/.gitignore
+++ /dev/null
@@ -1,26 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-package-lock.json
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
-.env
\ No newline at end of file
diff --git a/Backend/config/firebase-admin.js b/Backend/config/firebase-admin.js
deleted file mode 100644
index e678186..0000000
--- a/Backend/config/firebase-admin.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import admin from 'firebase-admin';
-import fs from 'fs';
-import path from 'path';
-import { fileURLToPath } from 'url';
-
-// Get the directory name
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-
-// Read service account key file
-const serviceAccountPath = path.join(__dirname, 'serviceAccountKey.json');
-const serviceAccount = JSON.parse(fs.readFileSync(serviceAccountPath, 'utf8'));
-
-// Initialize Firebase Admin
-admin.initializeApp({
- credential: admin.credential.cert(serviceAccount)
-});
-
-console.log('Firebase Admin initialized successfully');
-
-export default admin;
diff --git a/Backend/config/serviceAccountKey.json b/Backend/config/serviceAccountKey.json
deleted file mode 100644
index afa290f..0000000
--- a/Backend/config/serviceAccountKey.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "type": "service_account",
- "project_id": "taskboard-pro-aa57d",
- "private_key_id": "1f32d7f0562e0bbb95f2e7382ab8e86ac3ff3344",
- "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCHkOFIX06BPkM5\nCGZSj+3TtgQ5aq00ckTBjHcyvVra805hqs1jFQuB8PQ73ukQTb0KgfHQIzWBhIpH\n9WXOJXYTNR+mDApglb6rq31q8/UowAqrkUNf0IYhrgI36UMuvhU/JmvylfnLHoPN\nOw0kAeTEIP4MKo2KC/qbC74V3Xt84xyBiPXnVt0If3dviGnZhoH6lD7H7JUWuDAw\nXiPs7a+muSiEyhbq0kBDjrgg5AnQTH539Xuu7YBgbcYgX440WYF291ZbgoWQ2qw3\nFPtnuoYjNLkR3SlybA4cUbjCJFDaCls8EqkAIsSKXDATwEOduk4Y8zdt7bqVtYM3\n+/iVIOsLAgMBAAECggEAAYGCfyNP4++lH4UQXeprYeartVeSBPsf+GZvDIk98SCy\nxjL3hRo+vnrGu8OGI0A50VwQK5e4iG/IeXQoZVnVLfFxII8RrnD7ZTzKb92143X+\nqFk8vlu6obUlISneLS6/Xaw3lsJDvBXisOzvAG9k8yjKqafvWpE3f3Fp8yQ6svBu\nxMsYA3A6SC9NBczpCDb+8FTJ93mpjjkAI6O0ZjfR2nAYq7FV9UiXWq9gCYiLt/tr\nNvRhqMpft9L2y36gPj8i+qwKmD9Ms/Q02bCExv6WA7fl+N80IAfZSsHHRSJmQ2ND\n2b/wOxLBFEPGYBHud0Zqyg1tzLjMUSBKojhc1Z7tQQKBgQC+xnUCAEN/LjVSTUna\nFo31NTHBaL3hOIPbUOpq8yXqh+Qri65O60hLps6N6NN/X/hnsZc6qyvvzxuNyFMm\nB0Lr29rokY5slIi/oDpYL0Xa1HJ1XXtRb9DF9uEapGc7jvDLHGjm13etlXjWU0/u\n+pLdukp7KYfO/2h665D+Pnj/JQKBgQC16j9GAE8+wzo/eMYBTM6mU4vhJaR+dTe4\nhBQPgiSUgJuhnmGHx8kHJwsp5kb1J30pofBS42SM+0dz9n5u5voFf1LXLo/lNEOT\nTqLpuK38FGp2EjXjiD37Rh5Sit2li0QHU8gBzZjAF8Cp+2hn58RAYWVFW2WOE0YV\nezA7wDwCbwKBgQCnQrJFnduPvwCq9u5gElRF/2xvKRkJRJZ+i9PrDuFYXepTr3SU\n5r4M7eO9EbuUupy8tTxlCLxN1aRPy6ny9nza83hbXXqkghnfAGkG9fNl58uuUNaU\n0NcXKdu0kx2bXziIq5Dhi1n3S8yVBJhZa0GmuvUgRIo4lz+QPcZy0m0dLQKBgFAU\nqHn2VOw6IQAj+HZGC4poqOEaIwmQLFFLw1D4Z4X//4LsJ98P8cz2QRHWz1HIam7T\nXOoANBlj3JaN4iaMA3A8Fomnc6zgjwbfzRO6Os0HZ75GUfax2ScuPNb1TpE7d10K\nYrd4fE/DpQqvI8zp2BjHRz969n/OuEFok1kaTNB9AoGBAIu5tNBRQEv1TGV9nH82\na3f2GYAd2/owYrDLXflqZKniMRHA4r0Z9H61CRpSnqWHMxmw9oGwA6eG8LDLS97b\n7eWEUrnfbeF4lXWRMBGZx+NQYZbJBMg0iqhXZH9Z6LUpxFnEcTSMUbRrb5hNdB9b\npT4M7txpqwh2t3TrO0avMP0M\n-----END PRIVATE KEY-----\n",
- "client_email": "firebase-adminsdk-fbsvc@taskboard-pro-aa57d.iam.gserviceaccount.com",
- "client_id": "117401675681900250516",
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
- "token_uri": "https://oauth2.googleapis.com/token",
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
- "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40taskboard-pro-aa57d.iam.gserviceaccount.com",
- "universe_domain": "googleapis.com"
-}
diff --git a/Backend/controllers/authController.js b/Backend/controllers/authController.js
deleted file mode 100644
index 43397a2..0000000
--- a/Backend/controllers/authController.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import jwt from 'jsonwebtoken';
-import User from '../models/userModel.js';
-
-export const generateToken = async (req, res) => {
- try {
- const { uid, email, name, photoURL } = req.body;
-
- if (!uid || !email) {
- return res.status(400).json({ message: 'UID and email are required' });
- }
-
- // Save or update user in the database
- try {
- // Use upsert operation for atomic update or create
- await User.findOneAndUpdate(
- { uid },
- {
- uid,
- email,
- name: name || email.split('@')[0],
- photoURL: photoURL || '',
- updatedAt: Date.now()
- },
- {
- upsert: true,
- new: true,
- runValidators: true
- }
- );
- } catch (dbError) {
- console.error('Database error when saving user:', dbError);
- }
-
- // Generate JWT token
- const token = jwt.sign(
- { uid, email, name },
- process.env.JWT_SECRET,
- { expiresIn: '7d' }
- );
-
- res.status(200).json({ token });
- } catch (error) {
- console.error('Error generating token:', error);
- res.status(500).json({ message: 'Error generating token', error: error.message });
- }
-};
diff --git a/Backend/controllers/automationController.js b/Backend/controllers/automationController.js
deleted file mode 100644
index 8d85099..0000000
--- a/Backend/controllers/automationController.js
+++ /dev/null
@@ -1,241 +0,0 @@
-import Automation from '../models/automationModel.js';
-import Project from '../models/projectModel.js';
-import Task from '../models/taskModel.js';
-import Badge from '../models/badgeModel.js';
-import Notification from '../models/notificationModel.js';
-
-// Create a new automation rule
-export const createAutomation = async (req, res) => {
- try {
- const { projectId, name, trigger, action } = req.body;
- const { uid } = req.user;
-
- // Verify that the project exists
- const project = await Project.findById(projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that the user is a project owner
- const userMember = project.members.find(member => member.userId === uid);
- if (!userMember || userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Only project owners can create automation rules' });
- }
-
- // Validate trigger and action based on type
- if (trigger.type === 'STATUS_CHANGE') {
- // Validate statuses
- if (!project.statuses.includes(trigger.fromStatus) ||
- !project.statuses.includes(trigger.toStatus)) {
- return res.status(400).json({
- message: 'Invalid status in trigger',
- validStatuses: project.statuses
- });
- }
- }
-
- if (action.type === 'MOVE_TASK') {
- if (!project.statuses.includes(action.targetStatus)) {
- return res.status(400).json({
- message: 'Invalid status in action',
- validStatuses: project.statuses
- });
- }
- }
-
- const automation = new Automation({
- projectId,
- name,
- trigger,
- action,
- createdBy: uid
- });
-
- await automation.save();
-
- res.status(201).json(automation);
- } catch (error) {
- console.error('Error creating automation rule:', error);
- res.status(500).json({ message: 'Error creating automation rule', error: error.message });
- }
-};
-
-// Get all automations for a project
-export const getProjectAutomations = async (req, res) => {
- try {
- const { projectId } = req.params;
- const { uid } = req.user;
-
- // Verify that the project exists
- const project = await Project.findById(projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that user is a member of the project
- const isMember = project.members.some(member => member.userId === uid);
- if (!isMember) {
- return res.status(403).json({ message: 'Access denied. You are not a member of this project.' });
- }
-
- const automations = await Automation.find({ projectId });
-
- res.status(200).json(automations);
- } catch (error) {
- console.error('Error fetching automations:', error);
- res.status(500).json({ message: 'Error fetching automations', error: error.message });
- }
-};
-
-// Update an automation rule
-export const updateAutomation = async (req, res) => {
- try {
- const { automationId } = req.params;
- const { name, trigger, action, isActive } = req.body;
- const { uid } = req.user;
-
- const automation = await Automation.findById(automationId);
- if (!automation) {
- return res.status(404).json({ message: 'Automation rule not found' });
- }
-
- // Verify that the project exists
- const project = await Project.findById(automation.projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that the user is a project owner
- const userMember = project.members.find(member => member.userId === uid);
- if (!userMember || userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Only project owners can update automation rules' });
- }
-
- // Update automation fields
- if (name) automation.name = name;
- if (trigger) {
- // Validate trigger based on type
- if (trigger.type === 'STATUS_CHANGE') {
- if (!project.statuses.includes(trigger.fromStatus) ||
- !project.statuses.includes(trigger.toStatus)) {
- return res.status(400).json({
- message: 'Invalid status in trigger',
- validStatuses: project.statuses
- });
- }
- }
- automation.trigger = trigger;
- }
-
- if (action) {
- // Validate action based on type
- if (action.type === 'MOVE_TASK') {
- if (!project.statuses.includes(action.targetStatus)) {
- return res.status(400).json({
- message: 'Invalid status in action',
- validStatuses: project.statuses
- });
- }
- }
- automation.action = action;
- }
-
- if (isActive !== undefined) automation.isActive = isActive;
- automation.updatedAt = Date.now();
-
- await automation.save();
-
- res.status(200).json(automation);
- } catch (error) {
- console.error('Error updating automation rule:', error);
- res.status(500).json({ message: 'Error updating automation rule', error: error.message });
- }
-};
-
-// Delete an automation rule
-export const deleteAutomation = async (req, res) => {
- try {
- const { automationId } = req.params;
- const { uid } = req.user;
-
- const automation = await Automation.findById(automationId);
- if (!automation) {
- return res.status(404).json({ message: 'Automation rule not found' });
- }
-
- // Verify that the project exists
- const project = await Project.findById(automation.projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that the user is a project owner
- const userMember = project.members.find(member => member.userId === uid);
- if (!userMember || userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Only project owners can delete automation rules' });
- }
-
- await Automation.findByIdAndDelete(automationId);
-
- res.status(200).json({ message: 'Automation rule deleted successfully' });
- } catch (error) {
- console.error('Error deleting automation rule:', error);
- res.status(500).json({ message: 'Error deleting automation rule', error: error.message });
- }
-};
-
-// Get all badges for a user
-export const getUserBadges = async (req, res) => {
- try {
- const { uid } = req.user;
-
- const badges = await Badge.find({ userId: uid });
-
- res.status(200).json(badges);
- } catch (error) {
- console.error('Error fetching badges:', error);
- res.status(500).json({ message: 'Error fetching badges', error: error.message });
- }
-};
-
-// Get user notifications
-export const getUserNotifications = async (req, res) => {
- try {
- const { uid } = req.user;
-
- const notifications = await Notification.find({ userId: uid })
- .sort({ createdAt: -1 })
- .limit(50);
-
- res.status(200).json(notifications);
- } catch (error) {
- console.error('Error fetching notifications:', error);
- res.status(500).json({ message: 'Error fetching notifications', error: error.message });
- }
-};
-
-// Mark notification as read
-export const markNotificationRead = async (req, res) => {
- try {
- const { notificationId } = req.params;
- const { uid } = req.user;
-
- const notification = await Notification.findById(notificationId);
- if (!notification) {
- return res.status(404).json({ message: 'Notification not found' });
- }
-
- // Verify ownership
- if (notification.userId !== uid) {
- return res.status(403).json({ message: 'Access denied. This notification belongs to another user.' });
- }
-
- notification.isRead = true;
- await notification.save();
-
- res.status(200).json(notification);
- } catch (error) {
- console.error('Error updating notification:', error);
- res.status(500).json({ message: 'Error updating notification', error: error.message });
- }
-};
diff --git a/Backend/controllers/commentController.js b/Backend/controllers/commentController.js
deleted file mode 100644
index dab1c90..0000000
--- a/Backend/controllers/commentController.js
+++ /dev/null
@@ -1,138 +0,0 @@
-import Comment from '../models/commentModel.js';
-import Task from '../models/taskModel.js';
-import Project from '../models/projectModel.js';
-import User from '../models/userModel.js';
-import { getIO } from '../websocket/socketServer.js';
-
-// Create a new comment
-export const createComment = async (req, res) => {
- try {
- const { taskId, content } = req.body;
- const { uid } = req.user;
-
- // Verify the task exists
- const task = await Task.findById(taskId);
- if (!task) {
- return res.status(404).json({ message: 'Task not found' });
- }
-
- // Verify that the project exists
- const project = await Project.findById(task.projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that user is a member of the project
- const isMember = project.members.some(member => member.userId === uid);
- if (!isMember) {
- return res.status(403).json({ message: 'Access denied. You are not a member of this project.' });
- }
-
- // Get user data for author field
- const user = await User.findOne({ uid });
- if (!user) {
- return res.status(404).json({ message: 'User not found' });
- }
-
- const comment = new Comment({
- taskId,
- projectId: task.projectId,
- content,
- author: {
- userId: uid,
- name: user.name,
- email: user.email,
- photoURL: user.photoURL
- }
- });
-
- await comment.save();
-
- // Emit real-time update via WebSocket
- const io = getIO();
- io.to(`project:${task.projectId}`).emit('comment-added', {
- taskId,
- projectId: task.projectId,
- comment
- });
-
- res.status(201).json(comment);
- } catch (error) {
- console.error('Error creating comment:', error);
- res.status(500).json({ message: 'Error creating comment', error: error.message });
- }
-};
-
-// Get comments for a task
-export const getTaskComments = async (req, res) => {
- try {
- const { taskId } = req.params;
- const { uid } = req.user;
-
- // Verify the task exists
- const task = await Task.findById(taskId);
- if (!task) {
- return res.status(404).json({ message: 'Task not found' });
- }
-
- // Verify that the project exists
- const project = await Project.findById(task.projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that user is a member of the project
- const isMember = project.members.some(member => member.userId === uid);
- if (!isMember) {
- return res.status(403).json({ message: 'Access denied. You are not a member of this project.' });
- }
-
- const comments = await Comment.find({ taskId }).sort({ createdAt: 1 });
-
- res.status(200).json(comments);
- } catch (error) {
- console.error('Error fetching comments:', error);
- res.status(500).json({ message: 'Error fetching comments', error: error.message });
- }
-};
-
-// Delete a comment
-export const deleteComment = async (req, res) => {
- try {
- const { commentId } = req.params;
- const { uid } = req.user;
-
- const comment = await Comment.findById(commentId);
- if (!comment) {
- return res.status(404).json({ message: 'Comment not found' });
- }
-
- // Only allow comment author or project owner to delete
- if (comment.author.userId !== uid) {
- // Check if user is project owner
- const project = await Project.findById(comment.projectId);
- const isOwner = project?.members.some(
- member => member.userId === uid && member.role === 'owner'
- );
-
- if (!isOwner) {
- return res.status(403).json({ message: 'Access denied. You can only delete your own comments.' });
- }
- }
-
- await Comment.findByIdAndDelete(commentId);
-
- // Emit real-time update via WebSocket
- const io = getIO();
- io.to(`project:${comment.projectId}`).emit('comment-deleted', {
- commentId,
- taskId: comment.taskId,
- projectId: comment.projectId
- });
-
- res.status(200).json({ message: 'Comment deleted successfully' });
- } catch (error) {
- console.error('Error deleting comment:', error);
- res.status(500).json({ message: 'Error deleting comment', error: error.message });
- }
-};
diff --git a/Backend/controllers/projectController.js b/Backend/controllers/projectController.js
deleted file mode 100644
index 0388e51..0000000
--- a/Backend/controllers/projectController.js
+++ /dev/null
@@ -1,254 +0,0 @@
-import Project from '../models/projectModel.js';
-import User from '../models/userModel.js';
-import { sendProjectInvitation } from '../services/emailService.js';
-
-// Create a new project
-export const createProject = async (req, res) => {
- try {
- const { title, description } = req.body;
- const { uid, email } = req.user;
-
- const project = new Project({
- title,
- description,
- createdBy: uid,
- members: [
- {
- userId: uid,
- email,
- role: 'owner',
- joinedAt: Date.now()
- }
- ]
- });
-
- await project.save();
-
- res.status(201).json(project);
- } catch (error) {
- console.error('Error creating project:', error);
- res.status(500).json({ message: 'Error creating project', error: error.message });
- }
-};
-
-// Get all projects for current user
-export const getUserProjects = async (req, res) => {
- try {
- const { uid } = req.user;
-
- const projects = await Project.find({
- 'members.userId': uid
- });
-
- res.status(200).json(projects);
- } catch (error) {
- console.error('Error fetching projects:', error);
- res.status(500).json({ message: 'Error fetching projects', error: error.message });
- }
-};
-
-// Get project by ID
-export const getProjectById = async (req, res) => {
- try {
- const { projectId } = req.params;
- const { uid } = req.user;
-
- const project = await Project.findById(projectId);
-
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Check if user is a member of the project
- const isMember = project.members.some(member => member.userId === uid);
-
- if (!isMember) {
- return res.status(403).json({ message: 'Access denied. You are not a member of this project.' });
- }
-
- res.status(200).json(project);
- } catch (error) {
- console.error('Error fetching project:', error);
- res.status(500).json({ message: 'Error fetching project', error: error.message });
- }
-};
-
-// Update project
-export const updateProject = async (req, res) => {
- try {
- const { projectId } = req.params;
- const { title, description } = req.body;
- const { uid } = req.user;
-
- const project = await Project.findById(projectId);
-
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Check if user is a member of the project
- const userMember = project.members.find(member => member.userId === uid);
-
- if (!userMember) {
- return res.status(403).json({ message: 'Access denied. You are not a member of this project.' });
- }
-
- // Only allow updates if user is owner
- if (userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Access denied. Only project owners can update project details.' });
- }
-
- project.title = title || project.title;
- project.description = description || project.description;
- project.updatedAt = Date.now();
-
- await project.save();
-
- res.status(200).json(project);
- } catch (error) {
- console.error('Error updating project:', error);
- res.status(500).json({ message: 'Error updating project', error: error.message });
- }
-};
-
-// Invite user to project
-export const inviteUserToProject = async (req, res) => {
- try {
- const { projectId } = req.params;
- const { email } = req.body;
- const { uid } = req.user;
-
- const project = await Project.findById(projectId);
-
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Check if user is a member of the project with owner role
- const userMember = project.members.find(member => member.userId === uid);
-
- if (!userMember || userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Access denied. Only project owners can invite users.' });
- }
-
- // Check if user is already a member
- const isAlreadyMember = project.members.some(member => member.email === email);
-
- if (isAlreadyMember) {
- return res.status(400).json({ message: 'User is already a member of this project.' });
- }
-
- // Find user by email (if they exist)
- const user = await User.findOne({ email });
-
- // Add user to project members
- project.members.push({
- userId: user ? user.uid : null,
- email,
- role: 'member',
- joinedAt: Date.now()
- });
-
- await project.save();
-
- // Get the inviter's name
- const inviter = await User.findOne({ uid });
-
- // Generate invitation link
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:5173';
- const invitationLink = `${frontendUrl}/projects/${projectId}`;
-
- // Send invitation email
- try {
- if (process.env.EMAIL_USER) {
- await sendProjectInvitation({
- email,
- projectName: project.title,
- inviterName: inviter?.name || 'A project owner',
- invitationLink
- });
- console.log(`Invitation email sent to ${email}`);
- }
- } catch (emailError) {
- console.error('Error sending invitation email:', emailError);
- // Don't fail the request if email sending fails
- }
-
- res.status(200).json({ message: 'User invited successfully', project });
- } catch (error) {
- console.error('Error inviting user to project:', error);
- res.status(500).json({ message: 'Error inviting user to project', error: error.message });
- }
-};
-
-// Remove user from project
-export const removeUserFromProject = async (req, res) => {
- try {
- const { projectId, userId } = req.params;
- const { uid } = req.user;
-
- const project = await Project.findById(projectId);
-
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Check if user is a member of the project with owner role
- const userMember = project.members.find(member => member.userId === uid);
-
- if (!userMember || userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Access denied. Only project owners can remove users.' });
- }
-
- // Cannot remove yourself (owner) from the project
- if (userId === uid) {
- return res.status(400).json({ message: 'Cannot remove project owner. Transfer ownership first.' });
- }
-
- // Remove user from project members
- const memberToRemove = project.members.find(member => member.userId === userId || member.email === userId);
-
- if (!memberToRemove) {
- return res.status(404).json({ message: 'Member not found in project' });
- }
-
- project.members = project.members.filter(member =>
- member.userId !== userId && member.email !== userId
- );
-
- await project.save();
-
- res.status(200).json({ message: 'User removed successfully', project });
- } catch (error) {
- console.error('Error removing user from project:', error);
- res.status(500).json({ message: 'Error removing user from project', error: error.message });
- }
-};
-
-// Delete project
-export const deleteProject = async (req, res) => {
- try {
- const { projectId } = req.params;
- const { uid } = req.user;
-
- const project = await Project.findById(projectId);
-
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Check if user is the project owner
- const isOwner = project.members.some(member => member.userId === uid && member.role === 'owner');
-
- if (!isOwner) {
- return res.status(403).json({ message: 'Access denied. Only project owner can delete a project.' });
- }
-
- await Project.findByIdAndDelete(projectId);
-
- res.status(200).json({ message: 'Project deleted successfully' });
- } catch (error) {
- console.error('Error deleting project:', error);
- res.status(500).json({ message: 'Error deleting project', error: error.message });
- }
-};
diff --git a/Backend/controllers/taskController.js b/Backend/controllers/taskController.js
deleted file mode 100644
index 2861c2f..0000000
--- a/Backend/controllers/taskController.js
+++ /dev/null
@@ -1,434 +0,0 @@
-import Task from '../models/taskModel.js';
-import Project from '../models/projectModel.js';
-import User from '../models/userModel.js';
-import { processTaskAutomations } from '../services/automationService.js';
-import { getIO } from '../websocket/socketServer.js';
-import { sendTaskAssignment } from '../services/emailService.js';
-import { isAuthorizedForTask } from '../utils/taskUtils.js';
-
-// Create a new task
-export const createTask = async (req, res) => {
- try {
- const { title, description, projectId, status, assignee, dueDate } = req.body;
- const { uid } = req.user;
-
- // Verify that the project exists
- const project = await Project.findById(projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that user is a project owner
- const userMember = project.members.find(member => member.userId === uid);
- if (!userMember || userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Access denied. Only project owners can create tasks.' });
- }
-
- // Verify the status is valid for the project
- if (!project.statuses.includes(status)) {
- return res.status(400).json({
- message: 'Invalid status. Must be one of the project statuses.',
- validStatuses: project.statuses
- });
- }
-
- // Find the assignee if provided by email
- let assigneeData = null;
- if (assignee) {
- // Check if the assignee email is a project member
- const assigneeMember = project.members.find(member => member.email === assignee);
-
- if (!assigneeMember) {
- return res.status(400).json({ message: 'Assignee must be a member of the project.' });
- }
-
- assigneeData = {
- userId: assigneeMember.userId,
- email: assigneeMember.email
- };
- }
-
- const task = new Task({
- title,
- description,
- projectId,
- status: status || project.statuses[0], // Default to first status if not provided
- assignee: assigneeData,
- dueDate,
- createdBy: uid
- });
-
- await task.save();
-
- // Send email notification to assignee if task is assigned
- if (assigneeData) {
- try {
- // Get the creator's name
- const creator = await User.findOne({ uid });
-
- // Generate task link
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:5173';
- const taskLink = `${frontendUrl}/projects/${projectId}?task=${task._id}`;
-
- await sendTaskAssignment({
- email: assigneeData.email,
- taskTitle: task.title,
- projectName: project.title,
- assignerName: creator ? creator.name : 'A team member',
- dueDate: task.dueDate,
- taskLink
- });
- console.log(`Task assignment email sent to ${assigneeData.email}`);
- } catch (emailError) {
- console.error('Error sending task assignment email:', emailError);
- // Don't fail the request if email sending fails
- }
- }
-
- // Emit real-time update via WebSocket
- const io = getIO();
- io.to(`project:${task.projectId}`).emit('task-created', task);
-
- res.status(201).json(task);
- } catch (error) {
- console.error('Error creating task:', error);
- res.status(500).json({ message: 'Error creating task', error: error.message });
- }
-};
-
-// Get all tasks for a project
-export const getProjectTasks = async (req, res) => {
- try {
- const { projectId } = req.params;
- const { uid } = req.user;
-
- // Verify that the project exists
- const project = await Project.findById(projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that user is a member of the project
- const isMember = project.members.some(member => member.userId === uid);
- if (!isMember) {
- return res.status(403).json({ message: 'Access denied. You are not a member of this project.' });
- }
-
- const tasks = await Task.find({ projectId });
-
- res.status(200).json(tasks);
- } catch (error) {
- console.error('Error fetching tasks:', error);
- res.status(500).json({ message: 'Error fetching tasks', error: error.message });
- }
-};
-
-// Get a single task by ID
-export const getTaskById = async (req, res) => {
- try {
- const { taskId } = req.params;
- const { uid } = req.user;
-
- const task = await Task.findById(taskId);
- if (!task) {
- return res.status(404).json({ message: 'Task not found' });
- }
-
- // Verify that the project exists
- const project = await Project.findById(task.projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that user is a member of the project
- const isMember = project.members.some(member => member.userId === uid);
- if (!isMember) {
- return res.status(403).json({ message: 'Access denied. You are not a member of this project.' });
- }
-
- res.status(200).json(task);
- } catch (error) {
- console.error('Error fetching task:', error);
- res.status(500).json({ message: 'Error fetching task', error: error.message });
- }
-};
-
-// Update a task
-export const updateTask = async (req, res) => {
- try {
- const { taskId } = req.params;
- const { title, description, status, assignee, dueDate } = req.body;
- const { uid } = req.user;
-
- const task = await Task.findById(taskId);
- if (!task) {
- return res.status(404).json({ message: 'Task not found' });
- }
-
- // Verify that the project exists
- const project = await Project.findById(task.projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Check if user is the task assignee or project owner
- const userMember = project.members.find(member => member.userId === uid);
- const isProjectOwner = userMember && userMember.role === 'owner';
-
- // Only project owners can update most task details
- if (!isProjectOwner) {
- return res.status(403).json({ message: 'Access denied. Only project owners can update task details.' });
- }
-
- // Save the previous state for automation comparison
- const previousTask = { ...task.toObject() };
-
- // Check if assignee is changing
- const isAssigneeChanging = assignee !== undefined &&
- (!task.assignee || task.assignee.email !== assignee);
-
- // Update task fields
- if (title) task.title = title;
- if (description !== undefined) task.description = description;
- if (status) task.status = status;
-
- // Handle assignee update
- let newAssigneeData = null;
- if (assignee !== undefined) {
- if (assignee) {
- // Check if the assignee email is a project member
- const assigneeMember = project.members.find(member => member.email === assignee);
-
- if (!assigneeMember) {
- return res.status(400).json({ message: 'Assignee must be a member of the project.' });
- }
-
- newAssigneeData = {
- userId: assigneeMember.userId,
- email: assigneeMember.email
- };
- task.assignee = newAssigneeData;
- } else {
- task.assignee = null;
- }
- }
-
- if (dueDate !== undefined) task.dueDate = dueDate;
- task.updatedAt = Date.now();
-
- await task.save();
-
- // Send email notification if assignee was changed
- if (isAssigneeChanging && newAssigneeData) {
- try {
- // Get the assigner's name
- const assigner = await User.findOne({ uid });
-
- // Generate task link
- const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:5173';
- const taskLink = `${frontendUrl}/projects/${task.projectId}?task=${task._id}`;
-
- await sendTaskAssignment({
- email: newAssigneeData.email,
- taskTitle: task.title,
- projectName: project.title,
- assignerName: assigner ? assigner.name : 'A team member',
- dueDate: task.dueDate,
- taskLink
- });
- console.log(`Task assignment email sent to ${newAssigneeData.email}`);
- } catch (emailError) {
- console.error('Error sending task assignment email:', emailError);
- // Don't fail the request if email sending fails
- }
- }
-
- // Process automations
- await processTaskAutomations(task, previousTask);
-
- // Emit real-time update via WebSocket
- const io = getIO();
- io.to(`project:${task.projectId}`).emit('task-updated', task);
-
- res.status(200).json(task);
- } catch (error) {
- console.error('Error updating task:', error);
- res.status(500).json({ message: 'Error updating task', error: error.message });
- }
-};
-
-// Update task status (move task)
-export const updateTaskStatus = async (req, res) => {
- try {
- const { taskId } = req.params;
- const { status } = req.body;
- const { uid } = req.user;
-
- console.log(`User ${uid} attempting to update task ${taskId} to status: ${status}`);
-
- const task = await Task.findById(taskId);
- if (!task) {
- return res.status(404).json({ message: 'Task not found' });
- }
-
- // Verify that the project exists
- const project = await Project.findById(task.projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Check if user is authorized (project owner, task assignee, or project member)
- if (!isAuthorizedForTask(task, project, uid)) {
- console.log('Authorization failed for user:', uid);
- return res.status(403).json({
- message: 'Access denied. Only project members can update task status.'
- });
- }
-
- // Verify the status is valid for the project
- if (!project.statuses.includes(status)) {
- return res.status(400).json({
- message: 'Invalid status. Must be one of the project statuses.',
- validStatuses: project.statuses
- });
- }
-
- // Save the previous state for automation comparison
- const previousTask = { ...task.toObject() };
-
- task.status = status;
- task.updatedAt = Date.now();
-
- await task.save();
- console.log(`Task ${taskId} status updated to ${status}`);
-
- // Process automations
- await processTaskAutomations(task, previousTask);
-
- // Emit real-time update via WebSocket
- const io = getIO();
- io.to(`project:${task.projectId}`).emit('task-updated', task);
-
- res.status(200).json(task);
- } catch (error) {
- console.error('Error updating task status:', error);
- res.status(500).json({ message: 'Error updating task status', error: error.message });
- }
-};
-
-// Delete a task
-export const deleteTask = async (req, res) => {
- try {
- const { taskId } = req.params;
- const { uid } = req.user;
-
- const task = await Task.findById(taskId);
- if (!task) {
- return res.status(404).json({ message: 'Task not found' });
- }
-
- // Verify that the project exists
- const project = await Project.findById(task.projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Only project owners can delete tasks
- const userMember = project.members.find(member => member.userId === uid);
- if (!userMember || userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Access denied. Only project owners can delete tasks.' });
- }
-
- await Task.findByIdAndDelete(taskId);
-
- // Emit real-time update via WebSocket
- const io = getIO();
- io.to(`project:${task.projectId}`).emit('task-deleted', { taskId, projectId: task.projectId });
-
- res.status(200).json({ message: 'Task deleted successfully' });
- } catch (error) {
- console.error('Error deleting task:', error);
- res.status(500).json({ message: 'Error deleting task', error: error.message });
- }
-};
-
-// Update project statuses
-export const updateProjectStatuses = async (req, res) => {
- try {
- const { projectId } = req.params;
- const { statuses } = req.body;
- const { uid } = req.user;
-
- const project = await Project.findById(projectId);
- if (!project) {
- return res.status(404).json({ message: 'Project not found' });
- }
-
- // Verify that user has owner role in project
- const userMember = project.members.find(member => member.userId === uid);
- if (!userMember || userMember.role !== 'owner') {
- return res.status(403).json({ message: 'Access denied. Only project owner can update statuses.' });
- }
-
- // Validate statuses array
- if (!Array.isArray(statuses) || statuses.length === 0) {
- return res.status(400).json({ message: 'Statuses must be a non-empty array of strings.' });
- }
-
- // Make sure all tasks with statuses not in the new list are moved to a default status
- const defaultStatus = statuses[0];
- const tasksToUpdate = await Task.find({
- projectId,
- status: { $nin: statuses }
- });
-
- // Update tasks with outdated statuses
- if (tasksToUpdate.length > 0) {
- await Task.updateMany(
- {
- projectId,
- status: { $nin: statuses }
- },
- { status: defaultStatus }
- );
- }
-
- // Update project statuses
- project.statuses = statuses;
- await project.save();
-
- res.status(200).json({
- message: 'Project statuses updated successfully',
- project,
- tasksUpdated: tasksToUpdate.length
- });
- } catch (error) {
- console.error('Error updating project statuses:', error);
- res.status(500).json({ message: 'Error updating project statuses', error: error.message });
- }
-};
-
-// Get tasks assigned to a user
-export const getUserTasks = async (req, res) => {
- try {
- const { uid } = req.user;
-
- const tasks = await Task.find({
- 'assignee.userId': uid
- }).populate({
- path: 'projectId',
- select: 'title members'
- });
-
- // Filter out tasks where the user might no longer be a member of the project
- const filteredTasks = tasks.filter(task => {
- if (!task.projectId) return false;
- return task.projectId.members.some(member => member.userId === uid);
- });
-
- res.status(200).json(filteredTasks);
- } catch (error) {
- console.error('Error fetching user tasks:', error);
- res.status(500).json({ message: 'Error fetching user tasks', error: error.message });
- }
-};
diff --git a/Backend/middleware/auth.js b/Backend/middleware/auth.js
deleted file mode 100644
index fec128c..0000000
--- a/Backend/middleware/auth.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import admin from 'firebase-admin';
-import jwt from 'jsonwebtoken';
-
-export const authenticateToken = async (req, res, next) => {
- const authHeader = req.headers.authorization;
- const token = authHeader && authHeader.split(' ')[1];
-
- if (!token) {
- return res.status(401).json({ message: 'Access denied. No token provided.' });
- }
-
- try {
- // First try to verify as a Firebase token
- try {
- // If Firebase admin is properly initialized
- if (admin.apps.length) {
- const decodedFirebase = await admin.auth().verifyIdToken(token);
- req.user = {
- uid: decodedFirebase.uid,
- email: decodedFirebase.email,
- name: decodedFirebase.name || decodedFirebase.email?.split('@')[0]
- };
- return next();
- }
- } catch (firebaseError) {
- console.log('Not a valid Firebase token, trying JWT');
- }
-
- // If not a Firebase token or Firebase admin not initialized, try as JWT
- const decoded = jwt.verify(token, process.env.JWT_SECRET);
- req.user = decoded;
- next();
- } catch (error) {
- console.error('Error verifying token:', error);
- return res.status(403).json({ message: 'Invalid token.' });
- }
-};
diff --git a/Backend/middleware/simpleAuth.js b/Backend/middleware/simpleAuth.js
deleted file mode 100644
index f929aff..0000000
--- a/Backend/middleware/simpleAuth.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import jwt from 'jsonwebtoken';
-
-export const authenticateToken = (req, res, next) => {
- const authHeader = req.headers.authorization;
- const token = authHeader && authHeader.split(' ')[1];
-
- if (!token) {
- return res.status(401).json({ message: 'Access denied. No token provided.' });
- }
-
- try {
- // Since we can't verify Firebase token without admin SDK, we'll use JWT for simplicity
- const decoded = jwt.verify(token, process.env.JWT_SECRET);
- req.user = decoded;
- next();
- } catch (error) {
- console.error('Error verifying token:', error);
- res.status(403).json({ message: 'Invalid token.' });
- }
-};
diff --git a/Backend/models/automationModel.js b/Backend/models/automationModel.js
deleted file mode 100644
index 9100ff9..0000000
--- a/Backend/models/automationModel.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import mongoose from 'mongoose';
-
-const automationSchema = new mongoose.Schema({
- projectId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Project',
- required: true
- },
- name: {
- type: String,
- required: true,
- trim: true
- },
- trigger: {
- type: {
- type: String,
- required: true,
- enum: ['STATUS_CHANGE', 'ASSIGNMENT_CHANGE', 'DUE_DATE_PASSED']
- },
- // For STATUS_CHANGE
- fromStatus: String,
- toStatus: String,
- // For ASSIGNMENT_CHANGE
- assigneeId: String,
- assigneeEmail: String,
- // For DUE_DATE_PASSED
- // No additional fields needed
- },
- action: {
- type: {
- type: String,
- required: true,
- enum: ['ASSIGN_BADGE', 'MOVE_TASK', 'SEND_NOTIFICATION']
- },
- // For ASSIGN_BADGE
- badgeName: String,
- // For MOVE_TASK
- targetStatus: String,
- // For SEND_NOTIFICATION
- notificationText: String,
- notifyAssignee: {
- type: Boolean,
- default: true
- },
- notifyCreator: {
- type: Boolean,
- default: false
- },
- notifyProjectOwners: {
- type: Boolean,
- default: false
- }
- },
- isActive: {
- type: Boolean,
- default: true
- },
- createdBy: {
- type: String,
- ref: 'User',
- required: true
- },
- createdAt: {
- type: Date,
- default: Date.now
- },
- updatedAt: {
- type: Date,
- default: Date.now
- }
-});
-
-// Update the updatedAt field on save
-automationSchema.pre('save', function(next) {
- this.updatedAt = Date.now();
- next();
-});
-
-const Automation = mongoose.model('Automation', automationSchema);
-
-export default Automation;
diff --git a/Backend/models/badgeModel.js b/Backend/models/badgeModel.js
deleted file mode 100644
index 8d2dcb2..0000000
--- a/Backend/models/badgeModel.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import mongoose from 'mongoose';
-
-const badgeSchema = new mongoose.Schema({
- userId: {
- type: String,
- ref: 'User',
- required: true
- },
- name: {
- type: String,
- required: true,
- trim: true
- },
- description: {
- type: String,
- trim: true
- },
- projectId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Project'
- },
- taskId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Task'
- },
- awardedAt: {
- type: Date,
- default: Date.now
- }
-});
-
-const Badge = mongoose.model('Badge', badgeSchema);
-
-export default Badge;
diff --git a/Backend/models/commentModel.js b/Backend/models/commentModel.js
deleted file mode 100644
index 5bf9085..0000000
--- a/Backend/models/commentModel.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import mongoose from 'mongoose';
-
-const commentSchema = new mongoose.Schema({
- taskId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Task',
- required: true
- },
- projectId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Project',
- required: true
- },
- content: {
- type: String,
- required: true,
- trim: true
- },
- author: {
- userId: {
- type: String,
- required: true
- },
- name: {
- type: String,
- required: true
- },
- email: {
- type: String,
- required: true
- },
- photoURL: String
- },
- createdAt: {
- type: Date,
- default: Date.now
- },
- updatedAt: {
- type: Date,
- default: Date.now
- }
-});
-
-// Update the updatedAt field on save
-commentSchema.pre('save', function(next) {
- this.updatedAt = Date.now();
- next();
-});
-
-const Comment = mongoose.model('Comment', commentSchema);
-
-export default Comment;
diff --git a/Backend/models/notificationModel.js b/Backend/models/notificationModel.js
deleted file mode 100644
index c92c977..0000000
--- a/Backend/models/notificationModel.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import mongoose from 'mongoose';
-
-const notificationSchema = new mongoose.Schema({
- userId: {
- type: String,
- ref: 'User',
- required: true
- },
- title: {
- type: String,
- required: true,
- trim: true
- },
- message: {
- type: String,
- required: true,
- trim: true
- },
- type: {
- type: String,
- enum: ['TASK', 'PROJECT', 'BADGE', 'SYSTEM'],
- default: 'SYSTEM'
- },
- relatedProjectId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Project'
- },
- relatedTaskId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Task'
- },
- isRead: {
- type: Boolean,
- default: false
- },
- createdAt: {
- type: Date,
- default: Date.now
- }
-});
-
-const Notification = mongoose.model('Notification', notificationSchema);
-
-export default Notification;
diff --git a/Backend/models/projectModel.js b/Backend/models/projectModel.js
deleted file mode 100644
index 7d88e4d..0000000
--- a/Backend/models/projectModel.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import mongoose from 'mongoose';
-
-const projectSchema = new mongoose.Schema({
- title: {
- type: String,
- required: true,
- trim: true
- },
- description: {
- type: String,
- trim: true
- },
- createdBy: {
- type: String,
- required: true,
- ref: 'User'
- },
- members: [{
- userId: {
- type: String,
- ref: 'User'
- },
- email: {
- type: String,
- required: true
- },
- role: {
- type: String,
- enum: ['owner', 'member'],
- default: 'member'
- },
- joinedAt: {
- type: Date,
- default: Date.now
- }
- }],
- statuses: {
- type: [String],
- default: ['To Do', 'In Progress', 'Done']
- },
- createdAt: {
- type: Date,
- default: Date.now
- },
- updatedAt: {
- type: Date,
- default: Date.now
- }
-});
-
-projectSchema.pre('save', function(next) {
- this.updatedAt = Date.now();
- next();
-});
-
-const Project = mongoose.model('Project', projectSchema);
-
-export default Project;
diff --git a/Backend/models/taskModel.js b/Backend/models/taskModel.js
deleted file mode 100644
index 69e83b0..0000000
--- a/Backend/models/taskModel.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import mongoose from 'mongoose';
-
-const taskSchema = new mongoose.Schema({
- title: {
- type: String,
- required: true,
- trim: true
- },
- description: {
- type: String,
- trim: true
- },
- projectId: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Project',
- required: true
- },
- status: {
- type: String,
- required: true,
- default: 'To Do',
- enum: ['To Do', 'In Progress', 'Done']
- },
- priority: {
- type: String,
- enum: ['low', 'medium', 'high'],
- default: 'medium'
- },
- assignee: {
- userId: {
- type: String,
- ref: 'User'
- },
- email: {
- type: String
- },
- name: {
- type: String
- },
- avatar: {
- type: String
- }
- },
- labels: [{
- type: String,
- trim: true,
- enum: ['design', 'development', 'marketing', 'research', 'testing', 'planning', 'ui/ux', 'backend', 'frontend']
- }],
- dueDate: {
- type: Date
- },
- createdBy: {
- type: String,
- required: true,
- ref: 'User'
- },
- createdAt: {
- type: Date,
- default: Date.now
- },
- updatedAt: {
- type: Date,
- default: Date.now
- }
-});
-
-taskSchema.pre('save', function(next) {
- this.updatedAt = Date.now();
- next();
-});
-
-const Task = mongoose.model('Task', taskSchema);
-
-export default Task;
diff --git a/Backend/models/userModel.js b/Backend/models/userModel.js
deleted file mode 100644
index c285c1c..0000000
--- a/Backend/models/userModel.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import mongoose from 'mongoose';
-
-const userSchema = new mongoose.Schema({
- uid: {
- type: String,
- required: true,
- unique: true
- },
- email: {
- type: String,
- required: true,
- unique: true
- },
- name: {
- type: String,
- required: true
- },
- photoURL: {
- type: String,
- default: ''
- },
- badges: {
- total: {
- type: Number,
- default: 0
- },
- types: {
- taskMaster: {
- type: Number,
- default: 0
- },
- problemSolver: {
- type: Number,
- default: 0
- },
- teamPlayer: {
- type: Number,
- default: 0
- },
- productivityStar: {
- type: Number,
- default: 0
- },
- fastCompleter: {
- type: Number,
- default: 0
- }
- }
- },
- createdAt: {
- type: Date,
- default: Date.now
- },
- updatedAt: {
- type: Date,
- default: Date.now
- }
-});
-
-// Update the updatedAt field on save
-userSchema.pre('save', function(next) {
- this.updatedAt = Date.now();
- next();
-});
-
-// Add some debugging to track when users are saved
-userSchema.post('save', function(doc) {
- console.log(`User saved successfully: ${doc.email} (${doc.uid})`);
-});
-
-const User = mongoose.model('User', userSchema);
-
-export default User;
diff --git a/Backend/package.json b/Backend/package.json
deleted file mode 100644
index 489bb3f..0000000
--- a/Backend/package.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "name": "taskboard-pro-backend",
- "version": "1.0.0",
- "description": "Backend for TaskBoard Pro - Project Collaboration Platform",
- "main": "server.js",
- "type": "module",
- "scripts": {
- "start": "node server.js",
- "dev": "nodemon server.js",
- "test": "echo \"Error: no test specified\" && exit 1",
- "check-users": "node check-users.js"
- },
- "keywords": [
- "project",
- "management",
- "collaboration",
- "tasks"
- ],
- "author": "",
- "license": "ISC",
- "dependencies": {
- "cors": "^2.8.5",
- "dotenv": "^16.4.1",
- "express": "^4.18.2",
- "firebase-admin": "^11.11.1",
- "jsonwebtoken": "^9.0.2",
- "mongoose": "^8.15.0",
- "morgan": "^1.10.0",
- "node-schedule": "^2.1.1",
- "nodemailer": "^6.9.9",
- "socket.io": "^4.7.2"
- },
- "devDependencies": {
- "nodemon": "^3.0.3"
- }
-}
diff --git a/Backend/routes/authRoutes.js b/Backend/routes/authRoutes.js
deleted file mode 100644
index 72ae64b..0000000
--- a/Backend/routes/authRoutes.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import express from 'express';
-import jwt from 'jsonwebtoken';
-import { authenticateToken } from '../middleware/auth.js';
-import User from '../models/userModel.js';
-
-const router = express.Router();
-
-// Generate and return JWT token for Firebase authenticated users
-router.post('/token', async (req, res) => {
- try {
- const { uid, email, name, photoURL } = req.body;
-
- if (!uid || !email) {
- return res.status(400).json({ message: 'UID and email are required' });
- }
-
- // Generate JWT token
- const token = jwt.sign(
- { uid, email, name },
- process.env.JWT_SECRET,
- { expiresIn: '7d' }
- );
-
- // Save or update user in database
- try {
- await User.findOneAndUpdate(
- { uid },
- {
- uid,
- email,
- name: name || email.split('@')[0],
- photoURL: photoURL || '',
- updatedAt: Date.now()
- },
- {
- upsert: true,
- new: true,
- runValidators: true
- }
- );
- } catch (dbError) {
- console.error('Error saving user to database:', dbError);
- // Continue even if DB operation fails
- }
-
- res.status(200).json({ token });
- } catch (error) {
- console.error('Token generation error:', error);
- res.status(500).json({ message: 'Error generating token', error: error.message });
- }
-});
-
-// Test endpoint to verify authentication
-router.get('/test', authenticateToken, (req, res) => {
- res.json({
- message: 'Authentication successful',
- user: {
- uid: req.user.uid,
- email: req.user.email,
- name: req.user.name
- }
- });
-});
-
-export default router;
diff --git a/Backend/routes/automationRoutes.js b/Backend/routes/automationRoutes.js
deleted file mode 100644
index c3e4c8f..0000000
--- a/Backend/routes/automationRoutes.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import express from 'express';
-import {
- createAutomation,
- getProjectAutomations,
- updateAutomation,
- deleteAutomation,
- getUserBadges,
- getUserNotifications,
- markNotificationRead
-} from '../controllers/automationController.js';
-import { authenticateToken } from '../middleware/auth.js';
-
-const router = express.Router();
-
-// All routes need authentication
-router.use(authenticateToken);
-
-// Automation CRUD routes
-router.post('/', createAutomation);
-router.get('/project/:projectId', getProjectAutomations);
-router.put('/:automationId', updateAutomation);
-router.delete('/:automationId', deleteAutomation);
-
-// Badge routes
-router.get('/badges', getUserBadges);
-
-// Notification routes
-router.get('/notifications', getUserNotifications);
-router.patch('/notifications/:notificationId/read', markNotificationRead);
-
-export default router;
diff --git a/Backend/routes/commentRoutes.js b/Backend/routes/commentRoutes.js
deleted file mode 100644
index 84d491c..0000000
--- a/Backend/routes/commentRoutes.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import express from 'express';
-import {
- createComment,
- getTaskComments,
- deleteComment
-} from '../controllers/commentController.js';
-import { authenticateToken } from '../middleware/auth.js';
-
-const router = express.Router();
-
-// All routes need authentication
-router.use(authenticateToken);
-
-// Comment routes
-router.post('/', createComment);
-router.get('/task/:taskId', getTaskComments);
-router.delete('/:commentId', deleteComment);
-
-export default router;
diff --git a/Backend/routes/projectRoutes.js b/Backend/routes/projectRoutes.js
deleted file mode 100644
index 716fd09..0000000
--- a/Backend/routes/projectRoutes.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import express from 'express';
-import {
- createProject,
- getUserProjects,
- getProjectById,
- updateProject,
- inviteUserToProject,
- removeUserFromProject,
- deleteProject
-} from '../controllers/projectController.js';
-import { authenticateToken } from '../middleware/auth.js';
-
-const router = express.Router();
-
-// All routes need authentication
-router.use(authenticateToken);
-
-// Project CRUD routes
-router.post('/', createProject);
-router.get('/', getUserProjects);
-router.get('/:projectId', getProjectById);
-router.put('/:projectId', updateProject);
-router.delete('/:projectId', deleteProject);
-
-// Project member management
-router.post('/:projectId/invite', inviteUserToProject);
-router.delete('/:projectId/members/:userId', removeUserFromProject);
-
-export default router;
diff --git a/Backend/routes/taskRoutes.js b/Backend/routes/taskRoutes.js
deleted file mode 100644
index 636a746..0000000
--- a/Backend/routes/taskRoutes.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import express from 'express';
-import {
- createTask,
- getProjectTasks,
- getTaskById,
- updateTask,
- updateTaskStatus,
- deleteTask,
- updateProjectStatuses,
- getUserTasks
-} from '../controllers/taskController.js';
-import { authenticateToken } from '../middleware/auth.js';
-
-const router = express.Router();
-
-// All routes require authentication
-router.use(authenticateToken);
-
-// Task CRUD routes
-router.post('/', createTask);
-router.get('/project/:projectId', getProjectTasks);
-router.get('/user/assigned', getUserTasks); // Add this new route
-router.get('/:taskId', getTaskById);
-router.put('/:taskId', updateTask);
-router.patch('/:taskId/status', updateTaskStatus);
-router.delete('/:taskId', deleteTask);
-
-// Project statuses routes
-router.put('/project/:projectId/statuses', updateProjectStatuses);
-
-export default router;
diff --git a/Backend/routes/userRoutes.js b/Backend/routes/userRoutes.js
deleted file mode 100644
index 77f7751..0000000
--- a/Backend/routes/userRoutes.js
+++ /dev/null
@@ -1,114 +0,0 @@
-import express from 'express';
-import User from '../models/userModel.js';
-import Task from '../models/taskModel.js';
-import Badge from '../models/badgeModel.js';
-import { authenticateToken } from '../middleware/auth.js';
-
-const router = express.Router();
-
-// Create or update user
-router.post('/', authenticateToken, async (req, res) => {
- try {
- const { name, email, photoURL, uid } = req.body;
-
- // Verify the token's uid matches the request body uid
- if (req.user.uid !== uid) {
- return res.status(403).json({ message: 'Unauthorized: Token doesn\'t match the user' });
- }
-
- // Find user by uid and update, or create if doesn't exist
- const user = await User.findOneAndUpdate(
- { uid },
- { name, email, photoURL, uid },
- { new: true, upsert: true }
- );
-
- res.status(200).json(user);
- } catch (error) {
- console.error('Error creating/updating user:', error);
- res.status(500).json({ message: 'Error creating/updating user', error: error.message });
- }
-});
-
-// Get user profile
-router.get('/me', authenticateToken, async (req, res) => {
- try {
- const user = await User.findOne({ uid: req.user.uid });
-
- if (!user) {
- return res.status(404).json({ message: 'User not found' });
- }
-
- res.status(200).json(user);
- } catch (error) {
- console.error('Error fetching user:', error);
- res.status(500).json({ message: 'Error fetching user', error: error.message });
- }
-});
-
-// Get user statistics
-router.get('/me/stats', authenticateToken, async (req, res) => {
- try {
- const { uid } = req.user;
-
- // Get tasks completed by user
- const completedTasks = await Task.find({
- 'assignee.userId': uid,
- status: 'Done'
- }).countDocuments();
-
- // Get total badges earned
- const totalBadges = await Badge.find({
- userId: uid
- }).countDocuments();
-
- // Get projects user is a member of
- const user = await User.findOne({ uid });
-
- res.status(200).json({
- tasksCompleted: completedTasks,
- badgesEarned: totalBadges,
- userInfo: {
- name: user.name,
- email: user.email,
- photoURL: user.photoURL,
- badges: user.badges || { total: 0, types: {} }
- }
- });
- } catch (error) {
- console.error('Error fetching user stats:', error);
- res.status(500).json({ message: 'Error fetching user statistics', error: error.message });
- }
-});
-
-// Search users by email
-router.get('/search', authenticateToken, async (req, res) => {
- try {
- const { email } = req.query;
-
- if (!email) {
- return res.status(400).json({ message: 'Email query parameter is required' });
- }
-
- // Find users that match or partially match the email
- const users = await User.find({
- email: { $regex: email, $options: 'i' }
- }).limit(10);
-
- // Return users with limited fields for security
- const safeUsers = users.map(user => ({
- id: user._id,
- uid: user.uid,
- name: user.name,
- email: user.email,
- photoURL: user.photoURL
- }));
-
- res.status(200).json(safeUsers);
- } catch (error) {
- console.error('Error searching users:', error);
- res.status(500).json({ message: 'Error searching users', error: error.message });
- }
-});
-
-export default router;
diff --git a/Backend/server.js b/Backend/server.js
deleted file mode 100644
index eefd734..0000000
--- a/Backend/server.js
+++ /dev/null
@@ -1,163 +0,0 @@
-import express from 'express';
-import mongoose from 'mongoose';
-import dotenv from 'dotenv';
-import cors from 'cors';
-import morgan from 'morgan';
-import http from 'http';
-import jwt from 'jsonwebtoken';
-import userRoutes from './routes/userRoutes.js';
-import projectRoutes from './routes/projectRoutes.js';
-import taskRoutes from './routes/taskRoutes.js';
-import automationRoutes from './routes/automationRoutes.js';
-import commentRoutes from './routes/commentRoutes.js';
-import authRoutes from './routes/authRoutes.js';
-import { authenticateToken } from './middleware/auth.js';
-import { setupDueDateAutomations } from './services/automationService.js';
-import { initSocketServer } from './websocket/socketServer.js';
-
-// Load environment variables
-dotenv.config();
-
-// Initialize Express app
-const app = express();
-const PORT = process.env.PORT || 5000;
-
-// Middleware
-app.use(cors());
-app.use(express.json());
-app.use(morgan('dev'));
-
-// Create HTTP server
-const server = http.createServer(app);
-
-// Initialize socket server
-initSocketServer(server);
-
-// Enhanced database connection with retry logic
-const connectDB = async () => {
- const MAX_RETRIES = 5;
- let retries = 0;
- let connected = false;
-
- while (retries < MAX_RETRIES && !connected) {
- try {
- console.log(`MongoDB connection attempt ${retries + 1}...`);
- await mongoose.connect(process.env.MONGODB_URI);
- console.log('Connected to MongoDB');
- connected = true;
- } catch (err) {
- console.error('MongoDB connection error:', err);
- retries++;
-
- if (retries < MAX_RETRIES) {
- console.log(`Retrying in ${retries * 2} seconds...`);
- await new Promise(resolve => setTimeout(resolve, retries * 2000));
- }
- }
- }
-
- if (!connected) {
- console.error(`Failed to connect to MongoDB after ${MAX_RETRIES} attempts`);
- process.exit(1);
- }
-
- return mongoose.connection;
-};
-
-// Call connectDB before setting up routes
-connectDB().then(() => {
- // Routes setup
-
- // Auth routes - Generate token for testing
- app.post('/api/auth/token', (req, res) => {
- const { uid, email, name } = req.body;
-
- if (!uid || !email) {
- return res.status(400).json({ message: 'Missing required fields' });
- }
-
- try {
- const token = jwt.sign(
- { uid, email, name },
- process.env.JWT_SECRET,
- { expiresIn: '7d' }
- );
-
- console.log('Token generated for:', email);
- res.json({ token });
- } catch (error) {
- console.error('Token generation error:', error);
- res.status(500).json({ message: 'Error generating token' });
- }
- });
-
- // Routes
- app.get('/api/health', (req, res) => {
- res.status(200).json({ status: 'OK', message: 'Server is running' });
- });
-
- // API routes
- app.use('/api/auth', authRoutes);
- app.use('/api/users', userRoutes);
- app.use('/api/projects', projectRoutes);
- app.use('/api/tasks', taskRoutes);
- app.use('/api/automations', automationRoutes);
- app.use('/api/comments', commentRoutes);
-
- // Test authentication route
- app.get('/api/auth/test', authenticateToken, (req, res) => {
- res.json({ message: 'Authentication successful', user: req.user });
- });
-
- // Add a test endpoint for user creation
- app.post('/api/test/create-user', async (req, res) => {
- try {
- const { uid, email, name } = req.body;
-
- if (!uid || !email) {
- return res.status(400).json({ message: 'UID and email are required' });
- }
-
- const User = mongoose.model('User');
- const user = new User({
- uid,
- email,
- name: name || email.split('@')[0]
- });
-
- await user.save();
-
- res.status(201).json({
- message: 'Test user created successfully',
- user: {
- uid: user.uid,
- email: user.email,
- name: user.name
- }
- });
- } catch (error) {
- console.error('Error creating test user:', error);
- res.status(500).json({ message: 'Error creating test user', error: error.toString() });
- }
- });
-
- // Error handling middleware
- app.use((err, req, res, next) => {
- console.error(err.stack);
- res.status(500).json({
- message: err.message || 'Something went wrong on the server',
- error: process.env.NODE_ENV === 'production' ? {} : err
- });
- });
-
- // Start server
- server.listen(PORT, () => {
- console.log(`Server running on port ${PORT}`);
- console.log(`API available at http://localhost:${PORT}/api`);
-
- // Set up the automation scheduler
- setupDueDateAutomations();
- });
-}).catch(err => {
- console.error('Failed to start server due to database connection issues:', err);
-});
diff --git a/Backend/services/automationService.js b/Backend/services/automationService.js
deleted file mode 100644
index 20325fe..0000000
--- a/Backend/services/automationService.js
+++ /dev/null
@@ -1,251 +0,0 @@
-import Automation from '../models/automationModel.js';
-import Task from '../models/taskModel.js';
-import Project from '../models/projectModel.js';
-import Badge from '../models/badgeModel.js';
-import Notification from '../models/notificationModel.js';
-import User from '../models/userModel.js';
-import { scheduleJob } from 'node-schedule';
-
-// Process the automations for a task
-export const processTaskAutomations = async (task, previousTask = null) => {
- try {
- // Get the project
- const project = await Project.findById(task.projectId);
- if (!project) return;
-
- // Get active automations for this project
- const automations = await Automation.find({
- projectId: task.projectId,
- isActive: true
- });
-
- if (!automations || automations.length === 0) return;
-
- // Process each automation
- for (const automation of automations) {
- let shouldExecute = false;
-
- // Check if the trigger conditions are met
- switch (automation.trigger.type) {
- case 'STATUS_CHANGE':
- if (previousTask &&
- previousTask.status === automation.trigger.fromStatus &&
- task.status === automation.trigger.toStatus) {
- shouldExecute = true;
- }
- break;
-
- case 'ASSIGNMENT_CHANGE':
- if (previousTask &&
- (!previousTask.assignee || previousTask.assignee.userId !== automation.trigger.assigneeId) &&
- task.assignee &&
- (task.assignee.userId === automation.trigger.assigneeId ||
- task.assignee.email === automation.trigger.assigneeEmail)) {
- shouldExecute = true;
- }
- break;
-
- case 'DUE_DATE_PASSED':
- // This is triggered by a scheduler, not here directly
- break;
- }
-
- // If trigger conditions are met, execute the action
- if (shouldExecute) {
- await executeAutomationAction(automation, task, project);
- }
- }
- } catch (error) {
- console.error('Error processing automations:', error);
- }
-};
-
-// Execute an automation action
-const executeAutomationAction = async (automation, task, project) => {
- try {
- switch (automation.action.type) {
- case 'ASSIGN_BADGE':
- await assignBadge(task, automation);
- break;
-
- case 'MOVE_TASK':
- await moveTask(task, automation);
- break;
-
- case 'SEND_NOTIFICATION':
- await sendNotification(task, project, automation);
- break;
- }
- } catch (error) {
- console.error('Error executing automation action:', error);
- }
-};
-
-// Assign a badge to the task assignee
-const assignBadge = async (task, automation) => {
- try {
- if (!task.assignee || !task.assignee.userId) return;
-
- // Create the badge
- const badgeName = automation.action.badgeName || 'Task Completed';
-
- const badge = new Badge({
- userId: task.assignee.userId,
- name: badgeName,
- description: `Awarded for completing task: ${task.title}`,
- projectId: task.projectId,
- taskId: task._id
- });
-
- await badge.save();
-
- // Update user badge counters
- const badgeType = getBadgeType(badgeName);
- if (badgeType) {
- await User.findOneAndUpdate(
- { uid: task.assignee.userId },
- {
- $inc: {
- 'badges.total': 1,
- [`badges.types.${badgeType}`]: 1
- }
- }
- );
- }
-
- // Create a notification for the badge
- const notification = new Notification({
- userId: task.assignee.userId,
- title: 'New Badge Earned!',
- message: `You earned the "${badge.name}" badge for task: ${task.title}`,
- type: 'BADGE',
- relatedProjectId: task.projectId,
- relatedTaskId: task._id
- });
-
- await notification.save();
-
- } catch (error) {
- console.error('Error assigning badge:', error);
- }
-};
-
-// Helper function to map badge names to badge types
-const getBadgeType = (badgeName) => {
- const lowerName = badgeName.toLowerCase();
-
- if (lowerName.includes('task master')) return 'taskMaster';
- if (lowerName.includes('problem solver')) return 'problemSolver';
- if (lowerName.includes('team player')) return 'teamPlayer';
- if (lowerName.includes('productivity')) return 'productivityStar';
- if (lowerName.includes('fast') || lowerName.includes('quick')) return 'fastCompleter';
-
- // Default to task master for generic badges
- return 'taskMaster';
-};
-
-// Move a task to a different status
-const moveTask = async (task, automation) => {
- try {
- // Update the task status
- task.status = automation.action.targetStatus;
- await task.save();
-
- // Create a notification for the task creator
- const notification = new Notification({
- userId: task.createdBy,
- title: 'Task Status Changed',
- message: `Task "${task.title}" was moved to "${automation.action.targetStatus}" automatically.`,
- type: 'TASK',
- relatedProjectId: task.projectId,
- relatedTaskId: task._id
- });
-
- await notification.save();
-
- } catch (error) {
- console.error('Error moving task:', error);
- }
-};
-
-// Send a notification
-const sendNotification = async (task, project, automation) => {
- try {
- const notificationTargets = [];
-
- // Determine who should be notified
- if (automation.action.notifyAssignee && task.assignee && task.assignee.userId) {
- notificationTargets.push(task.assignee.userId);
- }
-
- if (automation.action.notifyCreator) {
- notificationTargets.push(task.createdBy);
- }
-
- if (automation.action.notifyProjectOwners) {
- // Get project owners
- const ownerMembers = project.members.filter(member => member.role === 'owner');
- ownerMembers.forEach(member => {
- if (member.userId) notificationTargets.push(member.userId);
- });
- }
-
- // Remove duplicates
- const uniqueTargets = [...new Set(notificationTargets)];
-
- // Create notifications for each target
- for (const userId of uniqueTargets) {
- const notification = new Notification({
- userId,
- title: 'Task Notification',
- message: automation.action.notificationText || `Notification about task: ${task.title}`,
- type: 'TASK',
- relatedProjectId: task.projectId,
- relatedTaskId: task._id
- });
-
- await notification.save();
- }
-
- } catch (error) {
- console.error('Error sending notification:', error);
- }
-};
-
-// Set up a scheduler for due date passed automations
-export const setupDueDateAutomations = () => {
- // Run daily at midnight
- const job = scheduleJob('0 0 * * *', async () => {
- try {
- const today = new Date();
- today.setHours(0, 0, 0, 0);
-
- // Find tasks with due date in the past
- const overdueTasks = await Task.find({
- dueDate: { $lt: today }
- });
-
- for (const task of overdueTasks) {
- const automations = await Automation.find({
- projectId: task.projectId,
- isActive: true,
- 'trigger.type': 'DUE_DATE_PASSED'
- });
-
- if (automations.length > 0) {
- const project = await Project.findById(task.projectId);
-
- for (const automation of automations) {
- await executeAutomationAction(automation, task, project);
- }
- }
- }
- } catch (error) {
- console.error('Error processing due date automations:', error);
- }
- });
-
- console.log('Due date automation scheduler set up');
-
- return job;
-};
diff --git a/Backend/services/emailService.js b/Backend/services/emailService.js
deleted file mode 100644
index 90c4166..0000000
--- a/Backend/services/emailService.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import nodemailer from 'nodemailer';
-import dotenv from 'dotenv';
-
-dotenv.config();
-
-// Create a transporter object using SMTP transport
-const transporter = nodemailer.createTransport({
- service: process.env.EMAIL_SERVICE || 'gmail',
- auth: {
- user: process.env.EMAIL_USER,
- pass: process.env.EMAIL_PASSWORD
- }
-});
-
-/**
- * Send an email
- * @param {Object} options - Email options
- * @param {string} options.to - Recipient email
- * @param {string} options.subject - Email subject
- * @param {string} options.html - Email body in HTML format
- * @returns {Promise} - Promise that resolves with the send info
- */
-export const sendEmail = async (options) => {
- try {
- const mailOptions = {
- from: `"TaskBoard Pro" <${process.env.EMAIL_USER}>`,
- to: options.to,
- subject: options.subject,
- html: options.html
- };
-
- const info = await transporter.sendMail(mailOptions);
- console.log(`Email sent: ${info.messageId}`);
- return info;
- } catch (error) {
- console.error('Error sending email:', error);
- throw error;
- }
-};
-
-/**
- * Send project invitation email
- * @param {Object} options - Email details
- * @param {string} options.email - Recipient email
- * @param {string} options.projectName - Project name
- * @param {string} options.inviterName - Name of the person who sent the invitation
- * @param {string} options.invitationLink - Link to accept the invitation
- */
-export const sendProjectInvitation = async ({ email, projectName, inviterName, invitationLink }) => {
- const subject = `You've been invited to join "${projectName}" on TaskBoard Pro`;
-
- const html = `
-
-
Project Invitation
-
Hello,
-
${inviterName} has invited you to collaborate on the project "${projectName}" on TaskBoard Pro.
-
Click the button below to join the project and start collaborating:
-
-
If the button doesn't work, you can also copy and paste this link into your browser:
-
${invitationLink}
-
-
- This is an automated message from TaskBoard Pro. Please do not reply to this email.
-
-
- `;
-
- return sendEmail({ to: email, subject, html });
-};
-
-/**
- * Send task assignment notification email
- * @param {Object} options - Email details
- * @param {string} options.email - Recipient email
- * @param {string} options.taskTitle - Task title
- * @param {string} options.projectName - Project name
- * @param {string} options.assignerName - Name of person who assigned the task
- * @param {string} options.dueDate - Task due date (optional)
- * @param {string} options.taskLink - Link to the task
- */
-export const sendTaskAssignment = async ({ email, taskTitle, projectName, assignerName, dueDate, taskLink }) => {
- const subject = `Task assigned to you: "${taskTitle}" on TaskBoard Pro`;
-
- let dueDateText = '';
- if (dueDate) {
- dueDateText = `Due date: ${new Date(dueDate).toLocaleDateString()}
`;
- }
-
- const html = `
-
-
New Task Assignment
-
Hello,
-
${assignerName} has assigned a task to you on TaskBoard Pro.
-
-
Task: ${taskTitle}
-
Project: ${projectName}
- ${dueDateText}
-
-
Click the button below to view the task details:
-
-
-
- This is an automated message from TaskBoard Pro. Please do not reply to this email.
-
-
- `;
-
- return sendEmail({ to: email, subject, html });
-};
diff --git a/Backend/utils/taskUtils.js b/Backend/utils/taskUtils.js
deleted file mode 100644
index f46ae29..0000000
--- a/Backend/utils/taskUtils.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Verify if a user is authorized to modify a task
- * @param {Object} task - The task document
- * @param {Object} project - The project document
- * @param {String} uid - The user's ID
- * @returns {Boolean} - Whether the user is authorized
- */
-export const isAuthorizedForTask = (task, project, uid) => {
- // Check if user is project owner
- const isProjectOwner = project.members.some(
- member => member.userId === uid && member.role === 'owner'
- );
-
- // Check if user is task assignee
- const isTaskAssignee = task.assignee && task.assignee.userId === uid;
-
- // Check if user is project member
- const isProjectMember = project.members.some(
- member => member.userId === uid
- );
-
- // Allow project owners and assignees to do anything
- if (isProjectOwner || isTaskAssignee) return true;
-
- // Allow project members to view and update status
- return isProjectMember;
-};
diff --git a/Backend/websocket/socketServer.js b/Backend/websocket/socketServer.js
deleted file mode 100644
index 2ec159b..0000000
--- a/Backend/websocket/socketServer.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import { Server } from 'socket.io';
-import jwt from 'jsonwebtoken';
-
-let io;
-
-export const initSocketServer = (server) => {
- io = new Server(server, {
- cors: {
- origin: process.env.FRONTEND_URL || 'http://localhost:5173',
- methods: ['GET', 'POST']
- }
- });
-
- // Socket authentication middleware
- io.use((socket, next) => {
- const token = socket.handshake.auth.token;
-
- if (!token) {
- return next(new Error('Authentication error: No token provided'));
- }
-
- try {
- const decoded = jwt.verify(token, process.env.JWT_SECRET);
- socket.user = decoded;
- next();
- } catch (error) {
- next(new Error('Authentication error: Invalid token'));
- }
- });
-
- io.on('connection', (socket) => {
- console.log('User connected:', socket.user.email);
-
- // Join user to their personal room
- socket.join(`user:${socket.user.uid}`);
-
- // Handle project room subscription
- socket.on('join-project', (projectId) => {
- socket.join(`project:${projectId}`);
- console.log(`${socket.user.email} joined project ${projectId}`);
- });
-
- socket.on('leave-project', (projectId) => {
- socket.leave(`project:${projectId}`);
- console.log(`${socket.user.email} left project ${projectId}`);
- });
-
- socket.on('disconnect', () => {
- console.log('User disconnected:', socket.user.email);
- });
- });
-
- return io;
-};
-
-export const getIO = () => {
- if (!io) {
- throw new Error('Socket.io not initialized');
- }
- return io;
-};
diff --git a/Frontend/.env.example b/Frontend/.env.example
deleted file mode 100644
index d5cb0df..0000000
--- a/Frontend/.env.example
+++ /dev/null
@@ -1,7 +0,0 @@
-VITE_FIREBASE_API_KEY=your_api_key_here
-VITE_FIREBASE_AUTH_DOMAIN=your-project-id.firebaseapp.com
-VITE_FIREBASE_PROJECT_ID=your-project-id
-VITE_FIREBASE_STORAGE_BUCKET=your-project-id.appspot.com
-VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id_here
-VITE_FIREBASE_APP_ID=your_app_id_here
-VITE_FIREBASE_MEASUREMENT_ID=your_measurement_id_here
diff --git a/Frontend/.gitignore b/Frontend/.gitignore
deleted file mode 100644
index 7ceb59f..0000000
--- a/Frontend/.gitignore
+++ /dev/null
@@ -1,25 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
-.env
diff --git a/Frontend/eslint.config.js b/Frontend/eslint.config.js
deleted file mode 100644
index 82c2e20..0000000
--- a/Frontend/eslint.config.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import js from '@eslint/js';
-import globals from 'globals';
-import reactHooks from 'eslint-plugin-react-hooks';
-import reactRefresh from 'eslint-plugin-react-refresh';
-import tseslint from 'typescript-eslint';
-
-export default tseslint.config(
- { ignores: ['dist'] },
- {
- extends: [js.configs.recommended, ...tseslint.configs.recommended],
- files: ['**/*.{ts,tsx}'],
- languageOptions: {
- ecmaVersion: 2020,
- globals: globals.browser,
- },
- plugins: {
- 'react-hooks': reactHooks,
- 'react-refresh': reactRefresh,
- },
- rules: {
- ...reactHooks.configs.recommended.rules,
- 'react-refresh/only-export-components': [
- 'warn',
- { allowConstantExport: true },
- ],
- },
- }
-);
diff --git a/Frontend/index.html b/Frontend/index.html
deleted file mode 100644
index 9455230..0000000
--- a/Frontend/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
- TaskBoard Pro
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json
deleted file mode 100644
index 99bbf91..0000000
--- a/Frontend/package-lock.json
+++ /dev/null
@@ -1,5634 +0,0 @@
-{
- "name": "taskboard-pro",
- "version": "0.0.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "taskboard-pro",
- "version": "0.0.0",
- "dependencies": {
- "axios": "^1.9.0",
- "firebase": "^11.7.3",
- "framer-motion": "^10.17.4",
- "lucide-react": "^0.344.0",
- "prop-types": "^15.8.1",
- "react": "^18.3.1",
- "react-beautiful-dnd": "^13.1.1",
- "react-dom": "^18.3.1",
- "react-router-dom": "^6.22.1"
- },
- "devDependencies": {
- "@eslint/js": "^9.9.1",
- "@types/react": "^18.3.5",
- "@types/react-dom": "^18.3.0",
- "@vitejs/plugin-react": "^4.3.1",
- "autoprefixer": "^10.4.18",
- "eslint": "^9.9.1",
- "eslint-plugin-react-hooks": "^5.1.0-rc.0",
- "eslint-plugin-react-refresh": "^0.4.11",
- "globals": "^15.9.0",
- "postcss": "^8.4.35",
- "tailwindcss": "^3.4.1",
- "typescript": "^5.5.3",
- "typescript-eslint": "^8.3.0",
- "vite": "^5.4.2"
- }
- },
- "node_modules/@alloc/quick-lru": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
- "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "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,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.3.5",
- "@jridgewell/trace-mapping": "^0.3.24"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz",
- "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==",
- "dev": true,
- "dependencies": {
- "@babel/highlight": "^7.25.7",
- "picocolors": "^1.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/compat-data": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz",
- "integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/core": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz",
- "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==",
- "dev": true,
- "dependencies": {
- "@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.25.7",
- "@babel/generator": "^7.25.7",
- "@babel/helper-compilation-targets": "^7.25.7",
- "@babel/helper-module-transforms": "^7.25.7",
- "@babel/helpers": "^7.25.7",
- "@babel/parser": "^7.25.7",
- "@babel/template": "^7.25.7",
- "@babel/traverse": "^7.25.7",
- "@babel/types": "^7.25.7",
- "convert-source-map": "^2.0.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.3",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/babel"
- }
- },
- "node_modules/@babel/generator": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz",
- "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.25.7",
- "@jridgewell/gen-mapping": "^0.3.5",
- "@jridgewell/trace-mapping": "^0.3.25",
- "jsesc": "^3.0.2"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-compilation-targets": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz",
- "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.25.7",
- "@babel/helper-validator-option": "^7.25.7",
- "browserslist": "^4.24.0",
- "lru-cache": "^5.1.1",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-imports": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz",
- "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==",
- "dev": true,
- "dependencies": {
- "@babel/traverse": "^7.25.7",
- "@babel/types": "^7.25.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-transforms": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz",
- "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-module-imports": "^7.25.7",
- "@babel/helper-simple-access": "^7.25.7",
- "@babel/helper-validator-identifier": "^7.25.7",
- "@babel/traverse": "^7.25.7"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-plugin-utils": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz",
- "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-simple-access": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz",
- "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==",
- "dev": true,
- "dependencies": {
- "@babel/traverse": "^7.25.7",
- "@babel/types": "^7.25.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-string-parser": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
- "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz",
- "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-option": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz",
- "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helpers": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz",
- "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.25.7",
- "@babel/types": "^7.25.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz",
- "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.25.7",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/parser": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz",
- "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.25.7"
- },
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/plugin-transform-react-jsx-self": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.7.tgz",
- "integrity": "sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.25.7"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-react-jsx-source": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.7.tgz",
- "integrity": "sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.25.7"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz",
- "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==",
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/template": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz",
- "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.25.7",
- "@babel/parser": "^7.25.7",
- "@babel/types": "^7.25.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/traverse": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz",
- "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.25.7",
- "@babel/generator": "^7.25.7",
- "@babel/parser": "^7.25.7",
- "@babel/template": "^7.25.7",
- "@babel/types": "^7.25.7",
- "debug": "^4.3.1",
- "globals": "^11.1.0"
- },
- "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,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/types": {
- "version": "7.25.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz",
- "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-string-parser": "^7.25.7",
- "@babel/helper-validator-identifier": "^7.25.7",
- "to-fast-properties": "^2.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@emotion/is-prop-valid": {
- "version": "0.8.8",
- "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
- "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "@emotion/memoize": "0.7.4"
- }
- },
- "node_modules/@emotion/memoize": {
- "version": "0.7.4",
- "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
- "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
- "license": "MIT",
- "optional": true
- },
- "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==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "aix"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@eslint-community/eslint-utils": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
- "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
- }
- },
- "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "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,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint-community/regexpp": {
- "version": "4.11.1",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz",
- "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==",
- "dev": true,
- "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==",
- "dev": true,
- "dependencies": {
- "@eslint/object-schema": "^2.1.4",
- "debug": "^4.3.1",
- "minimatch": "^3.1.2"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/core": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz",
- "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==",
- "dev": true,
- "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==",
- "dev": true,
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^10.0.1",
- "globals": "^14.0.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/globals": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
- "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
- "dev": true,
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@eslint/js": {
- "version": "9.12.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz",
- "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==",
- "dev": true,
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "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==",
- "dev": true,
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/plugin-kit": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz",
- "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==",
- "dev": true,
- "dependencies": {
- "levn": "^0.4.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@firebase/analytics": {
- "version": "0.10.15",
- "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.15.tgz",
- "integrity": "sha512-LzRzWtD1t1Fdzts+mHP6TEcIVlPK7XifZWMwM3+0RQbZCD4PxkB1myAvkbWVlXXzD6DlGS5Wc7kpt0oFDL/XxA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/installations": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/analytics-compat": {
- "version": "0.2.21",
- "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.21.tgz",
- "integrity": "sha512-t/uNh8rXws3t8nRdH75GclPP7/QCWDnVv78NfHMnedjbuQg6aF7YNbpHNznIJiKVKkRkcQobtpBqGdIPdvf3ZA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/analytics": "0.10.15",
- "@firebase/analytics-types": "0.8.3",
- "@firebase/component": "0.6.16",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/analytics-types": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz",
- "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/app": {
- "version": "0.12.3",
- "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.12.3.tgz",
- "integrity": "sha512-8BbBlBUEZ9LUQ1Sm9wcDNv+gdj+3k3hv2I59dsw0tayjdmJTo+IDWsWe1N7sUSi20Hc7p3QoE9DdVxp4jtT7Mg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "idb": "7.1.1",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@firebase/app-check": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.9.3.tgz",
- "integrity": "sha512-jACDmeq5jEazWOojVr5lWwEe70slJfeCszsKL3TVyxGHMnXVBH5tJQme2DuMqhyZv36SVhh0zt6i3dB+lwhf7w==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/app-check-compat": {
- "version": "0.3.24",
- "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.24.tgz",
- "integrity": "sha512-hLLFxyurZ+HzAuSMHQufyCq4Cy7KNwtzXcqzs/+eTsQ+gkyGFS+eavcjzwxg9qwSQPqMkXE9otGenvMsWmBbQQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/app-check": "0.9.3",
- "@firebase/app-check-types": "0.5.3",
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/app-check-interop-types": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz",
- "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/app-check-types": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz",
- "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/app-compat": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.3.3.tgz",
- "integrity": "sha512-olkQJHeU7t0MQJQ3wSgZFkg34lR2vUoAS7B5+2y7AheZ/mCNazwm3TjfzMfPoy9CB1WhwTOhizBQdDnChSsAXA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/app": "0.12.3",
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@firebase/app-types": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz",
- "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/auth-compat": {
- "version": "0.5.24",
- "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.24.tgz",
- "integrity": "sha512-nRGfAqK9EMoYcSdVJMWuhNJNFqTi5qU+O4U//vGjB9mKfX4v+eDYAxCf5eyB+2vxTOP55xR28AtA6He4LQKNJA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/auth": "1.10.4",
- "@firebase/auth-types": "0.13.0",
- "@firebase/component": "0.6.16",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/auth-compat/node_modules/@firebase/auth": {
- "version": "1.10.4",
- "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.10.4.tgz",
- "integrity": "sha512-rZQZQkn5x7BcHenYJi9RYWoOMJHdM/CsF6DMclb/CKbntzjUaZj+R45Iyzf/BFUJ9L2sA4bNPhJK9x+l9VKvLQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x",
- "@react-native-async-storage/async-storage": "^1.18.1"
- },
- "peerDependenciesMeta": {
- "@react-native-async-storage/async-storage": {
- "optional": true
- }
- }
- },
- "node_modules/@firebase/auth-interop-types": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz",
- "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/auth-types": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz",
- "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==",
- "license": "Apache-2.0",
- "peerDependencies": {
- "@firebase/app-types": "0.x",
- "@firebase/util": "1.x"
- }
- },
- "node_modules/@firebase/component": {
- "version": "0.6.16",
- "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.16.tgz",
- "integrity": "sha512-whx+e3pgC3J9O6t4LOB8jiLk3tpWtnXaQ+xt/ys/4IGUPRI+nnWooVdtWrEnMga/gT03ug9SdEAEJLl6I1BIlg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@firebase/data-connect": {
- "version": "0.3.7",
- "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.7.tgz",
- "integrity": "sha512-AvOXRsVDF8krA9lgXfj+v4cj5/L9u/2OIaR/JZ5cTf5QAcvPUExsB7gX0uvJFh9wNlv1E51TDVihcMlXYH1NiA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/auth-interop-types": "0.2.4",
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/database": {
- "version": "1.0.17",
- "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.17.tgz",
- "integrity": "sha512-CUUsegGubS90/QkZ4sO84SgoJlnYOCaArVl6CG8aTSuTJoEAoD8elVwR02aPM80m0GOFM6NBT7B+ayK7jeVmMA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/app-check-interop-types": "0.3.3",
- "@firebase/auth-interop-types": "0.2.4",
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "faye-websocket": "0.11.4",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@firebase/database-compat": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.8.tgz",
- "integrity": "sha512-GsopZGu8SefAUHtdh+1HL10TcpuBmXCz7RRJ1iPP9sbkF0vWHu5eYpkqKzaZ687EyS0SG03o2rno7JIwm1hbYQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/database": "1.0.17",
- "@firebase/database-types": "1.0.13",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@firebase/database-types": {
- "version": "1.0.13",
- "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.13.tgz",
- "integrity": "sha512-HoMVmHNLNEmSe55XMKXYbfAaie21h++G7gxhIttj330yPlW+RgG00CLedpmQvaqfEHEvh+6eUjddtJ/ezm1x2w==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/app-types": "0.9.3",
- "@firebase/util": "1.11.3"
- }
- },
- "node_modules/@firebase/firestore": {
- "version": "4.7.14",
- "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.14.tgz",
- "integrity": "sha512-YLz71p96ACfILNjnqh7H6ilsT3AZZyDpCCE+wpl8mJklAbdpyd2ahNIqS1eBCjseqls8vQO/XTaIcbpkSgQFIg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "@firebase/webchannel-wrapper": "1.0.3",
- "@grpc/grpc-js": "~1.9.0",
- "@grpc/proto-loader": "^0.7.8",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/firestore-compat": {
- "version": "0.3.49",
- "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.49.tgz",
- "integrity": "sha512-5sj+GFTV+GxVBOhsiRitIrZ0dPIIudllGvJxjfikcnUZV0wq6urmjjWSrmp8V3syc6QLEnGhGSWoArDTnHce1g==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/firestore": "4.7.14",
- "@firebase/firestore-types": "3.0.3",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/firestore-types": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz",
- "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==",
- "license": "Apache-2.0",
- "peerDependencies": {
- "@firebase/app-types": "0.x",
- "@firebase/util": "1.x"
- }
- },
- "node_modules/@firebase/functions": {
- "version": "0.12.6",
- "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.6.tgz",
- "integrity": "sha512-HfLWbphl5sA/+4wjwHWPHHgvuTDN+4DIs3bxW1746nMAblCQ3b26yHDssRCCZkpgzO1o01j/cmu1dbRL9pSJfg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/app-check-interop-types": "0.3.3",
- "@firebase/auth-interop-types": "0.2.4",
- "@firebase/component": "0.6.16",
- "@firebase/messaging-interop-types": "0.2.3",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/functions-compat": {
- "version": "0.3.23",
- "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.23.tgz",
- "integrity": "sha512-yt7Odu1gwPYE6B7C/rRcXZH8QlXOpqdu20ddCvp4H2sI3Le37OCxRxpecDNR0sUjtDmCeEFTlB2VV9RT8CENxQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/functions": "0.12.6",
- "@firebase/functions-types": "0.6.3",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/functions-types": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz",
- "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/installations": {
- "version": "0.6.16",
- "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.16.tgz",
- "integrity": "sha512-8oE25Nkdf/xUazViCYkEbvt42PXZ2TcnDuXUFykPCJ88xGEjtt9t+oCv2UpW9j1XEq3v80hlyX7iwWXE5RWj3w==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/util": "1.11.3",
- "idb": "7.1.1",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/installations-compat": {
- "version": "0.2.16",
- "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.16.tgz",
- "integrity": "sha512-gL5p1t4OzhAtqlc6t1kX7IKIEwF0D62/1+GmN8RK2enlnxGZ+whPFeTHfDM7IMxoMkdJ6o8/3X5Z7E2Hkha1Hw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/installations": "0.6.16",
- "@firebase/installations-types": "0.5.3",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/installations-types": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz",
- "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==",
- "license": "Apache-2.0",
- "peerDependencies": {
- "@firebase/app-types": "0.x"
- }
- },
- "node_modules/@firebase/logger": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz",
- "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==",
- "license": "Apache-2.0",
- "dependencies": {
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@firebase/messaging": {
- "version": "0.12.20",
- "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.20.tgz",
- "integrity": "sha512-YkUPUlfrsBQ0uOo2AxL2pGN9Ns1WmL2ohzTqJVGXNyne6YBc8ppFtxCQqB4qL5hRdgh3/ZJmnrOm2Yee/SfIgA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/installations": "0.6.16",
- "@firebase/messaging-interop-types": "0.2.3",
- "@firebase/util": "1.11.3",
- "idb": "7.1.1",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/messaging-compat": {
- "version": "0.2.20",
- "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.20.tgz",
- "integrity": "sha512-AQtNqofrZTbNX4h8eXtFyIhhJm5MiavPjXU7vk4yG1fJRCxaVEiWuj/lBQdDbKnA0E9Mv8wE1N6eWC1pjOnZfA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/messaging": "0.12.20",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/messaging-interop-types": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz",
- "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/performance": {
- "version": "0.7.5",
- "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.5.tgz",
- "integrity": "sha512-1bwG4ACRQZX6fKcIobZaSsCe9eRZnSKHTJ3/4GNhS7rO2W9nlj30xRd0GozZszBLgjn6lFcFPRxV+o2mcgjmOA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/installations": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0",
- "web-vitals": "^4.2.4"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/performance-compat": {
- "version": "0.2.18",
- "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.18.tgz",
- "integrity": "sha512-gwgENv/KnIa/EVErFC1MaM+r/Qs9lM/XAhI1x1/gwd56B9kYA77x1L0DggElb24ddm3Vo83tQVnV2N6nLeIjyQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/performance": "0.7.5",
- "@firebase/performance-types": "0.2.3",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/performance-types": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz",
- "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/remote-config": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.6.3.tgz",
- "integrity": "sha512-Bhf8KB1EGwo6exaN7XcOnkzgkmjBJkAk4+Ny+dBDW1+AI+KIrZ9ToCmP1MpSJTNJ4ZBbLWruawEse7cOJzIe4w==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/installations": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/remote-config-compat": {
- "version": "0.2.16",
- "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.16.tgz",
- "integrity": "sha512-In4cP+PxPWXF09FJLQs22Yx2x99AYO6u1egxpECPhCulGnLj+B8vhuqgV3aFJEoZ+4vjg+u0FY3+kzeXeNFf/Q==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/remote-config": "0.6.3",
- "@firebase/remote-config-types": "0.4.0",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/remote-config-types": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz",
- "integrity": "sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg==",
- "license": "Apache-2.0"
- },
- "node_modules/@firebase/storage": {
- "version": "0.13.10",
- "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.10.tgz",
- "integrity": "sha512-OEt3jD5O3Xp8PJrMTRw0WCUvTkrc3ENzY8RMN5OUIWX/oIKxv+kV0WyNjTYu3s4HsQs0Q9rjMPbREMIihM0KDg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x"
- }
- },
- "node_modules/@firebase/storage-compat": {
- "version": "0.3.20",
- "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.20.tgz",
- "integrity": "sha512-JjXcyyjlPbZ3SCBwDfjk1hVfc3ybuezO0LvvmHEr6gGnZkUaM/iOjgSdQ9xXcRAWL5IGEby0qlDCAF3TClTtGQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/storage": "0.13.10",
- "@firebase/storage-types": "0.8.3",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app-compat": "0.x"
- }
- },
- "node_modules/@firebase/storage-types": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz",
- "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==",
- "license": "Apache-2.0",
- "peerDependencies": {
- "@firebase/app-types": "0.x",
- "@firebase/util": "1.x"
- }
- },
- "node_modules/@firebase/util": {
- "version": "1.11.3",
- "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.11.3.tgz",
- "integrity": "sha512-4wYnOV9FpwdCq3rHQOCrdx4AQBUbfH1p2DhWGQxlQ+D3Xl/wSxc/HttcyPN4NNFiynxoNCFGWQH/zdhRfxP1Zg==",
- "hasInstallScript": true,
- "license": "Apache-2.0",
- "dependencies": {
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@firebase/vertexai": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.2.4.tgz",
- "integrity": "sha512-QvNp8mqD/TmAfdSu5lBwqDarAmW7l6j2fRC/S9GwvsE9l/oz+HH+glkQ/qn8+Qd/mjD3OGYLWQFYhD8bF9t5Vg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/app-check-interop-types": "0.3.3",
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x",
- "@firebase/app-types": "0.x"
- }
- },
- "node_modules/@firebase/webchannel-wrapper": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz",
- "integrity": "sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==",
- "license": "Apache-2.0"
- },
- "node_modules/@grpc/grpc-js": {
- "version": "1.9.15",
- "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz",
- "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@grpc/proto-loader": "^0.7.8",
- "@types/node": ">=12.12.47"
- },
- "engines": {
- "node": "^8.13.0 || >=10.10.0"
- }
- },
- "node_modules/@grpc/proto-loader": {
- "version": "0.7.15",
- "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz",
- "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "lodash.camelcase": "^4.3.0",
- "long": "^5.0.0",
- "protobufjs": "^7.2.5",
- "yargs": "^17.7.2"
- },
- "bin": {
- "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "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==",
- "dev": true,
- "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==",
- "dev": true,
- "dependencies": {
- "@humanfs/core": "^0.19.0",
- "@humanwhocodes/retry": "^0.3.0"
- },
- "engines": {
- "node": ">=18.18.0"
- }
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true,
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "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==",
- "dev": true,
- "engines": {
- "node": ">=18.18"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@isaacs/cliui": {
- "version": "8.0.2",
- "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
- "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
- "dev": true,
- "dependencies": {
- "string-width": "^5.1.2",
- "string-width-cjs": "npm:string-width@^4.2.0",
- "strip-ansi": "^7.0.1",
- "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
- "wrap-ansi": "^8.1.0",
- "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "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==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.2.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.24"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/resolve-uri": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
- "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
- "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,
- "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
- },
- "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==",
- "dev": true,
- "dependencies": {
- "@jridgewell/resolve-uri": "^3.1.0",
- "@jridgewell/sourcemap-codec": "^1.4.14"
- }
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@pkgjs/parseargs": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
- "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/@protobufjs/aspromise": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
- "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/base64": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
- "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/codegen": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
- "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/eventemitter": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
- "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/fetch": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
- "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
- "license": "BSD-3-Clause",
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.1",
- "@protobufjs/inquire": "^1.1.0"
- }
- },
- "node_modules/@protobufjs/float": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
- "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/inquire": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
- "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/path": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
- "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/pool": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
- "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@protobufjs/utf8": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
- "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
- "license": "BSD-3-Clause"
- },
- "node_modules/@remix-run/router": {
- "version": "1.23.0",
- "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz",
- "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==",
- "license": "MIT",
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "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==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "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==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "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==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "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==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@types/babel__core": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
- "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
- "dev": true,
- "dependencies": {
- "@babel/parser": "^7.20.7",
- "@babel/types": "^7.20.7",
- "@types/babel__generator": "*",
- "@types/babel__template": "*",
- "@types/babel__traverse": "*"
- }
- },
- "node_modules/@types/babel__generator": {
- "version": "7.6.8",
- "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz",
- "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.0.0"
- }
- },
- "node_modules/@types/babel__template": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
- "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
- "dev": true,
- "dependencies": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0"
- }
- },
- "node_modules/@types/babel__traverse": {
- "version": "7.20.6",
- "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz",
- "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.20.7"
- }
- },
- "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
- },
- "node_modules/@types/hoist-non-react-statics": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz",
- "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==",
- "license": "MIT",
- "dependencies": {
- "@types/react": "*",
- "hoist-non-react-statics": "^3.3.0"
- }
- },
- "node_modules/@types/json-schema": {
- "version": "7.0.15",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
- "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
- "dev": true
- },
- "node_modules/@types/node": {
- "version": "22.15.18",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.18.tgz",
- "integrity": "sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg==",
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.21.0"
- }
- },
- "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=="
- },
- "node_modules/@types/react": {
- "version": "18.3.11",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz",
- "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==",
- "dependencies": {
- "@types/prop-types": "*",
- "csstype": "^3.0.2"
- }
- },
- "node_modules/@types/react-dom": {
- "version": "18.3.0",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz",
- "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==",
- "dev": true,
- "dependencies": {
- "@types/react": "*"
- }
- },
- "node_modules/@types/react-redux": {
- "version": "7.1.34",
- "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.34.tgz",
- "integrity": "sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==",
- "license": "MIT",
- "dependencies": {
- "@types/hoist-non-react-statics": "^3.3.0",
- "@types/react": "*",
- "hoist-non-react-statics": "^3.3.0",
- "redux": "^4.0.0"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz",
- "integrity": "sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==",
- "dev": true,
- "dependencies": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.8.1",
- "@typescript-eslint/type-utils": "8.8.1",
- "@typescript-eslint/utils": "8.8.1",
- "@typescript-eslint/visitor-keys": "8.8.1",
- "graphemer": "^1.4.0",
- "ignore": "^5.3.1",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^1.3.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
- "eslint": "^8.57.0 || ^9.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/parser": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.1.tgz",
- "integrity": "sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.8.1",
- "@typescript-eslint/types": "8.8.1",
- "@typescript-eslint/typescript-estree": "8.8.1",
- "@typescript-eslint/visitor-keys": "8.8.1",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz",
- "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "8.8.1",
- "@typescript-eslint/visitor-keys": "8.8.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/type-utils": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz",
- "integrity": "sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/typescript-estree": "8.8.1",
- "@typescript-eslint/utils": "8.8.1",
- "debug": "^4.3.4",
- "ts-api-utils": "^1.3.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz",
- "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==",
- "dev": true,
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz",
- "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "8.8.1",
- "@typescript-eslint/visitor-keys": "8.8.1",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^1.3.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
- "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/utils": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz",
- "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "8.8.1",
- "@typescript-eslint/types": "8.8.1",
- "@typescript-eslint/typescript-estree": "8.8.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz",
- "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "8.8.1",
- "eslint-visitor-keys": "^3.4.3"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "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,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@vitejs/plugin-react": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz",
- "integrity": "sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.25.2",
- "@babel/plugin-transform-react-jsx-self": "^7.24.7",
- "@babel/plugin-transform-react-jsx-source": "^7.24.7",
- "@types/babel__core": "^7.20.5",
- "react-refresh": "^0.14.2"
- },
- "engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "peerDependencies": {
- "vite": "^4.2.0 || ^5.0.0"
- }
- },
- "node_modules/acorn": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
- "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
- "dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ansi-regex": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
- "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
- "node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/any-promise": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
- "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
- "dev": true
- },
- "node_modules/anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/arg": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
- "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
- "dev": true
- },
- "node_modules/argparse": {
- "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
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "license": "MIT"
- },
- "node_modules/autoprefixer": {
- "version": "10.4.20",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
- "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/autoprefixer"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "browserslist": "^4.23.3",
- "caniuse-lite": "^1.0.30001646",
- "fraction.js": "^4.3.7",
- "normalize-range": "^0.1.2",
- "picocolors": "^1.0.1",
- "postcss-value-parser": "^4.2.0"
- },
- "bin": {
- "autoprefixer": "bin/autoprefixer"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- },
- "peerDependencies": {
- "postcss": "^8.1.0"
- }
- },
- "node_modules/axios": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
- "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
- "license": "MIT",
- "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==",
- "dev": true
- },
- "node_modules/binary-extensions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
- "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "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==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
- "dependencies": {
- "fill-range": "^7.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/browserslist": {
- "version": "4.24.0",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz",
- "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "caniuse-lite": "^1.0.30001663",
- "electron-to-chromium": "^1.5.28",
- "node-releases": "^2.0.18",
- "update-browserslist-db": "^1.1.0"
- },
- "bin": {
- "browserslist": "cli.js"
- },
- "engines": {
- "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
- }
- },
- "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==",
- "license": "MIT",
- "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,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/camelcase-css": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
- "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001667",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz",
- "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ]
- },
- "node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/chokidar": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
- "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
- "dev": true,
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/chokidar/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "license": "ISC",
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/cliui/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cliui/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/cliui/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/cliui/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "license": "MIT"
- },
- "node_modules/cliui/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "license": "MIT"
- },
- "node_modules/cliui/node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cliui/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cliui/node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "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==",
- "license": "MIT",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/commander": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
- "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "node_modules/convert-source-map": {
- "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
- },
- "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==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/css-box-model": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
- "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
- "license": "MIT",
- "dependencies": {
- "tiny-invariant": "^1.0.6"
- }
- },
- "node_modules/cssesc": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
- "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
- "dev": true,
- "bin": {
- "cssesc": "bin/cssesc"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/csstype": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
- "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
- },
- "node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
- "dev": true,
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "license": "MIT",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/didyoumean": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
- "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
- "dev": true
- },
- "node_modules/dlv": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
- "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
- "dev": true
- },
- "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==",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/eastasianwidth": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
- "dev": true
- },
- "node_modules/electron-to-chromium": {
- "version": "1.5.33",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.33.tgz",
- "integrity": "sha512-+cYTcFB1QqD4j4LegwLfpCNxifb6dDFUAwk6RsLusCwIaZI6or2f+q8rs5tTB2YC53HhOlIbEaqHMAAC8IOIwA==",
- "dev": true
- },
- "node_modules/emoji-regex": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
- "dev": true
- },
- "node_modules/es-define-property": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
- "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-object-atoms": {
- "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==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-set-tostringtag": {
- "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==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "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==",
- "dev": true,
- "hasInstallScript": true,
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=12"
- },
- "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"
- }
- },
- "node_modules/escalade": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
- "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/eslint": {
- "version": "9.12.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz",
- "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.11.0",
- "@eslint/config-array": "^0.18.0",
- "@eslint/core": "^0.6.0",
- "@eslint/eslintrc": "^3.1.0",
- "@eslint/js": "9.12.0",
- "@eslint/plugin-kit": "^0.2.0",
- "@humanfs/node": "^0.16.5",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@humanwhocodes/retry": "^0.3.1",
- "@types/estree": "^1.0.6",
- "@types/json-schema": "^7.0.15",
- "ajv": "^6.12.4",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "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",
- "esquery": "^1.5.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^8.0.0",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "ignore": "^5.2.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "text-table": "^0.2.0"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://eslint.org/donate"
- },
- "peerDependencies": {
- "jiti": "*"
- },
- "peerDependenciesMeta": {
- "jiti": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-plugin-react-hooks": {
- "version": "5.1.0-rc-fb9a90fa48-20240614",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz",
- "integrity": "sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
- }
- },
- "node_modules/eslint-plugin-react-refresh": {
- "version": "0.4.12",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz",
- "integrity": "sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg==",
- "dev": true,
- "peerDependencies": {
- "eslint": ">=7"
- }
- },
- "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==",
- "dev": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "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==",
- "dev": true,
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/eslint/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/eslint/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/eslint/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/eslint/node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "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==",
- "dev": true,
- "dependencies": {
- "acorn": "^8.12.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/esquery": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/fast-deep-equal": {
- "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
- },
- "node_modules/fast-glob": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
- "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/fast-glob/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "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
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "node_modules/fastq": {
- "version": "1.17.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
- "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
- "dev": true,
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/faye-websocket": {
- "version": "0.11.4",
- "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
- "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
- "license": "Apache-2.0",
- "dependencies": {
- "websocket-driver": ">=0.5.1"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/file-entry-cache": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
- "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
- "dev": true,
- "dependencies": {
- "flat-cache": "^4.0.0"
- },
- "engines": {
- "node": ">=16.0.0"
- }
- },
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/firebase": {
- "version": "11.7.3",
- "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.7.3.tgz",
- "integrity": "sha512-5zhITZvxl6BQbf7RQNA6h08mCMUkSnJtgMzm67JFbXo2zfgWDMuakQOIlHAtnJBc/f3llvB3yoH2v1Nr2/bMMQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/analytics": "0.10.15",
- "@firebase/analytics-compat": "0.2.21",
- "@firebase/app": "0.12.3",
- "@firebase/app-check": "0.9.3",
- "@firebase/app-check-compat": "0.3.24",
- "@firebase/app-compat": "0.3.3",
- "@firebase/app-types": "0.9.3",
- "@firebase/auth": "1.10.4",
- "@firebase/auth-compat": "0.5.24",
- "@firebase/data-connect": "0.3.7",
- "@firebase/database": "1.0.17",
- "@firebase/database-compat": "2.0.8",
- "@firebase/firestore": "4.7.14",
- "@firebase/firestore-compat": "0.3.49",
- "@firebase/functions": "0.12.6",
- "@firebase/functions-compat": "0.3.23",
- "@firebase/installations": "0.6.16",
- "@firebase/installations-compat": "0.2.16",
- "@firebase/messaging": "0.12.20",
- "@firebase/messaging-compat": "0.2.20",
- "@firebase/performance": "0.7.5",
- "@firebase/performance-compat": "0.2.18",
- "@firebase/remote-config": "0.6.3",
- "@firebase/remote-config-compat": "0.2.16",
- "@firebase/storage": "0.13.10",
- "@firebase/storage-compat": "0.3.20",
- "@firebase/util": "1.11.3",
- "@firebase/vertexai": "1.2.4"
- }
- },
- "node_modules/firebase/node_modules/@firebase/auth": {
- "version": "1.10.4",
- "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.10.4.tgz",
- "integrity": "sha512-rZQZQkn5x7BcHenYJi9RYWoOMJHdM/CsF6DMclb/CKbntzjUaZj+R45Iyzf/BFUJ9L2sA4bNPhJK9x+l9VKvLQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@firebase/component": "0.6.16",
- "@firebase/logger": "0.4.4",
- "@firebase/util": "1.11.3",
- "tslib": "^2.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@firebase/app": "0.x",
- "@react-native-async-storage/async-storage": "^1.18.1"
- },
- "peerDependenciesMeta": {
- "@react-native-async-storage/async-storage": {
- "optional": true
- }
- }
- },
- "node_modules/flat-cache": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
- "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
- "dev": true,
- "dependencies": {
- "flatted": "^3.2.9",
- "keyv": "^4.5.4"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/flatted": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
- "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
- "dev": true
- },
- "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"
- }
- ],
- "license": "MIT",
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- },
- "node_modules/foreground-child": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
- "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.0",
- "signal-exit": "^4.0.1"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/form-data": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
- "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
- "license": "MIT",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "es-set-tostringtag": "^2.1.0",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/fraction.js": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
- "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
- "dev": true,
- "engines": {
- "node": "*"
- },
- "funding": {
- "type": "patreon",
- "url": "https://github.com/sponsors/rawify"
- }
- },
- "node_modules/framer-motion": {
- "version": "10.18.0",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.18.0.tgz",
- "integrity": "sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w==",
- "license": "MIT",
- "dependencies": {
- "tslib": "^2.4.0"
- },
- "optionalDependencies": {
- "@emotion/is-prop-valid": "^0.8.2"
- },
- "peerDependencies": {
- "react": "^18.0.0",
- "react-dom": "^18.0.0"
- },
- "peerDependenciesMeta": {
- "react": {
- "optional": true
- },
- "react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "license": "ISC",
- "engines": {
- "node": "6.* || 8.* || >= 10.*"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
- "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "license": "MIT",
- "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",
- "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"
- },
- "funding": {
- "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==",
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/glob": {
- "version": "10.4.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
- "dev": true,
- "dependencies": {
- "foreground-child": "^3.1.0",
- "jackspeak": "^3.1.2",
- "minimatch": "^9.0.4",
- "minipass": "^7.1.2",
- "package-json-from-dist": "^1.0.0",
- "path-scurry": "^1.11.1"
- },
- "bin": {
- "glob": "dist/esm/bin.mjs"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/glob/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/glob/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/globals": {
- "version": "15.11.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz",
- "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==",
- "dev": true,
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/gopd": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
- },
- "node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
- "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
- "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "license": "MIT",
- "dependencies": {
- "has-symbols": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "license": "BSD-3-Clause",
- "dependencies": {
- "react-is": "^16.7.0"
- }
- },
- "node_modules/http-parser-js": {
- "version": "0.5.10",
- "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
- "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
- "license": "MIT"
- },
- "node_modules/idb": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
- "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
- "license": "ISC"
- },
- "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,
- "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==",
- "dev": true,
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.15.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
- "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
- "dev": true,
- "dependencies": {
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "node_modules/jackspeak": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
- "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
- "dev": true,
- "dependencies": {
- "@isaacs/cliui": "^8.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- },
- "optionalDependencies": {
- "@pkgjs/parseargs": "^0.11.0"
- }
- },
- "node_modules/jiti": {
- "version": "1.21.6",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
- "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
- "dev": true,
- "bin": {
- "jiti": "bin/jiti.js"
- }
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "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==",
- "dev": true,
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true
- },
- "node_modules/json-schema-traverse": {
- "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
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "node_modules/json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
- "dev": true,
- "bin": {
- "json5": "lib/cli.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
- "dev": true,
- "dependencies": {
- "json-buffer": "3.0.1"
- }
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/lilconfig": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
- "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
- "dev": true
- },
- "node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lodash.camelcase": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
- "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
- "license": "MIT"
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "node_modules/long": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
- "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
- "license": "Apache-2.0"
- },
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/lru-cache": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
- "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
- "dev": true,
- "dependencies": {
- "yallist": "^3.0.2"
- }
- },
- "node_modules/lucide-react": {
- "version": "0.344.0",
- "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.344.0.tgz",
- "integrity": "sha512-6YyBnn91GB45VuVT96bYCOKElbJzUHqp65vX8cDcu55MQL9T969v4dhGClpljamuI/+KMO9P6w9Acq1CVQGvIQ==",
- "peerDependencies": {
- "react": "^16.5.1 || ^17.0.0 || ^18.0.0"
- }
- },
- "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==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/memoize-one": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
- "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
- "license": "MIT"
- },
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
- "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
- "dependencies": {
- "braces": "^3.0.3",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "license": "MIT",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/minipass": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
- "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
- "dev": true,
- "engines": {
- "node": ">=16 || 14 >=14.17"
- }
- },
- "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==",
- "dev": true
- },
- "node_modules/mz": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
- "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
- "dev": true,
- "dependencies": {
- "any-promise": "^1.0.0",
- "object-assign": "^4.0.1",
- "thenify-all": "^1.0.0"
- }
- },
- "node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "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
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/normalize-range": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
- "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-hash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
- "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
- "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
- "dev": true,
- "dependencies": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.5"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/package-json-from-dist": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
- "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
- "dev": true
- },
- "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,
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
- },
- "node_modules/path-scurry": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
- "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^10.2.0",
- "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
- },
- "engines": {
- "node": ">=16 || 14 >=14.18"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/path-scurry/node_modules/lru-cache": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
- "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
- "dev": true
- },
- "node_modules/picocolors": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
- "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
- "dev": true
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/pirates": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
- "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/postcss": {
- "version": "8.4.47",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
- "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "nanoid": "^3.3.7",
- "picocolors": "^1.1.0",
- "source-map-js": "^1.2.1"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/postcss-import": {
- "version": "15.1.0",
- "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
- "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
- "dev": true,
- "dependencies": {
- "postcss-value-parser": "^4.0.0",
- "read-cache": "^1.0.0",
- "resolve": "^1.1.7"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "peerDependencies": {
- "postcss": "^8.0.0"
- }
- },
- "node_modules/postcss-js": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
- "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
- "dev": true,
- "dependencies": {
- "camelcase-css": "^2.0.1"
- },
- "engines": {
- "node": "^12 || ^14 || >= 16"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- "peerDependencies": {
- "postcss": "^8.4.21"
- }
- },
- "node_modules/postcss-load-config": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
- "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "lilconfig": "^3.0.0",
- "yaml": "^2.3.4"
- },
- "engines": {
- "node": ">= 14"
- },
- "peerDependencies": {
- "postcss": ">=8.0.9",
- "ts-node": ">=9.0.0"
- },
- "peerDependenciesMeta": {
- "postcss": {
- "optional": true
- },
- "ts-node": {
- "optional": true
- }
- }
- },
- "node_modules/postcss-load-config/node_modules/lilconfig": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
- "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
- "dev": true,
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/antonk52"
- }
- },
- "node_modules/postcss-nested": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
- "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "postcss-selector-parser": "^6.1.1"
- },
- "engines": {
- "node": ">=12.0"
- },
- "peerDependencies": {
- "postcss": "^8.2.14"
- }
- },
- "node_modules/postcss-selector-parser": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
- "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
- "dev": true,
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/postcss-value-parser": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
- "dev": true
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
- "node_modules/protobufjs": {
- "version": "7.5.2",
- "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.2.tgz",
- "integrity": "sha512-f2ls6rpO6G153Cy+o2XQ+Y0sARLOZ17+OGVLHrc3VUKcLHYKEKWbkSujdBWQXM7gKn5NTfp0XnRPZn1MIu8n9w==",
- "hasInstallScript": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.2",
- "@protobufjs/base64": "^1.1.2",
- "@protobufjs/codegen": "^2.0.4",
- "@protobufjs/eventemitter": "^1.1.0",
- "@protobufjs/fetch": "^1.1.0",
- "@protobufjs/float": "^1.0.2",
- "@protobufjs/inquire": "^1.1.0",
- "@protobufjs/path": "^1.1.2",
- "@protobufjs/pool": "^1.1.0",
- "@protobufjs/utf8": "^1.1.0",
- "@types/node": ">=13.7.0",
- "long": "^5.0.0"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "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==",
- "license": "MIT"
- },
- "node_modules/punycode": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
- "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "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/raf-schd": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
- "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==",
- "license": "MIT"
- },
- "node_modules/react": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
- "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-beautiful-dnd": {
- "version": "13.1.1",
- "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz",
- "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==",
- "deprecated": "react-beautiful-dnd is now deprecated. Context and options: https://github.com/atlassian/react-beautiful-dnd/issues/2672",
- "license": "Apache-2.0",
- "dependencies": {
- "@babel/runtime": "^7.9.2",
- "css-box-model": "^1.2.0",
- "memoize-one": "^5.1.1",
- "raf-schd": "^4.0.2",
- "react-redux": "^7.2.0",
- "redux": "^4.0.4",
- "use-memo-one": "^1.1.1"
- },
- "peerDependencies": {
- "react": "^16.8.5 || ^17.0.0 || ^18.0.0",
- "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0"
- }
- },
- "node_modules/react-dom": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
- "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.2"
- },
- "peerDependencies": {
- "react": "^18.3.1"
- }
- },
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "license": "MIT"
- },
- "node_modules/react-redux": {
- "version": "7.2.9",
- "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz",
- "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.15.4",
- "@types/react-redux": "^7.1.20",
- "hoist-non-react-statics": "^3.3.2",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.7.2",
- "react-is": "^17.0.2"
- },
- "peerDependencies": {
- "react": "^16.8.3 || ^17 || ^18"
- },
- "peerDependenciesMeta": {
- "react-dom": {
- "optional": true
- },
- "react-native": {
- "optional": true
- }
- }
- },
- "node_modules/react-redux/node_modules/react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "license": "MIT"
- },
- "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==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-router": {
- "version": "6.30.0",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.0.tgz",
- "integrity": "sha512-D3X8FyH9nBcTSHGdEKurK7r8OYE1kKFn3d/CF+CoxbSHkxU7o37+Uh7eAHRXr6k2tSExXYO++07PeXJtA/dEhQ==",
- "license": "MIT",
- "dependencies": {
- "@remix-run/router": "1.23.0"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "peerDependencies": {
- "react": ">=16.8"
- }
- },
- "node_modules/react-router-dom": {
- "version": "6.30.0",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.0.tgz",
- "integrity": "sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA==",
- "license": "MIT",
- "dependencies": {
- "@remix-run/router": "1.23.0",
- "react-router": "6.30.0"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "peerDependencies": {
- "react": ">=16.8",
- "react-dom": ">=16.8"
- }
- },
- "node_modules/read-cache": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
- "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
- "dev": true,
- "dependencies": {
- "pify": "^2.3.0"
- }
- },
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/redux": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
- "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.9.2"
- }
- },
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/resolve": {
- "version": "1.22.8",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
- "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "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==",
- "dev": true,
- "dependencies": {
- "@types/estree": "1.0.6"
- },
- "bin": {
- "rollup": "dist/bin/rollup"
- },
- "engines": {
- "node": ">=18.0.0",
- "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",
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
- "node_modules/scheduler": {
- "version": "0.23.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
- "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
- },
- "node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/signal-exit": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
- "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
- "dev": true,
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/string-width": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
- "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
- "dev": true,
- "dependencies": {
- "eastasianwidth": "^0.2.0",
- "emoji-regex": "^9.2.2",
- "strip-ansi": "^7.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/string-width-cjs": {
- "name": "string-width",
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width-cjs/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width-cjs/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "node_modules/string-width-cjs/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^6.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/strip-ansi-cjs": {
- "name": "strip-ansi",
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/sucrase": {
- "version": "3.35.0",
- "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
- "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
- "dev": true,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.3.2",
- "commander": "^4.0.0",
- "glob": "^10.3.10",
- "lines-and-columns": "^1.1.6",
- "mz": "^2.7.0",
- "pirates": "^4.0.1",
- "ts-interface-checker": "^0.1.9"
- },
- "bin": {
- "sucrase": "bin/sucrase",
- "sucrase-node": "bin/sucrase-node"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- }
- },
- "node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/tailwindcss": {
- "version": "3.4.13",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz",
- "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==",
- "dev": true,
- "dependencies": {
- "@alloc/quick-lru": "^5.2.0",
- "arg": "^5.0.2",
- "chokidar": "^3.5.3",
- "didyoumean": "^1.2.2",
- "dlv": "^1.1.3",
- "fast-glob": "^3.3.0",
- "glob-parent": "^6.0.2",
- "is-glob": "^4.0.3",
- "jiti": "^1.21.0",
- "lilconfig": "^2.1.0",
- "micromatch": "^4.0.5",
- "normalize-path": "^3.0.0",
- "object-hash": "^3.0.0",
- "picocolors": "^1.0.0",
- "postcss": "^8.4.23",
- "postcss-import": "^15.1.0",
- "postcss-js": "^4.0.1",
- "postcss-load-config": "^4.0.1",
- "postcss-nested": "^6.0.1",
- "postcss-selector-parser": "^6.0.11",
- "resolve": "^1.22.2",
- "sucrase": "^3.32.0"
- },
- "bin": {
- "tailwind": "lib/cli.js",
- "tailwindcss": "lib/cli.js"
- },
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "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==",
- "dev": true
- },
- "node_modules/thenify": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
- "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
- "dev": true,
- "dependencies": {
- "any-promise": "^1.0.0"
- }
- },
- "node_modules/thenify-all": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
- "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
- "dev": true,
- "dependencies": {
- "thenify": ">= 3.1.0 < 4"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/tiny-invariant": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
- "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
- "license": "MIT"
- },
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/ts-api-utils": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
- "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
- "dev": true,
- "engines": {
- "node": ">=16"
- },
- "peerDependencies": {
- "typescript": ">=4.2.0"
- }
- },
- "node_modules/ts-interface-checker": {
- "version": "0.1.13",
- "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
- "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
- "dev": true
- },
- "node_modules/tslib": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
- "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "license": "0BSD"
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/typescript": {
- "version": "5.6.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
- "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
- "dev": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/typescript-eslint": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.1.tgz",
- "integrity": "sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/eslint-plugin": "8.8.1",
- "@typescript-eslint/parser": "8.8.1",
- "@typescript-eslint/utils": "8.8.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/undici-types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
- "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
- "license": "MIT"
- },
- "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==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "escalade": "^3.2.0",
- "picocolors": "^1.1.0"
- },
- "bin": {
- "update-browserslist-db": "cli.js"
- },
- "peerDependencies": {
- "browserslist": ">= 4.21.0"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/use-memo-one": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz",
- "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==",
- "license": "MIT",
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- }
- },
- "node_modules/util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true
- },
- "node_modules/vite": {
- "version": "5.4.8",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
- "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
- "dev": true,
- "dependencies": {
- "esbuild": "^0.21.3",
- "postcss": "^8.4.43",
- "rollup": "^4.20.0"
- },
- "bin": {
- "vite": "bin/vite.js"
- },
- "engines": {
- "node": "^18.0.0 || >=20.0.0"
- },
- "funding": {
- "url": "https://github.com/vitejs/vite?sponsor=1"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.3"
- },
- "peerDependencies": {
- "@types/node": "^18.0.0 || >=20.0.0",
- "less": "*",
- "lightningcss": "^1.21.0",
- "sass": "*",
- "sass-embedded": "*",
- "stylus": "*",
- "sugarss": "*",
- "terser": "^5.4.0"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- },
- "less": {
- "optional": true
- },
- "lightningcss": {
- "optional": true
- },
- "sass": {
- "optional": true
- },
- "sass-embedded": {
- "optional": true
- },
- "stylus": {
- "optional": true
- },
- "sugarss": {
- "optional": true
- },
- "terser": {
- "optional": true
- }
- }
- },
- "node_modules/web-vitals": {
- "version": "4.2.4",
- "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
- "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
- "license": "Apache-2.0"
- },
- "node_modules/websocket-driver": {
- "version": "0.7.4",
- "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
- "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
- "license": "Apache-2.0",
- "dependencies": {
- "http-parser-js": ">=0.5.1",
- "safe-buffer": ">=5.1.0",
- "websocket-extensions": ">=0.1.1"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/websocket-extensions": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
- "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/word-wrap": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
- "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrap-ansi": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
- "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^6.1.0",
- "string-width": "^5.0.1",
- "strip-ansi": "^7.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrap-ansi-cjs": {
- "name": "wrap-ansi",
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/wrap-ansi-cjs/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/wrap-ansi-cjs/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "node_modules/wrap-ansi-cjs/node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/wrap-ansi/node_modules/ansi-styles": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
- "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "license": "ISC",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/yallist": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
- "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
- "dev": true
- },
- "node_modules/yaml": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz",
- "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==",
- "dev": true,
- "bin": {
- "yaml": "bin.mjs"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "license": "MIT",
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "license": "ISC",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yargs/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yargs/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "license": "MIT"
- },
- "node_modules/yargs/node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yargs/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- }
- }
-}
diff --git a/Frontend/package.json b/Frontend/package.json
deleted file mode 100644
index ef17b46..0000000
--- a/Frontend/package.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "name": "taskboard-pro",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "vite build",
- "lint": "eslint .",
- "preview": "vite preview"
- },
- "dependencies": {
- "axios": "^1.9.0",
- "firebase": "^11.7.3",
- "framer-motion": "^10.17.4",
- "lucide-react": "^0.344.0",
- "prop-types": "^15.8.1",
- "react": "^18.3.1",
- "react-beautiful-dnd": "^13.1.1",
- "react-dom": "^18.3.1",
- "react-router-dom": "^6.22.1"
- },
- "devDependencies": {
- "@eslint/js": "^9.9.1",
- "@types/react": "^18.3.5",
- "@types/react-dom": "^18.3.0",
- "@vitejs/plugin-react": "^4.3.1",
- "autoprefixer": "^10.4.18",
- "eslint": "^9.9.1",
- "eslint-plugin-react-hooks": "^5.1.0-rc.0",
- "eslint-plugin-react-refresh": "^0.4.11",
- "globals": "^15.9.0",
- "postcss": "^8.4.35",
- "tailwindcss": "^3.4.1",
- "typescript": "^5.5.3",
- "typescript-eslint": "^8.3.0",
- "vite": "^5.4.2"
- }
-}
diff --git a/Frontend/postcss.config.js b/Frontend/postcss.config.js
deleted file mode 100644
index 2aa7205..0000000
--- a/Frontend/postcss.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
-};
diff --git a/Frontend/src/App.jsx b/Frontend/src/App.jsx
deleted file mode 100644
index bb5c7a2..0000000
--- a/Frontend/src/App.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
-import { auth } from './firebase/config';
-import { registerUserAfterGoogleLogin } from './services/userService';
-import { AuthProvider } from './context/AuthContext';
-import LoginPage from './pages/LoginPage';
-import DashboardPage from './pages/DashboardPage';
-import ProjectPage from './pages/ProjectPage';
-import AutomationPage from './pages/AutomationPage';
-import HomePage from './pages/HomePage';
-
-// AuthRoute component to protect routes that require authentication
-const AuthRoute = ({ children }) => {
- const [authChecked, setAuthChecked] = useState(false);
- const [isAuthenticated, setIsAuthenticated] = useState(false);
-
- useEffect(() => {
- const unsubscribe = auth.onAuthStateChanged((user) => {
- setIsAuthenticated(!!user);
- setAuthChecked(true);
-
- // If user exists and logs in, ensure their data is in MongoDB
- if (user) {
- registerUserAfterGoogleLogin(user)
- .catch(error => console.error('Error updating user data:', error));
- }
- });
-
- return () => unsubscribe();
- }, []);
-
- if (!authChecked) {
- return ;
- }
-
- return isAuthenticated ? children : ;
-};
-
-function App() {
- return (
-
-
-
- {/* Public routes */}
- } />
- } />
-
- {/* Protected routes */}
-
-
-
- } />
-
-
-
- } />
-
-
-
- } />
-
- {/* Fallback route */}
- } />
-
-
-
- );
-}
-
-export default App;
diff --git a/Frontend/src/assets/mockData.jsx b/Frontend/src/assets/mockData.jsx
deleted file mode 100644
index 4e4e80b..0000000
--- a/Frontend/src/assets/mockData.jsx
+++ /dev/null
@@ -1,129 +0,0 @@
-export const projects = [
- {
- id: '1',
- title: 'Website Redesign',
- description: 'Redesign company website with modern UI/UX',
- progress: 68,
- members: [
- { id: '1', name: 'Alex Johnson', avatar: 'https://i.pravatar.cc/150?img=1' },
- { id: '2', name: 'Maya Patel', avatar: 'https://i.pravatar.cc/150?img=5' },
- { id: '3', name: 'David Kim', avatar: 'https://i.pravatar.cc/150?img=3' }
- ],
- createdAt: '2023-09-15',
- dueDate: '2023-12-10'
- },
- {
- id: '2',
- title: 'Mobile App Development',
- description: 'Build a cross-platform mobile app for client management',
- progress: 42,
- members: [
- { id: '2', name: 'Maya Patel', avatar: 'https://i.pravatar.cc/150?img=5' },
- { id: '4', name: 'Sarah Lee', avatar: 'https://i.pravatar.cc/150?img=4' }
- ],
- createdAt: '2023-10-01',
- dueDate: '2023-12-31'
- },
- {
- id: '3',
- title: 'Marketing Campaign',
- description: 'Q4 marketing campaign for product launch',
- progress: 24,
- members: [
- { id: '1', name: 'Alex Johnson', avatar: 'https://i.pravatar.cc/150?img=1' },
- { id: '3', name: 'David Kim', avatar: 'https://i.pravatar.cc/150?img=3' },
- { id: '5', name: 'James Wilson', avatar: 'https://i.pravatar.cc/150?img=12' }
- ],
- createdAt: '2023-10-15',
- dueDate: '2024-01-15'
- }
-];
-
-export const tasks = {
- 'todo': [
- {
- id: 't1',
- title: 'Research competitors',
- description: 'Analyze top 5 competitors in the market',
- priority: 'high',
- assignee: { id: '1', name: 'Alex Johnson', avatar: 'https://i.pravatar.cc/150?img=1' },
- dueDate: '2023-11-05',
- labels: ['research', 'marketing']
- },
- {
- id: 't2',
- title: 'Create wireframes',
- description: 'Design initial wireframes for homepage',
- priority: 'medium',
- assignee: { id: '2', name: 'Maya Patel', avatar: 'https://i.pravatar.cc/150?img=5' },
- dueDate: '2023-11-10',
- labels: ['design', 'ui/ux']
- }
- ],
- 'in-progress': [
- {
- id: 't3',
- title: 'Develop API endpoints',
- description: 'Create backend API endpoints for user authentication',
- priority: 'high',
- assignee: { id: '3', name: 'David Kim', avatar: 'https://i.pravatar.cc/150?img=3' },
- dueDate: '2023-11-15',
- labels: ['development', 'backend']
- },
- {
- id: 't4',
- title: 'User testing plan',
- description: 'Create a comprehensive user testing plan',
- priority: 'low',
- assignee: { id: '4', name: 'Sarah Lee', avatar: 'https://i.pravatar.cc/150?img=4' },
- dueDate: '2023-11-20',
- labels: ['testing', 'ux']
- }
- ],
- 'done': [
- {
- id: 't5',
- title: 'Project kickoff meeting',
- description: 'Initial meeting with stakeholders to define project scope',
- priority: 'medium',
- assignee: { id: '1', name: 'Alex Johnson', avatar: 'https://i.pravatar.cc/150?img=1' },
- dueDate: '2023-10-25',
- labels: ['meeting', 'planning']
- }
- ]
-};
-
-export const automationRules = [
- {
- id: 'r1',
- name: 'Assign high priority tasks to team lead',
- condition: {
- type: 'priority',
- value: 'high'
- },
- action: {
- type: 'assign',
- value: { id: '1', name: 'Alex Johnson' }
- }
- },
- {
- id: 'r2',
- name: 'Move completed tasks to Done column',
- condition: {
- type: 'status',
- value: 'completed'
- },
- action: {
- type: 'move',
- value: 'done'
- }
- }
-];
-
-export const user = {
- id: 'u1',
- name: 'Alex Johnson',
- email: 'alex@example.com',
- avatar: 'https://i.pravatar.cc/150?img=1',
- role: 'Product Manager'
-};
diff --git a/Frontend/src/components/automation/RuleCreationForm.jsx b/Frontend/src/components/automation/RuleCreationForm.jsx
deleted file mode 100644
index 191b631..0000000
--- a/Frontend/src/components/automation/RuleCreationForm.jsx
+++ /dev/null
@@ -1,384 +0,0 @@
-import React, { useState } from 'react';
-import { motion } from 'framer-motion';
-import Button from '../ui/Button';
-import { Zap, Plus } from 'lucide-react';
-
-import PropTypes from 'prop-types';
-
-const RuleCreationForm = ({
- onCreateRule
-}) => {
- const [ruleName, setRuleName] = useState('');
- const [trigger, setTrigger] = useState({
- type: 'STATUS_CHANGE',
- fromStatus: 'To Do',
- toStatus: 'In Progress'
- });
- const [action, setAction] = useState({
- type: 'SEND_NOTIFICATION',
- notificationText: '',
- notifyAssignee: true,
- notifyCreator: false,
- notifyProjectOwners: false
- });
-
- const triggerTypes = [
- {
- id: 'STATUS_CHANGE',
- name: 'Task Status Changes',
- hasAdditionalFields: true
- },
- {
- id: 'ASSIGNMENT_CHANGE',
- name: 'Task Assignment Changes',
- hasAdditionalFields: true
- },
- {
- id: 'DUE_DATE_PASSED',
- name: 'Task Due Date Passes',
- hasAdditionalFields: false
- }
- ];
-
- const actionTypes = [
- {
- id: 'ASSIGN_BADGE',
- name: 'Assign Badge',
- hasAdditionalFields: true
- },
- {
- id: 'MOVE_TASK',
- name: 'Move Task',
- hasAdditionalFields: true
- },
- {
- id: 'SEND_NOTIFICATION',
- name: 'Send Notification',
- hasAdditionalFields: true
- }
- ];
-
- const statusOptions = ['To Do', 'In Progress', 'Review', 'Done'];
-
- const handleSubmit = (e) => {
- e.preventDefault();
-
- if (!ruleName) return;
-
- const newRule = {
- name: ruleName,
- trigger,
- action,
- isActive: true
- };
-
- onCreateRule(newRule);
- setRuleName('');
- };
-
- const handleTriggerTypeChange = (e) => {
- const type = e.target.value;
-
- let newTrigger = { type };
-
- // Add appropriate fields based on trigger type
- switch (type) {
- case 'STATUS_CHANGE':
- newTrigger = {
- ...newTrigger,
- fromStatus: 'To Do',
- toStatus: 'In Progress'
- };
- break;
- case 'ASSIGNMENT_CHANGE':
- newTrigger = {
- ...newTrigger,
- assigneeEmail: ''
- };
- break;
- case 'DUE_DATE_PASSED':
- // No additional fields needed
- break;
- default:
- break;
- }
-
- setTrigger(newTrigger);
- };
-
- const handleActionTypeChange = (e) => {
- const type = e.target.value;
-
- let newAction = { type };
-
- // Add appropriate fields based on action type
- switch (type) {
- case 'ASSIGN_BADGE':
- newAction = {
- ...newAction,
- badgeName: 'Achiever'
- };
- break;
- case 'MOVE_TASK':
- newAction = {
- ...newAction,
- targetStatus: 'Done'
- };
- break;
- case 'SEND_NOTIFICATION':
- newAction = {
- ...newAction,
- notificationText: '',
- notifyAssignee: true,
- notifyCreator: false,
- notifyProjectOwners: false
- };
- break;
- default:
- break;
- }
-
- setAction(newAction);
- };
-
- const renderTriggerFields = () => {
- switch (trigger.type) {
- case 'STATUS_CHANGE':
- return (
-
-
-
-
-
-
-
-
-
-
- );
- case 'ASSIGNMENT_CHANGE':
- return (
-
-
- setTrigger({...trigger, assigneeEmail: e.target.value})}
- className="w-full px-4 py-2 bg-[#1A1A1A] border border-[#333333] rounded-md text-white focus:outline-none focus:ring-2 focus:ring-[#1DCD9F]/50 focus:border-transparent transition"
- placeholder="example@email.com"
- />
-
- );
- case 'DUE_DATE_PASSED':
- return (
-
- This trigger will activate when a task's due date passes.
-
- );
- default:
- return null;
- }
- };
-
- const renderActionFields = () => {
- switch (action.type) {
- case 'ASSIGN_BADGE':
- return (
-
-
- setAction({...action, badgeName: e.target.value})}
- className="w-full px-4 py-2 bg-[#1A1A1A] border border-[#333333] rounded-md text-white focus:outline-none focus:ring-2 focus:ring-[#1DCD9F]/50 focus:border-transparent transition"
- placeholder="e.g., Achiever, Fast Completer"
- />
-
- );
- case 'MOVE_TASK':
- return (
-
-
-
-
- );
- case 'SEND_NOTIFICATION':
- return (
-
-
-
-
-
-
- );
- default:
- return null;
- }
- };
-
- return (
-
-
-
- Create Automation Rule
-
-
-
-
- );
-};
-
-RuleCreationForm.propTypes = {
- onCreateRule: PropTypes.func.isRequired,
-};
-
-export default RuleCreationForm;
\ No newline at end of file
diff --git a/Frontend/src/components/automation/RulePreview.jsx b/Frontend/src/components/automation/RulePreview.jsx
deleted file mode 100644
index 85c1851..0000000
--- a/Frontend/src/components/automation/RulePreview.jsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import React from 'react';
-import { motion } from 'framer-motion';
-import { ArrowRight, AlertTriangle, Trash2, Zap, Bell, Tag, ArrowRight as MoveIcon } from 'lucide-react';
-import Button from '../ui/Button';
-import PropTypes from 'prop-types';
-
-const RulePreview = ({ rule, onDeleteRule }) => {
- const getTriggerDisplay = () => {
- let triggerType = '';
- let triggerDetails = '';
-
- switch (rule.trigger.type) {
- case 'STATUS_CHANGE':
- triggerType = 'Task status changes';
- triggerDetails = `from "${rule.trigger.fromStatus}" to "${rule.trigger.toStatus}"`;
- break;
- case 'ASSIGNMENT_CHANGE':
- triggerType = 'Task is assigned';
- triggerDetails = rule.trigger.assigneeEmail ?
- `to ${rule.trigger.assigneeEmail}` : 'to someone';
- break;
- case 'DUE_DATE_PASSED':
- triggerType = 'Task due date passes';
- triggerDetails = '';
- break;
- default:
- triggerType = rule.trigger.type;
- triggerDetails = '';
- }
-
- return { triggerType, triggerDetails };
- };
-
- const getActionDisplay = () => {
- let actionType = '';
- let actionDetails = '';
- let actionIcon = ;
-
- switch (rule.action.type) {
- case 'ASSIGN_BADGE':
- actionType = 'Assign badge';
- actionDetails = rule.action.badgeName || 'to user';
- actionIcon = ;
- break;
- case 'MOVE_TASK':
- actionType = 'Move task';
- actionDetails = `to "${rule.action.targetStatus}"`;
- actionIcon = ;
- break;
- case 'SEND_NOTIFICATION':
- actionType = 'Send notification';
- const recipients = [];
- if (rule.action.notifyAssignee) recipients.push('assignee');
- if (rule.action.notifyCreator) recipients.push('creator');
- if (rule.action.notifyProjectOwners) recipients.push('project owners');
-
- actionDetails = recipients.length > 0 ?
- `to ${recipients.join(', ')}` :
- rule.action.notificationText ?
- `"${rule.action.notificationText.substring(0, 20)}${rule.action.notificationText.length > 20 ? '...' : ''}"` :
- '';
- actionIcon = ;
- break;
- default:
- actionType = rule.action.type;
- actionDetails = '';
- }
-
- return { actionType, actionDetails, actionIcon };
- };
-
- const { triggerType, triggerDetails } = getTriggerDisplay();
- const { actionType, actionDetails, actionIcon } = getActionDisplay();
-
- return (
-
-
-
{rule.name}
-
- {!rule.isActive && (
-
-
- Disabled
-
- )}
-
-
-
-
-
-
-
- When {triggerType}{' '}
- {triggerDetails && (
- {triggerDetails}
- )}
-
-
-
-
-
-
-
-
- {actionIcon} {actionType}
- {' '}
- {actionDetails && (
- {actionDetails}
- )}
-
-
-
-
- {rule.action.type === 'SEND_NOTIFICATION' && rule.action.notificationText && (
-
-
- "{rule.action.notificationText}"
-
-
- )}
-
- );
-};
-
-RulePreview.propTypes = {
- rule: PropTypes.shape({
- _id: PropTypes.string,
- name: PropTypes.string.isRequired,
- trigger: PropTypes.object.isRequired,
- action: PropTypes.object.isRequired,
- isActive: PropTypes.bool
- }).isRequired,
- onDeleteRule: PropTypes.func.isRequired
-};
-
-export default RulePreview;
\ No newline at end of file
diff --git a/Frontend/src/components/dashboard/CreateProjectModal.jsx b/Frontend/src/components/dashboard/CreateProjectModal.jsx
deleted file mode 100644
index f0608d8..0000000
--- a/Frontend/src/components/dashboard/CreateProjectModal.jsx
+++ /dev/null
@@ -1,148 +0,0 @@
-import React, { useState } from 'react';
-import Modal from '../ui/Modal';
-import Button from '../ui/Button';
-import { Calendar } from 'lucide-react';
-
-/**
- * @typedef {Object} CreateProjectModalProps
- * @property {boolean} isOpen
- * @property {() => void} onClose
- * @property {(project: any) => void} onCreateProject
- */
-
-/**
- * Modal for creating a new project
- * @param {CreateProjectModalProps} props
- */
-const CreateProjectModal = ({
- isOpen,
- onClose,
- onCreateProject
-}) => {
- const [formData, setFormData] = useState({
- title: '',
- description: '',
- dueDate: ''
- });
-
- const [isLoading, setIsLoading] = useState(false);
-
- /**
- * Handle form input changes
- * @param {React.ChangeEvent} e
- */
- const handleChange = (e) => {
- const { name, value } = e.target;
- setFormData(prev => ({ ...prev, [name]: value }));
- };
-
- /**
- * Handle form submission
- * @param {React.FormEvent} e
- */
- const handleSubmit = async (e) => {
- e.preventDefault();
-
- if (!formData.title || !formData.description || !formData.dueDate) {
- return;
- }
-
- setIsLoading(true);
-
- try {
- const projectData = {
- ...formData
- };
-
- await onCreateProject(projectData);
- setFormData({ title: '', description: '', dueDate: '' });
- onClose();
- } catch (error) {
- console.error('Error creating project:', error);
- } finally {
- setIsLoading(false);
- }
- };
-
- const modalFooter = (
-
-
-
-
- );
-
- return (
-
-
-
- );
-};
-
-export default CreateProjectModal;
diff --git a/Frontend/src/components/dashboard/ProjectCard.jsx b/Frontend/src/components/dashboard/ProjectCard.jsx
deleted file mode 100644
index 0ffe570..0000000
--- a/Frontend/src/components/dashboard/ProjectCard.jsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import React from 'react';
-import { motion } from 'framer-motion';
-import { Link } from 'react-router-dom';
-import { Calendar, Users } from 'lucide-react';
-
-/**
- * @typedef {Object} Member
- * @property {string} id
- * @property {string} name
- * @property {string} avatar
- */
-
-/**
- * @typedef {Object} ProjectCardProps
- * @property {string} id
- * @property {string} _id
- * @property {string} title
- * @property {string} description
- * @property {number} progress
- * @property {Member[]} members
- * @property {string} createdAt
- * @property {string} dueDate
- * @property {number} [index=0]
- */
-
-/**
- * Project card component
- * @param {ProjectCardProps} props
- */
-const ProjectCard = ({
- id,
- _id,
- title,
- description,
- progress = 0,
- members = [],
- dueDate,
- index = 0
-}) => {
- // Ensure we have a valid project ID
- const projectId = id || _id;
-
- // Ensure members is always an array
- const membersList = Array.isArray(members) ? members : [];
-
- const formatDate = (dateString) => {
- if (!dateString) return 'Not set';
- const date = new Date(dateString);
- return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
- };
-
- return (
-
-
-
-
-
{title}
-
- {progress}% Complete
-
-
-
-
{description}
-
-
-
-
- Due: {formatDate(dueDate)}
-
-
-
-
- {membersList.length} members
-
-
-
-
-
- {membersList.length > 0 ? (
- <>
- {membersList.slice(0, 3).map((member) => (
-

- ))}
- {membersList.length > 3 && (
-
- +{membersList.length - 3}
-
- )}
- >
- ) : (
-
-
-
- )}
-
-
-
-
-
-
-
- );
-};
-
-export default ProjectCard;
diff --git a/Frontend/src/components/home/HeroSection.jsx b/Frontend/src/components/home/HeroSection.jsx
deleted file mode 100644
index 4595aa2..0000000
--- a/Frontend/src/components/home/HeroSection.jsx
+++ /dev/null
@@ -1,232 +0,0 @@
-import React from 'react';
-import { motion } from 'framer-motion';
-import { Link } from 'react-router-dom';
-import Button from '../ui/Button';
-import { ArrowRight, CheckCircle, BarChart, Users, Zap, PieChart } from 'lucide-react';
-
-const HeroSection = () => {
- const containerVariants = {
- hidden: { opacity: 0 },
- visible: {
- opacity: 1,
- transition: {
- staggerChildren: 0.2
- }
- }
- };
-
- const itemVariants = {
- hidden: { y: 20, opacity: 0 },
- visible: {
- y: 0,
- opacity: 1,
- transition: {
- type: 'spring',
- stiffness: 100,
- damping: 15
- }
- }
- };
-
- const features = [
- 'Intuitive Kanban boards',
- 'Real-time collaboration',
- 'Powerful automation',
- 'Advanced reporting'
- ];
-
- const featuresDetailed = [
- {
- title: 'Intuitive Kanban Boards',
- description: 'Visualize your workflow with customizable boards that make project management simple and effective.',
- icon:
- },
- {
- title: 'Real-time Collaboration',
- description: 'Work together with your team in real-time with instant updates and seamless communication.',
- icon:
- },
- {
- title: 'Powerful Automation',
- description: 'Save time with automated workflows that handle repetitive tasks and keep your projects moving forward.',
- icon:
- },
- {
- title: 'Advanced Reporting',
- description: 'Gain valuable insights with detailed reports and analytics to keep your projects on track.',
- icon:
- }
- ];
-
- return (
- <>
-
- {/* Background gradient effect */}
-
-
-
-
-
-
-
-
- Project Management Reimagined
-
-
-
- Collaborate and
- deliver with TaskBoard Pro
-
-
-
- Streamline your workflow, increase productivity, and deliver projects on time with our powerful and intuitive project management platform.
-
-
-
-
- }>
- Get Started
-
-
-
-
-
-
- {features.map((feature, index) => (
-
-
- {feature}
-
- ))}
-
-
-
-
-
-
-
-
-
-
- {["To Do", "In Progress", "Done"].map((column, colIndex) => (
-
- {column}
-
- {[1, 2, 3].map((task, taskIndex) => (
-
-
- Task {colIndex + 1}.{taskIndex + 1}
-
-
-
- ))}
-
- ))}
-
-
-
-
-
-
-
- {/* Features Section */}
-
-
-
-
-
-
- Powerful Features for Your Projects
-
- TaskBoard Pro comes packed with all the tools you need to manage your projects efficiently and effectively.
-
-
-
-
- {featuresDetailed.map((feature, index) => (
-
-
- {feature.icon}
-
- {feature.title}
- {feature.description}
-
- ))}
-
-
-
-
-
-
-
-
-
- >
- );
-};
-
-export default HeroSection;
\ No newline at end of file
diff --git a/Frontend/src/components/project/AddTaskModal.jsx b/Frontend/src/components/project/AddTaskModal.jsx
deleted file mode 100644
index eb921ff..0000000
--- a/Frontend/src/components/project/AddTaskModal.jsx
+++ /dev/null
@@ -1,485 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import Modal from '../ui/Modal';
-import Button from '../ui/Button';
-import { Calendar, Tag, AlertCircle, User, PlusCircle } from 'lucide-react';
-
-const AddTaskModal = ({
- isOpen,
- onClose,
- onTaskCreated,
- columnType,
- teamMembers = [],
- isLoading
-}) => {
- const [formData, setFormData] = useState({
- title: '',
- description: '',
- priority: 'medium', // Set default priority to medium
- dueDate: '',
- assigneeId: '',
- labels: [],
- status: columnTypeToStatus(columnType)
- });
-
- const [validationError, setValidationError] = useState(null);
- const [isAddingCustomStatus, setIsAddingCustomStatus] = useState(false);
- const [customStatus, setCustomStatus] = useState('');
-
- function columnTypeToStatus(type) {
- const statusMap = {
- 'todo': 'To Do',
- 'in-progress': 'In Progress',
- 'done': 'Done'
- };
- return statusMap[type] || 'To Do';
- }
-
- useEffect(() => {
- if (teamMembers && teamMembers.length > 0) {
- setFormData(prev => ({
- ...prev,
- assigneeId: prev.assigneeId || teamMembers[0].id || teamMembers[0].userId || ''
- }));
- } else {
- // Reset assigneeId if no team members are available
- setFormData(prev => ({
- ...prev,
- assigneeId: ''
- }));
- }
- }, [teamMembers]);
-
- // Log team members for debugging
- useEffect(() => {
- console.log("TeamMembers in AddTaskModal:", teamMembers);
- }, [teamMembers]);
-
- useEffect(() => {
- setFormData(prev => ({
- ...prev,
- status: columnTypeToStatus(columnType)
- }));
- }, [columnType]);
-
- // Reset form when modal opens
- useEffect(() => {
- if (isOpen) {
- setFormData({
- title: '',
- description: '',
- priority: 'medium', // Set default priority to medium
- dueDate: '',
- assigneeId: teamMembers.length > 0 ? teamMembers[0].id || teamMembers[0].userId : '',
- labels: [],
- status: columnTypeToStatus(columnType)
- });
- }
- }, [isOpen, columnType, teamMembers]);
-
- const availableLabels = [
- 'design', 'development', 'marketing', 'research', 'testing', 'planning', 'ui/ux', 'backend', 'frontend'
- ];
-
- const handleChange = (e) => {
- const { name, value } = e.target;
- console.log(`Updating ${name} to ${value}`); // Debug log
- setFormData(prev => ({ ...prev, [name]: value }));
- setValidationError(null); // Clear validation errors on change
- };
-
- const toggleLabel = (label) => {
- setFormData(prev => ({
- ...prev,
- labels: prev.labels.includes(label)
- ? prev.labels.filter(l => l !== label)
- : [...prev.labels, label]
- }));
- console.log("Updated labels:", formData.labels); // Debug log for labels
- };
-
- const handleSubmit = (e) => {
- e.preventDefault();
-
- // Basic form validation
- if (!formData.title) {
- setValidationError("Title is required");
- return;
- }
-
- if (!formData.description) {
- setValidationError("Description is required");
- return;
- }
-
- if (!formData.dueDate) {
- setValidationError("Due date is required");
- return;
- }
-
- if (!formData.priority) {
- setValidationError("Please select a priority");
- return;
- }
-
- // Validate assignee if team members exist
- if (teamMembers.length > 0 && !formData.assigneeId) {
- setValidationError("Please select an assignee");
- return;
- }
-
- // Find the selected assignee from team members
- const assignee = teamMembers.find(member =>
- (member.id === formData.assigneeId) ||
- (member.userId === formData.assigneeId)
- );
-
- if (!assignee && teamMembers.length > 0) {
- setValidationError("Selected assignee is not a team member");
- return;
- }
-
- // Prepare the task data for creation
- const taskData = {
- ...formData,
- status: columnTypeToStatus(columnType)
- };
-
- // Debug log to verify the priority being sent
- console.log("Creating task with priority:", taskData.priority);
- console.log("Creating task with labels:", taskData.labels);
-
- // Only add assignee data if an assignee was selected
- if (assignee) {
- // Instead of embedding full assignee object, just send the email
- // The backend expects an email and will handle the rest
- taskData.assignee = assignee.email;
- }
-
- onTaskCreated(taskData);
-
- // Don't reset the form here, we'll do it when the modal opens
- setValidationError(null);
- };
-
- const modalFooter = (
-
-
-
-
- );
-
- const columnTitles = {
- 'todo': 'To Do',
- 'in-progress': 'In Progress',
- 'done': 'Done'
- };
-
- return (
-
- {validationError && (
-
- )}
-
-
-
- );
-};
-
-export default AddTaskModal;
diff --git a/Frontend/src/components/project/InviteMemberModal.jsx b/Frontend/src/components/project/InviteMemberModal.jsx
deleted file mode 100644
index fb084f7..0000000
--- a/Frontend/src/components/project/InviteMemberModal.jsx
+++ /dev/null
@@ -1,287 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { motion } from 'framer-motion';
-import Modal from '../ui/Modal';
-import Button from '../ui/Button';
-import { Search, Mail, AlertCircle, Check, X, User } from 'lucide-react';
-import { getUsersByEmail } from '../../services/userService';
-import { inviteUserToProject, removeUserFromProject } from '../../services/projectService';
-
-const InviteMemberModal = ({ isOpen, onClose, projectId, currentMembers = [], onMembersUpdated }) => {
- const [searchEmail, setSearchEmail] = useState('');
- const [searchResults, setSearchResults] = useState([]);
- const [members, setMembers] = useState([]);
- const [isLoading, setIsLoading] = useState(false);
- const [searchPerformed, setSearchPerformed] = useState(false);
- const [error, setError] = useState(null);
- const [successMessage, setSuccessMessage] = useState(null);
-
- // Initialize members from currentMembers prop
- useEffect(() => {
- if (currentMembers && currentMembers.length > 0) {
- setMembers(currentMembers);
- }
- }, [currentMembers]);
-
- const handleSearch = async (e) => {
- e.preventDefault();
-
- if (!searchEmail.trim()) return;
-
- try {
- setIsLoading(true);
- setError(null);
- const result = await getUsersByEmail(searchEmail);
-
- // Filter out users who are already members
- const filteredResults = Array.isArray(result) ? result.filter(user => {
- return !members.some(member =>
- (member.email === user.email) ||
- (member.userId === user.uid) ||
- (member.id === user.id)
- );
- }) : [];
-
- setSearchResults(filteredResults);
- setSearchPerformed(true);
- } catch (err) {
- console.error("Error searching for users:", err);
- setError("Failed to search for users. Please try again.");
- setSearchResults([]);
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleInvite = async (email) => {
- try {
- setIsLoading(true);
- setError(null);
- const result = await inviteUserToProject(projectId, email);
-
- setSuccessMessage(`Successfully invited ${email} to the project!`);
- // Clear search results and input
- setSearchEmail('');
- setSearchResults([]);
- setSearchPerformed(false);
-
- // Update members list with the new member
- if (result.project && result.project.members) {
- const updatedMembers = result.project.members.map(member => ({
- id: member.userId,
- userId: member.userId,
- email: member.email,
- name: member.name || member.email.split('@')[0],
- avatar: member.photoURL || `https://ui-avatars.com/api/?name=${encodeURIComponent(member.email)}&background=1A1A1A&color=FFFFFF`,
- role: member.role
- }));
-
- setMembers(updatedMembers);
-
- // Notify parent component about the updated members
- if (onMembersUpdated) {
- onMembersUpdated(updatedMembers);
- }
- }
-
- // Clear success message after 3 seconds
- setTimeout(() => {
- setSuccessMessage(null);
- }, 3000);
- } catch (err) {
- console.error("Error inviting user:", err);
- setError(err.response?.data?.message || "Failed to invite user. Please try again.");
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleRemoveMember = async (userId) => {
- try {
- setIsLoading(true);
- setError(null);
- await removeUserFromProject(projectId, userId);
-
- // Update the members list
- const updatedMembers = members.filter(member =>
- (member.userId !== userId) && (member.id !== userId)
- );
- setMembers(updatedMembers);
-
- // Notify parent component
- if (onMembersUpdated) {
- onMembersUpdated(updatedMembers);
- }
-
- setSuccessMessage("Team member removed successfully.");
-
- // Clear success message after 3 seconds
- setTimeout(() => {
- setSuccessMessage(null);
- }, 3000);
- } catch (err) {
- console.error("Error removing team member:", err);
- setError("Failed to remove team member. Please try again.");
- } finally {
- setIsLoading(false);
- }
- };
-
- const modalFooter = (
-
-
-
- );
-
- return (
-
-
- {error && (
-
- )}
-
- {successMessage && (
-
-
- {successMessage}
-
- )}
-
-
-
Invite Team Members
-
-
- {searchPerformed && (
-
- {searchResults.length === 0 ? (
-
-
No users found with that email.
-
-
- ) : (
-
- {searchResults.map((user) => (
- -
-
-

-
-
{user.name}
-
{user.email}
-
-
-
-
-
- ))}
-
- )}
-
- )}
-
-
-
-
Current Team Members
- {members && members.length > 0 ? (
-
- {members.map((member) => (
-
-
-

-
-
{member.name || member.email}
-
- {member.email}
- {member.role === 'owner' && (
-
- Owner
-
- )}
-
-
-
-
- {member.role !== 'owner' && (
-
- )}
-
- ))}
-
- ) : (
-
-
-
No team members added yet.
-
- )}
-
-
-
- );
-};
-
-export default InviteMemberModal;
diff --git a/Frontend/src/components/project/KanbanBoard.jsx b/Frontend/src/components/project/KanbanBoard.jsx
deleted file mode 100644
index 7e72213..0000000
--- a/Frontend/src/components/project/KanbanBoard.jsx
+++ /dev/null
@@ -1,377 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
-import { PlusCircle, MoreVertical } from "lucide-react";
-import TaskCard from './TaskCard';
-import AddTaskModal from './AddTaskModal';
-import { createTask, moveTask, updateTask, getFrontendStatus, deleteTask } from '../../services/taskService';
-
-const KanbanBoard = ({ projectId, initialTasks = [], teamMembers = [] }) => {
- const [columns, setColumns] = useState({
- 'todo': {
- id: 'todo',
- title: 'To Do',
- tasks: []
- },
- 'in-progress': {
- id: 'in-progress',
- title: 'In Progress',
- tasks: []
- },
- 'done': {
- id: 'done',
- title: 'Done',
- tasks: []
- }
- });
-
- const [isAddTaskModalOpen, setIsAddTaskModalOpen] = useState(false);
- const [activeColumn, setActiveColumn] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState(null);
-
- // Organize tasks into columns
- useEffect(() => {
- if (initialTasks && initialTasks.length > 0) {
- const tasksByStatus = {
- 'todo': [],
- 'in-progress': [],
- 'done': []
- };
-
- initialTasks.forEach(task => {
- // Map backend status to frontend status
- const frontendStatus = getFrontendStatus(task.status || 'To Do');
- if (tasksByStatus[frontendStatus]) {
- tasksByStatus[frontendStatus].push(task);
- } else {
- tasksByStatus['todo'].push(task);
- }
- });
-
- setColumns({
- 'todo': {
- id: 'todo',
- title: 'To Do',
- tasks: tasksByStatus['todo'] || []
- },
- 'in-progress': {
- id: 'in-progress',
- title: 'In Progress',
- tasks: tasksByStatus['in-progress'] || []
- },
- 'done': {
- id: 'done',
- title: 'Done',
- tasks: tasksByStatus['done'] || []
- }
- });
- }
- }, [initialTasks]);
-
- // Add a log to verify teamMembers is passed correctly
- useEffect(() => {
- console.log("Team members in KanbanBoard:", teamMembers);
- }, [teamMembers]);
-
- const handleDragEnd = async (result) => {
- const { destination, source, draggableId } = result;
-
- // Drop outside a droppable area
- if (!destination) return;
-
- // Drop in the same position
- if (
- destination.droppableId === source.droppableId &&
- destination.index === source.index
- ) return;
-
- const sourceColumn = columns[source.droppableId];
- const destColumn = columns[destination.droppableId];
-
- // Move within the same column
- if (sourceColumn === destColumn) {
- const newTasks = Array.from(sourceColumn.tasks);
- const [movedTask] = newTasks.splice(source.index, 1);
- newTasks.splice(destination.index, 0, movedTask);
-
- const newColumn = {
- ...sourceColumn,
- tasks: newTasks
- };
-
- setColumns({
- ...columns,
- [newColumn.id]: newColumn
- });
-
- // No need to update the backend as the status hasn't changed
- return;
- }
-
- // Move to a different column
- // Update locally first for responsive UI
- const sourceTasks = Array.from(sourceColumn.tasks);
- const [movedTask] = sourceTasks.splice(source.index, 1);
-
- const destTasks = Array.from(destColumn.tasks);
- destTasks.splice(destination.index, 0, movedTask);
-
- setColumns({
- ...columns,
- [sourceColumn.id]: {
- ...sourceColumn,
- tasks: sourceTasks
- },
- [destColumn.id]: {
- ...destColumn,
- tasks: destTasks
- }
- });
-
- // Update the task status in the backend
- try {
- setIsLoading(true);
- await moveTask(movedTask._id || movedTask.id, destination.droppableId);
- setError(null);
- } catch (err) {
- console.error('Error moving task:', err);
- setError('Failed to update task position. Please refresh and try again.');
-
- // Revert the UI change on error
- setColumns({
- ...columns,
- [sourceColumn.id]: sourceColumn,
- [destColumn.id]: destColumn
- });
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleAddTask = async (taskData) => {
- try {
- setIsLoading(true);
- console.log("Adding new task with data:", taskData); // Debug log for task creation data
- const newTask = await createTask({
- ...taskData,
- projectId,
- status: activeColumn
- });
-
- console.log("New task created:", newTask); // Debug log for created task
-
- // Update the UI with the returned task
- // Map the backend status to frontend status if needed
- const frontendStatus = getFrontendStatus(newTask.status);
- const columnToUpdate = frontendStatus || activeColumn;
-
- const column = columns[columnToUpdate];
- if (column) {
- const updatedColumn = {
- ...column,
- tasks: [newTask, ...column.tasks]
- };
-
- setColumns({
- ...columns,
- [columnToUpdate]: updatedColumn
- });
- }
-
- setIsAddTaskModalOpen(false);
- setError(null);
- } catch (err) {
- console.error('Error adding task:', err);
- // Extract specific error message if available
- const errorMessage = err.response?.data?.message || 'Failed to add task. Please try again.';
- setError(errorMessage);
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleTaskUpdate = async (taskId, taskData) => {
- try {
- setIsLoading(true);
- const updatedTask = await updateTask(taskId, taskData);
-
- // Update the task in the correct column
- // Map the backend status to frontend status
- const frontendStatus = getFrontendStatus(updatedTask.status);
- const columnId = frontendStatus;
- const column = columns[columnId];
-
- if (column) {
- const taskIndex = column.tasks.findIndex(task => (task._id || task.id) === taskId);
-
- if (taskIndex !== -1) {
- const updatedTasks = [...column.tasks];
- updatedTasks[taskIndex] = updatedTask;
-
- setColumns({
- ...columns,
- [columnId]: {
- ...column,
- tasks: updatedTasks
- }
- });
- }
- }
-
- setError(null);
- } catch (err) {
- console.error('Error updating task:', err);
- const errorMessage = err.response?.data?.message || 'Failed to update task. Please try again.';
- setError(errorMessage);
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleTaskDelete = async (taskId) => {
- try {
- setIsLoading(true);
- console.log("KanbanBoard: Deleting task with ID:", taskId);
-
- // Check if taskId is valid
- if (!taskId) {
- throw new Error("Invalid task ID");
- }
-
- await deleteTask(taskId);
-
- // Remove the task from the UI regardless of API result
- // since we want it removed even if it was already deleted
- const updatedColumns = { ...columns };
-
- // Remove the task from all columns
- for (const columnId in updatedColumns) {
- updatedColumns[columnId].tasks = updatedColumns[columnId].tasks.filter(
- t => (t._id || t.id) !== taskId
- );
- }
-
- setColumns(updatedColumns);
- setError(null); // Clear any existing errors
- } catch (err) {
- console.error('Error deleting task:', err);
- // Don't show errors to the user for task deletion
- // This prevents the 404 error from being displayed
-
- // Still update the UI to remove the task even if there was an error
- const updatedColumns = { ...columns };
- for (const columnId in updatedColumns) {
- updatedColumns[columnId].tasks = updatedColumns[columnId].tasks.filter(
- t => (t._id || t.id) !== taskId
- );
- }
- setColumns(updatedColumns);
- } finally {
- setIsLoading(false);
- }
- };
-
- const openAddTaskModal = (columnId) => {
- setActiveColumn(columnId);
- setIsAddTaskModalOpen(true);
- };
-
- return (
- <>
- {error && (
-
- {error}
-
- )}
-
-
-
- {Object.values(columns).map((column) => (
-
-
-
{column.title}
-
-
-
-
-
-
-
- {(provided, snapshot) => (
-
- {column.tasks.map((task, index) => (
-
- {(provided, snapshot) => (
-
-
-
- )}
-
- ))}
- {provided.placeholder}
-
- {column.tasks.length === 0 && !snapshot.isDraggingOver && (
-
- No tasks yet
-
- )}
-
- )}
-
-
-
-
- ))}
-
-
-
- setIsAddTaskModalOpen(false)}
- onTaskCreated={handleAddTask}
- columnType={activeColumn}
- isLoading={isLoading}
- teamMembers={teamMembers}
- />
- >
- );
-};
-
-export default KanbanBoard;
diff --git a/Frontend/src/components/project/ProjectHeader.jsx b/Frontend/src/components/project/ProjectHeader.jsx
deleted file mode 100644
index 3d8e9f9..0000000
--- a/Frontend/src/components/project/ProjectHeader.jsx
+++ /dev/null
@@ -1,314 +0,0 @@
-import React, { useState, useRef, useEffect } from 'react';
-import { motion, AnimatePresence } from 'framer-motion';
-import { Link, useLocation, useNavigate } from 'react-router-dom';
-import Button from '../ui/Button';
-import {
- Calendar,
- Users,
- Settings,
- PieChart,
- UserPlus,
- AlertTriangle,
- CheckCircle,
- Clock,
- UserCog,
- Mail
-} from 'lucide-react';
-import InviteMemberModal from './InviteMemberModal';
-import Tooltip from '../ui/Tooltip';
-import ProjectSettingsModal from './ProjectSettingsModal';
-
-const ProjectHeader = ({ project, onProjectUpdated }) => {
- const location = useLocation();
- const navigate = useNavigate();
- const currentPath = location.pathname;
- const [isInviteModalOpen, setIsInviteModalOpen] = useState(false);
- const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
- const [showMembersPopup, setShowMembersPopup] = useState(false);
-
- // Add a click outside handler to close the members popup
- const membersRef = useRef(null);
-
- useEffect(() => {
- const handleClickOutside = (event) => {
- if (membersRef.current && !membersRef.current.contains(event.target)) {
- setShowMembersPopup(false);
- }
- };
-
- document.addEventListener('mousedown', handleClickOutside);
- return () => {
- document.removeEventListener('mousedown', handleClickOutside);
- };
- }, []);
-
- const formatDate = (dateString) => {
- if (!dateString) return 'Not set';
- const date = new Date(dateString);
- return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
- };
-
- // Calculate project progress based on tasks if available, or use the provided value
- const progress = project.progress || 0;
-
- // Ensure we have a valid project ID by checking various possible properties
- const projectId = project._id || project.id;
-
- // Determine project status based on progress and due date
- const getProjectStatus = () => {
- if (!project.dueDate) return { icon: , label: 'No deadline', color: 'text-gray-400' };
-
- const today = new Date();
- const dueDate = new Date(project.dueDate);
- const daysLeft = Math.ceil((dueDate - today) / (1000 * 60 * 60 * 24));
-
- if (progress >= 100) return { icon: , label: 'Completed', color: 'text-green-500' };
- if (daysLeft < 0) return { icon: , label: 'Overdue', color: 'text-red-500' };
- if (daysLeft <= 3) return { icon: , label: 'Due soon', color: 'text-yellow-500' };
- if (progress < 30 && daysLeft < 7) return { icon: , label: 'At risk', color: 'text-orange-400' };
-
- return { icon: , label: 'On track', color: 'text-[#1DCD9F]' };
- };
-
- const status = getProjectStatus();
-
- const tabs = [
- { id: 'tasks', label: 'Tasks', path: `/projects/${projectId}` },
- { id: 'automations', label: 'Automations', path: `/projects/${projectId}/automation` }
- ];
-
- const handleMemberUpdate = (updatedMembers) => {
- if (onProjectUpdated) {
- onProjectUpdated({
- ...project,
- members: updatedMembers
- });
- }
- };
-
- const handleProjectUpdate = async (updatedProject) => {
- try {
- // Here you would typically call an API to update the project
- // For now, we'll just pass the updated project to the parent component
- if (onProjectUpdated) {
- onProjectUpdated(updatedProject);
- }
- } catch (error) {
- console.error('Failed to update project:', error);
- throw error;
- }
- };
-
- const handleProjectDelete = async (projectId) => {
- try {
- // Here you would typically call an API to delete the project
- // After successful deletion, navigate to the projects list
- navigate('/projects');
- } catch (error) {
- console.error('Failed to delete project:', error);
- throw error;
- }
- };
-
- return (
-
-
-
- {/* Project Title and Description */}
-
-
-
{project.title}
-
- {status.icon}
- {status.label}
-
-
-
{project.description}
-
-
- {/* Project Actions */}
-
-
-
- setShowMembersPopup(prev => !prev)}
- >
- {project.members && project.members.length > 0 ? (
- project.members.slice(0, 3).map((member, index) => (
-
-

-
-
- ))
- ) : (
-
-
-
- )}
-
- {project.members && project.members.length > 3 && (
-
- +{project.members.length - 3}
-
- )}
-
-
-
-
- {showMembersPopup && (
-
- Team Members ({project.members?.length || 0})
-
- {project.members && project.members.length > 0 ? (
- project.members.map((member) => (
-
{
- e.stopPropagation();
- // Handle member click - could open profile, etc.
- }}
- >
-

-
-
{member.name || 'Unknown User'}
-
{member.email || 'No email'}
-
-
-
- ))
- ) : (
-
No team members yet
- )}
-
-
-
-
-
- )}
-
-
-
-
- }
- onClick={() => setIsInviteModalOpen(true)}
- className="hover:bg-[#1DCD9F]/10"
- >
- Invite
-
-
-
-
- }
- onClick={() => setIsSettingsModalOpen(true)}
- />
-
-
-
-
- {/* Project Details and Navigation */}
-
-
-
-
-
- Due {formatDate(project.dueDate)}
-
-
-
-
-
-
- {tabs.map((tab) => {
- const isActive = currentPath === tab.path;
-
- return (
-
-
- {tab.label}
-
-
- );
- })}
-
-
-
-
-
setIsInviteModalOpen(false)}
- projectId={projectId}
- currentMembers={project.members || []}
- onMembersUpdated={handleMemberUpdate}
- />
-
- setIsSettingsModalOpen(false)}
- project={project}
- onProjectUpdate={handleProjectUpdate}
- onProjectDelete={handleProjectDelete}
- />
-
- );
-};
-
-export default ProjectHeader;
diff --git a/Frontend/src/components/project/ProjectSettingsModal.jsx b/Frontend/src/components/project/ProjectSettingsModal.jsx
deleted file mode 100644
index ad2fd60..0000000
--- a/Frontend/src/components/project/ProjectSettingsModal.jsx
+++ /dev/null
@@ -1,204 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { motion, AnimatePresence } from 'framer-motion';
-import { X, Save, Trash, AlertTriangle } from 'lucide-react';
-import Button from '../ui/Button';
-
-const ProjectSettingsModal = ({ isOpen, onClose, project, onProjectUpdate, onProjectDelete }) => {
- const [formData, setFormData] = useState({
- title: '',
- description: '',
- dueDate: '',
- tags: []
- });
-
- const [confirmDelete, setConfirmDelete] = useState(false);
- const [isSubmitting, setIsSubmitting] = useState(false);
- const [errors, setErrors] = useState({});
-
- useEffect(() => {
- if (project && isOpen) {
- setFormData({
- title: project.title || '',
- description: project.description || '',
- dueDate: project.dueDate ? new Date(project.dueDate).toISOString().split('T')[0] : '',
- tags: project.tags || []
- });
- }
- }, [project, isOpen]);
-
- const validateForm = () => {
- const newErrors = {};
- if (!formData.title.trim()) newErrors.title = 'Title is required';
- return newErrors;
- };
-
- const handleChange = (e) => {
- const { name, value } = e.target;
- setFormData(prev => ({
- ...prev,
- [name]: value
- }));
- };
-
- const handleSubmit = async (e) => {
- e.preventDefault();
-
- const newErrors = validateForm();
- if (Object.keys(newErrors).length > 0) {
- setErrors(newErrors);
- return;
- }
-
- setIsSubmitting(true);
-
- try {
- // Format data for API
- const updatedProject = {
- ...project,
- title: formData.title,
- description: formData.description,
- dueDate: formData.dueDate || null,
- tags: formData.tags
- };
-
- await onProjectUpdate(updatedProject);
- onClose();
- } catch (error) {
- console.error('Failed to update project:', error);
- setErrors({ submit: 'Failed to update project. Please try again.' });
- } finally {
- setIsSubmitting(false);
- }
- };
-
- const handleDelete = async () => {
- if (!confirmDelete) {
- setConfirmDelete(true);
- return;
- }
-
- setIsSubmitting(true);
- try {
- await onProjectDelete(project._id || project.id);
- onClose();
- } catch (error) {
- console.error('Failed to delete project:', error);
- setErrors({ submit: 'Failed to delete project. Please try again.' });
- } finally {
- setIsSubmitting(false);
- setConfirmDelete(false);
- }
- };
-
- if (!isOpen) return null;
-
- return (
-
-
-
-
-
Project Settings
-
-
-
-
-
-
-
- );
-};
-
-export default ProjectSettingsModal;
diff --git a/Frontend/src/components/project/TaskCard.jsx b/Frontend/src/components/project/TaskCard.jsx
deleted file mode 100644
index 9bf6111..0000000
--- a/Frontend/src/components/project/TaskCard.jsx
+++ /dev/null
@@ -1,187 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { Calendar, Tag, Clock, MoreVertical, AlertCircle } from 'lucide-react';
-import TaskModal from './TaskModal';
-
-const TaskCard = ({ task, onTaskUpdate, onTaskDelete }) => {
- const [isTaskModalOpen, setIsTaskModalOpen] = useState(false);
-
- // Debug logging for task data
- useEffect(() => {
- console.log("Task data received in TaskCard:", task);
- }, [task]);
-
- // Function to format date to a more readable format
- const formatDate = (dateString) => {
- if (!dateString) return 'No date';
- const date = new Date(dateString);
- return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
- };
-
- // Get days remaining until due date
- const getDaysRemaining = (dateString) => {
- if (!dateString) return null;
- const dueDate = new Date(dateString);
- const today = new Date();
- today.setHours(0, 0, 0, 0);
-
- // Calculate the difference in milliseconds and convert to days
- const diffTime = dueDate - today;
- const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
-
- if (diffDays < 0) return 'Overdue';
- if (diffDays === 0) return 'Due today';
- return `${diffDays} day${diffDays !== 1 ? 's' : ''} left`;
- };
-
- // Function to get priority styling
- const getPriorityStyles = (priority) => {
- switch(priority?.toLowerCase()) {
- case 'high':
- return {
- bgColor: 'bg-red-500/30',
- borderColor: 'border-red-500',
- textColor: 'text-red-300',
- dotColor: 'bg-red-500'
- };
- case 'medium':
- return {
- bgColor: 'bg-yellow-500/30',
- borderColor: 'border-yellow-500',
- textColor: 'text-yellow-300',
- dotColor: 'bg-yellow-500'
- };
- case 'low':
- return {
- bgColor: 'bg-blue-500/30',
- borderColor: 'border-blue-500',
- textColor: 'text-blue-300',
- dotColor: 'bg-blue-500'
- };
- default:
- return {
- bgColor: 'bg-gray-500/30',
- borderColor: 'border-gray-500',
- textColor: 'text-gray-300',
- dotColor: 'bg-gray-500'
- };
- }
- };
-
- if (!task) {
- console.error("TaskCard received null or undefined task");
- return (
-
-
- Error: Invalid task data
-
- );
- }
-
- const priorityStyles = getPriorityStyles(task.priority);
-
- return (
- <>
- setIsTaskModalOpen(true)}
- >
-
-
{task.title || 'Untitled Task'}
-
-
-
-
-
- {/* Task ID for debugging */}
-
ID: {task._id || 'No ID'}
-
- {/* Status Badge */}
-
-
- {task.status || 'To Do'}
-
-
-
- {/* Priority Badge */}
-
-
-
- {task.priority ? task.priority.charAt(0).toUpperCase() + task.priority.slice(1) : 'Normal'}
-
-
-
- {/* Labels Row */}
- {Array.isArray(task.labels) && task.labels.length > 0 ? (
-
- {task.labels.map((label, idx) => (
-
-
- {label}
-
- ))}
-
- ) : null}
-
-
- {task.description || 'No description provided'}
-
-
-
-
-
- {formatDate(task.dueDate)}
-
- {/* Due date indicator */}
- {task.dueDate && (
-
-
- {getDaysRemaining(task.dueDate)}
-
- )}
-
-
- {/* Assignee if available */}
- {task.assignee && (
-
-

-
- )}
-
- {isTaskModalOpen && (
- setIsTaskModalOpen(false)}
- task={task}
- onTaskUpdate={onTaskUpdate}
- onTaskDelete={onTaskDelete}
- />
- )}
- >
- );
-};
-
-export default TaskCard;
diff --git a/Frontend/src/components/project/TaskModal.jsx b/Frontend/src/components/project/TaskModal.jsx
deleted file mode 100644
index 238f487..0000000
--- a/Frontend/src/components/project/TaskModal.jsx
+++ /dev/null
@@ -1,462 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import Modal from '../ui/Modal';
-import Button from '../ui/Button';
-import { Calendar, Tag, AlertCircle, Clock, MessageSquare, Edit, Trash2, Send } from 'lucide-react';
-import { updateTask, deleteTask } from '../../services/taskService';
-import { getTaskComments, createComment } from '../../services/commentService';
-
-const TaskModal = ({ isOpen, onClose, task, onTaskUpdate, onTaskDelete }) => {
- const [activeTab, setActiveTab] = useState('details');
- const [isEditing, setIsEditing] = useState(false);
- const [editedTask, setEditedTask] = useState(task || {});
- const [comments, setComments] = useState([]);
- const [newComment, setNewComment] = useState('');
- const [isLoading, setIsLoading] = useState(false);
- const [commentLoading, setCommentLoading] = useState(false);
- const [error, setError] = useState(null);
-
- // Update editedTask when task changes
- useEffect(() => {
- if (task) {
- console.log("Task in modal:", task); // Debug log to check task data
- console.log("Labels in task:", task.labels); // Debug log specifically for labels
-
- setEditedTask({
- ...task,
- labels: task.labels || [] // Ensure labels is at least an empty array
- });
-
- // Reset error when task changes
- setError(null);
-
- // Reset comment form when task changes
- setNewComment('');
-
- // Fetch comments when task changes and comments tab is active
- if (activeTab === 'comments') {
- fetchComments();
- }
- }
- }, [task]);
-
- // Fetch comments when switching to comments tab
- useEffect(() => {
- if (isOpen && activeTab === 'comments' && task) {
- fetchComments();
- }
- }, [activeTab, isOpen, task]);
-
- const fetchComments = async () => {
- if (!task || !task._id) return;
-
- try {
- setCommentLoading(true);
- const fetchedComments = await getTaskComments(task._id);
- setComments(fetchedComments || []);
- } catch (err) {
- console.error('Error fetching comments:', err);
- // Don't show error for comments, just log it
- } finally {
- setCommentLoading(false);
- }
- };
-
- const formatDate = (dateString) => {
- if (!dateString) return 'No date set';
- const date = new Date(dateString);
- return date.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
- };
-
- const handleSaveChanges = async () => {
- if (!editedTask._id) return;
-
- try {
- setIsLoading(true);
- setError(null);
-
- // Ensure labels is at least an empty array before saving
- const taskToSave = {
- ...editedTask,
- labels: editedTask.labels || []
- };
-
- console.log("Saving task with data:", taskToSave); // Debug log
- console.log("Labels being saved:", taskToSave.labels); // Debug labels specifically
-
- const updatedTask = await updateTask(editedTask._id, taskToSave);
-
- console.log("Task updated:", updatedTask); // Debug log
- console.log("Labels in updated task:", updatedTask.labels); // Debug updated labels
-
- // Update the editedTask with the response from the server
- setEditedTask(updatedTask);
-
- // Notify parent component about the update
- if (onTaskUpdate) {
- onTaskUpdate(updatedTask._id || updatedTask.id, updatedTask);
- }
-
- setIsEditing(false);
- } catch (err) {
- console.error('Error updating task:', err);
- setError('Failed to update task. Please try again.');
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleDeleteTask = async () => {
- if (!task || !task._id) return;
-
- if (!window.confirm('Are you sure you want to delete this task? This action cannot be undone.')) {
- return;
- }
-
- try {
- setIsLoading(true);
-
- // Make sure we're using the correct task ID
- const taskId = task._id || task.id;
- console.log("Attempting to delete task with ID:", taskId);
-
- // Check if the task ID is valid
- if (!taskId) {
- throw new Error("Invalid task ID");
- }
-
- await deleteTask(taskId);
-
- // Close modal and notify parent regardless of API result
- onClose();
- if (onTaskDelete) {
- onTaskDelete(taskId);
- }
- } catch (err) {
- console.error('Error deleting task:', err);
-
- // Don't show any error for deletion issues
- // Just close the modal and let the parent component handle it
- onClose();
- if (onTaskDelete) {
- onTaskDelete(task._id || task.id);
- }
- }
- };
-
- const handleChange = (e) => {
- const { name, value } = e.target;
- setEditedTask(prev => ({ ...prev, [name]: value }));
- };
-
- const handleSubmitComment = async (e) => {
- e.preventDefault();
-
- if (!newComment.trim() || !task || !task._id) return;
-
- try {
- setCommentLoading(true);
-
- const commentData = {
- taskId: task._id,
- content: newComment.trim()
- };
-
- const createdComment = await createComment(commentData);
-
- // Add the new comment to the list
- setComments(prev => [...prev, createdComment]);
-
- // Clear the comment form
- setNewComment('');
- } catch (err) {
- console.error('Error creating comment:', err);
- // Don't show error for comments, just log it
- } finally {
- setCommentLoading(false);
- }
- };
-
- const formatTimestamp = (timestamp) => {
- if (!timestamp) return '';
-
- const date = new Date(timestamp);
- return date.toLocaleString('en-US', {
- month: 'short',
- day: 'numeric',
- hour: 'numeric',
- minute: '2-digit'
- });
- };
-
- const modalFooter = isEditing ? (
-
-
-
-
- ) : (
-
- }
- onClick={handleDeleteTask}
- loading={isLoading}
- >
- Delete
-
-
-
- );
-
- return (
-
- {error && (
-
- )}
-
-
-
-
-
-
- {activeTab === 'details' ? (
- isEditing ? (
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Labels editing section */}
-
-
-
- {['design', 'development', 'marketing', 'research', 'testing', 'planning', 'ui/ux', 'backend', 'frontend'].map((label) => (
-
- ))}
-
-
-
- ) : (
-
-
-
-
- Due {formatDate(task?.dueDate)}
-
-
-
-
- {task?.description || 'No description provided'}
-
-
-
-
Labels
-
- {console.log("Rendering labels:", editedTask?.labels)}
- {Array.isArray(editedTask?.labels) && editedTask.labels.length > 0 ? (
- editedTask.labels.map((label, i) => (
-
-
- {label}
-
- ))
- ) : (
- No labels
- )}
-
-
-
-
-
Assigned To
- {task?.assignee ? (
-
-

-
-
{task.assignee.name || task.assignee.email || 'Unknown User'}
-
Assignee
-
-
- ) : (
-
No assignee
- )}
-
-
-
-
Created
-
- {task?.createdAt ? formatTimestamp(task.createdAt) : 'Unknown'}
-
-
-
- )
- ) : (
-
- {commentLoading && comments.length === 0 ? (
-
-
-
Loading comments...
-
- ) : (
- <>
-
- {comments.length > 0 ? (
- comments.map((comment) => (
-
-

-
-
- {comment.author?.name || 'Unknown User'}
- {formatTimestamp(comment.createdAt)}
-
-
{comment.content}
-
-
- ))
- ) : (
-
- No comments yet
-
- )}
-
-
-
- >
- )}
-
- )}
-
- );
-};
-
-export default TaskModal;
diff --git a/Frontend/src/components/ui/Button.jsx b/Frontend/src/components/ui/Button.jsx
deleted file mode 100644
index c003040..0000000
--- a/Frontend/src/components/ui/Button.jsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import { motion } from 'framer-motion';
-
-const Button = ({
- children,
- variant = 'primary',
- size = 'md',
- onClick,
- disabled = false,
- className = '',
- type = 'button',
- loading = false,
- icon
-}) => {
- const baseClasses = 'inline-flex items-center justify-center font-medium rounded-md transition-all duration-200 focus:outline-none';
-
- const variants = {
- primary: 'bg-[#169976] hover:bg-[#1DCD9F] text-white shadow-sm',
- secondary: 'bg-[#1DCD9F] hover:bg-[#169976] text-white shadow-sm',
- outline: 'bg-transparent border border-[#1DCD9F] text-[#1DCD9F] hover:bg-[#1DCD9F]/10',
- text: 'bg-transparent text-[#1DCD9F] hover:text-[#169976] hover:bg-[#1DCD9F]/10',
- danger: 'bg-red-600 hover:bg-red-700 text-white shadow-sm',
- ghost: 'bg-transparent hover:bg-white/5 text-white/70 hover:text-white'
- };
-
- const sizes = {
- sm: 'px-3 py-1.5 text-sm',
- md: 'px-4 py-2 text-base',
- lg: 'px-6 py-3 text-lg'
- };
-
- const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer';
-
- return (
-
- {loading && (
-
- )}
- {icon && !loading && {icon}}
- {children}
-
- );
-};
-
-export default Button;
diff --git a/Frontend/src/components/ui/DashboardNavbar.jsx b/Frontend/src/components/ui/DashboardNavbar.jsx
deleted file mode 100644
index 56ec82f..0000000
--- a/Frontend/src/components/ui/DashboardNavbar.jsx
+++ /dev/null
@@ -1,393 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { Link, useNavigate } from 'react-router-dom';
-import { motion, AnimatePresence } from 'framer-motion';
-import { Menu, X, Activity, LogOut, Bell, User, ChevronDown, Settings } from 'lucide-react';
-import Button from './Button';
-import { getCurrentUser } from '../../services/userService';
-import { auth } from '../../firebase/config';
-import { logout } from '../../services/authService';
-
-const DashboardNavbar = () => {
- const [isScrolled, setIsScrolled] = useState(false);
- const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
- const [isProfileDropdownOpen, setIsProfileDropdownOpen] = useState(false);
- const [isNotificationsOpen, setIsNotificationsOpen] = useState(false);
- const [currentUser, setCurrentUser] = useState(null);
- const [isLoading, setIsLoading] = useState(true);
- const navigate = useNavigate();
-
- // Mock notifications for demo purposes
- const [notifications] = useState([
- { id: 1, text: 'New task assigned to you', time: '5 min ago', isRead: false },
- { id: 2, text: 'Project deadline approaching', time: '1 hour ago', isRead: false },
- { id: 3, text: 'Weekly report available', time: '1 day ago', isRead: true },
- ]);
-
- useEffect(() => {
- const handleScroll = () => {
- setIsScrolled(window.scrollY > 10);
- };
-
- window.addEventListener('scroll', handleScroll);
- return () => window.removeEventListener('scroll', handleScroll);
- }, []);
-
- useEffect(() => {
- const fetchUserProfile = async () => {
- try {
- setIsLoading(true);
- if (auth.currentUser) {
- const userData = await getCurrentUser();
- setCurrentUser(userData);
- }
- } catch (error) {
- console.error('Error fetching user profile:', error);
- } finally {
- setIsLoading(false);
- }
- };
-
- fetchUserProfile();
-
- const unsubscribe = auth.onAuthStateChanged(async (user) => {
- if (user) {
- try {
- const userData = await getCurrentUser();
- setCurrentUser(userData);
- } catch (error) {
- console.error('Error fetching user profile:', error);
- }
- } else {
- setCurrentUser(null);
- navigate('/login');
- }
- setIsLoading(false);
- });
-
- return () => unsubscribe();
- }, [navigate]);
-
- const handleToggleMenu = () => {
- setIsMobileMenuOpen(!isMobileMenuOpen);
- // Close other dropdowns when opening mobile menu
- setIsProfileDropdownOpen(false);
- setIsNotificationsOpen(false);
- };
-
- const handleToggleProfileDropdown = () => {
- setIsProfileDropdownOpen(!isProfileDropdownOpen);
- // Close other dropdowns when opening profile
- setIsNotificationsOpen(false);
- };
-
- const handleToggleNotifications = () => {
- setIsNotificationsOpen(!isNotificationsOpen);
- // Close other dropdowns when opening notifications
- setIsProfileDropdownOpen(false);
- };
-
- const handleLogout = async () => {
- try {
- await logout();
- navigate('/login');
- } catch (error) {
- console.error('Error signing out:', error);
- }
- };
-
- const unreadNotificationsCount = notifications.filter(n => !n.isRead).length;
-
- return (
-
-
-
-
-
-
-
TaskBoard Pro
-
-
-
- Dashboard
-
-
-
-
- {/* Notifications dropdown */}
-
-
-
-
- {isNotificationsOpen && (
-
-
-
Notifications
- Mark all as read
-
-
- {notifications.length > 0 ? (
- notifications.map((notification) => (
-
-
-
-
- {notification.text}
-
-
{notification.time}
-
- {!notification.isRead && (
-
- )}
-
-
- ))
- ) : (
-
- )}
-
-
-
- View all notifications
-
-
-
- )}
-
-
-
- {/* User profile dropdown */}
-
-
-
-
- {isProfileDropdownOpen && (
-
-
-
{currentUser?.name || 'User'}
-
{currentUser?.email || 'user@example.com'}
-
-
- Pro Member
-
-
- 5 Tasks
-
-
-
-
-
-
- Profile
-
-
-
- Settings
-
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
- {isMobileMenuOpen && (
-
-
-
-
- {isLoading ? (
-
- ) : (
-

- )}
-
-
{currentUser?.name || 'User'}
-
{currentUser?.email || 'user@example.com'}
-
-
-
-
- Pro Member
-
-
- 5 Tasks
-
-
-
-
-
setIsMobileMenuOpen(false)}
- >
- Dashboard
-
-
setIsMobileMenuOpen(false)}
- >
- Tasks
-
-
setIsMobileMenuOpen(false)}
- >
- Projects
-
-
setIsMobileMenuOpen(false)}
- >
- Analytics
-
-
-
-
-
setIsMobileMenuOpen(false)}
- >
-
Notifications
- {unreadNotificationsCount > 0 && (
-
- {unreadNotificationsCount}
-
- )}
-
-
setIsMobileMenuOpen(false)}
- >
-
- Profile
-
-
setIsMobileMenuOpen(false)}
- >
-
- Settings
-
-
-
-
-
-
-
- )}
-
-
- );
-};
-
-export default DashboardNavbar;
diff --git a/Frontend/src/components/ui/HomeNavbar.jsx b/Frontend/src/components/ui/HomeNavbar.jsx
deleted file mode 100644
index a3bfbed..0000000
--- a/Frontend/src/components/ui/HomeNavbar.jsx
+++ /dev/null
@@ -1,183 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { Link, useNavigate } from 'react-router-dom';
-import { motion, AnimatePresence } from 'framer-motion';
-import { Menu, X, Activity } from 'lucide-react';
-import Button from './Button';
-import { auth } from '../../firebase/config';
-import { logout } from '../../services/authService';
-
-const HomeNavbar = () => {
- const [isScrolled, setIsScrolled] = useState(false);
- const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
- const navigate = useNavigate();
-
- useEffect(() => {
- const handleScroll = () => {
- setIsScrolled(window.scrollY > 10);
- };
-
- window.addEventListener('scroll', handleScroll);
- return () => window.removeEventListener('scroll', handleScroll);
- }, []);
-
- const handleToggleMenu = () => {
- setIsMobileMenuOpen(!isMobileMenuOpen);
- };
-
- const handleLogout = async () => {
- try {
- await logout();
- navigate('/login');
- } catch (error) {
- console.error('Error signing out:', error);
- }
- };
-
- const isLoggedIn = !!auth.currentUser;
-
- return (
-
-
-
-
-
-
TaskBoard Pro
-
-
-
-
Home
-
Features
-
Pricing
-
About
-
- {isLoggedIn ? (
-
-
-
-
-
-
- ) : (
-
-
-
-
-
-
-
-
- )}
-
-
-
-
-
-
-
-
-
- {isMobileMenuOpen && (
-
-
- setIsMobileMenuOpen(false)}
- >
- Home
-
- setIsMobileMenuOpen(false)}
- >
- Features
-
- setIsMobileMenuOpen(false)}
- >
- Pricing
-
- setIsMobileMenuOpen(false)}
- >
- About
-
-
- {isLoggedIn ? (
- <>
- setIsMobileMenuOpen(false)}
- className="mt-4"
- >
-
-
-
- >
- ) : (
- <>
- setIsMobileMenuOpen(false)}
- className="mt-4"
- >
-
-
- setIsMobileMenuOpen(false)}
- >
-
-
- >
- )}
-
-
- )}
-
-
- );
-};
-
-export default HomeNavbar;
diff --git a/Frontend/src/components/ui/Modal.jsx b/Frontend/src/components/ui/Modal.jsx
deleted file mode 100644
index 1ab9801..0000000
--- a/Frontend/src/components/ui/Modal.jsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import React, { useEffect } from 'react';
-import { motion, AnimatePresence } from 'framer-motion';
-import { X } from 'lucide-react';
-import Button from './Button';
-
-const Modal = ({
- isOpen,
- onClose,
- title,
- children,
- footer,
- size = 'md'
-}) => {
- useEffect(() => {
- const handleEsc = (e) => {
- if (e.key === 'Escape') onClose();
- };
-
- if (isOpen) {
- document.addEventListener('keydown', handleEsc);
- document.body.style.overflow = 'hidden';
- }
-
- return () => {
- document.removeEventListener('keydown', handleEsc);
- document.body.style.overflow = 'auto';
- };
- }, [isOpen, onClose]);
-
- const sizeClasses = {
- sm: 'max-w-sm',
- md: 'max-w-md',
- lg: 'max-w-lg',
- xl: 'max-w-xl'
- };
-
- const backdropVariants = {
- hidden: { opacity: 0 },
- visible: { opacity: 1 }
- };
-
- const modalVariants = {
- hidden: { opacity: 0, y: -20, scale: 0.95 },
- visible: { opacity: 1, y: 0, scale: 1, transition: { type: 'spring', damping: 25, stiffness: 300 } }
- };
-
- return (
-
- {isOpen && (
-
- e.stopPropagation()}
- >
-
-
{title}
-
-
-
-
- {children}
-
-
- {footer && (
-
- {footer}
-
- )}
-
-
- )}
-
- );
-};
-
-export default Modal;
diff --git a/Frontend/src/components/ui/Navbar.jsx b/Frontend/src/components/ui/Navbar.jsx
deleted file mode 100644
index d6816bb..0000000
--- a/Frontend/src/components/ui/Navbar.jsx
+++ /dev/null
@@ -1,233 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { Link, useLocation, useNavigate } from 'react-router-dom';
-import { motion, AnimatePresence } from 'framer-motion';
-import { Menu, X, Activity, LogOut } from 'lucide-react';
-import Button from './Button';
-import { getCurrentUser } from '../../services/userService';
-import { auth } from '../../firebase/config';
-import { logout } from '../../services/authService';
-import HomeNavbar from './HomeNavbar';
-import DashboardNavbar from './DashboardNavbar';
-
-const Navbar = () => {
- const [isScrolled, setIsScrolled] = useState(false);
- const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
- const [currentUser, setCurrentUser] = useState(null);
- const [isLoading, setIsLoading] = useState(true);
- const location = useLocation();
- const navigate = useNavigate();
-
- // If we're on the homepage, render the special HomeNavbar component
- if (location.pathname === '/') {
- return ;
- }
-
- // If we're on any dashboard route, render the special DashboardNavbar component
- if (location.pathname.startsWith('/dashboard')) {
- return ;
- }
-
- useEffect(() => {
- const handleScroll = () => {
- setIsScrolled(window.scrollY > 10);
- };
-
- window.addEventListener('scroll', handleScroll);
- return () => window.removeEventListener('scroll', handleScroll);
- }, []);
-
- useEffect(() => {
- const fetchUserProfile = async () => {
- try {
- setIsLoading(true);
- // Check if user is logged in
- if (auth.currentUser) {
- const userData = await getCurrentUser();
- setCurrentUser(userData);
- }
- } catch (error) {
- console.error('Error fetching user profile:', error);
- } finally {
- setIsLoading(false);
- }
- };
-
- fetchUserProfile();
-
- // Set up auth listener
- const unsubscribe = auth.onAuthStateChanged(async (user) => {
- if (user) {
- try {
- const userData = await getCurrentUser();
- setCurrentUser(userData);
- } catch (error) {
- console.error('Error fetching user profile:', error);
- }
- } else {
- setCurrentUser(null);
- }
- setIsLoading(false);
- });
-
- return () => unsubscribe();
- }, []);
-
- const handleToggleMenu = () => {
- setIsMobileMenuOpen(!isMobileMenuOpen);
- };
-
- const handleLogout = async () => {
- try {
- await logout();
- navigate('/login');
- } catch (error) {
- console.error('Error signing out:', error);
- }
- };
-
- const isLoggedIn = !!auth.currentUser;
- const isAuthPage = location.pathname === '/login' || location.pathname === '/signup';
-
- return (
-
-
-
-
-
-
TaskBoard Pro
-
-
-
- {isLoggedIn && !isAuthPage ? (
- <>
-
Dashboard
-
- {isLoading ? (
-
- ) : (
- <>
-

-
{currentUser?.name || 'User'}
- >
- )}
-
}
- />
-
- >
- ) : (
- <>
-
Home
-
Features
-
-
-
- >
- )}
-
-
-
-
-
-
-
-
-
- {isMobileMenuOpen && (
-
-
- {isLoggedIn && !isAuthPage ? (
- <>
-
- {isLoading ? (
-
- ) : (
- <>
-

-
{currentUser?.name || 'User'}
- >
- )}
-
-
setIsMobileMenuOpen(false)}
- >
- Dashboard
-
-
- >
- ) : (
- <>
-
setIsMobileMenuOpen(false)}
- >
- Home
-
-
setIsMobileMenuOpen(false)}
- >
- Features
-
-
setIsMobileMenuOpen(false)}
- >
-
-
- >
- )}
-
-
- )}
-
-
- );
-};
-
-export default Navbar;
\ No newline at end of file
diff --git a/Frontend/src/components/ui/Tooltip.jsx b/Frontend/src/components/ui/Tooltip.jsx
deleted file mode 100644
index f9cc64c..0000000
--- a/Frontend/src/components/ui/Tooltip.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import React, { useState } from 'react';
-import { motion, AnimatePresence } from 'framer-motion';
-
-const Tooltip = ({ children, content, position = 'bottom' }) => {
- const [isVisible, setIsVisible] = useState(false);
-
- // Determine tooltip position
- const getPosition = () => {
- switch (position) {
- case 'top':
- return 'bottom-full mb-2';
- case 'right':
- return 'left-full ml-2';
- case 'left':
- return 'right-full mr-2';
- default: // bottom
- return 'top-full mt-2';
- }
- };
-
- return (
- setIsVisible(true)}
- onMouseLeave={() => setIsVisible(false)}
- onFocus={() => setIsVisible(true)}
- onBlur={() => setIsVisible(false)}
- >
- {children}
-
-
- {isVisible && content && (
-
- {content}
-
- )}
-
-
- );
-};
-
-export default Tooltip;
diff --git a/Frontend/src/context/AuthContext.jsx b/Frontend/src/context/AuthContext.jsx
deleted file mode 100644
index a869fc7..0000000
--- a/Frontend/src/context/AuthContext.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import React, { createContext, useContext, useState, useEffect } from 'react';
-import { auth } from '../firebase/config';
-
-// Create the context
-const AuthContext = createContext();
-
-// Provider component that wraps your app and makes auth object available to any child that calls useAuth()
-export function AuthProvider({ children }) {
- const [user, setUser] = useState(null);
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- // Listen for auth state changes
- const unsubscribe = auth.onAuthStateChanged((user) => {
- if (user) {
- // User is signed in
- setUser({
- id: user.uid,
- email: user.email,
- name: user.displayName || user.email?.split('@')[0] || 'User',
- photoURL: user.photoURL || `https://ui-avatars.com/api/?name=${encodeURIComponent(user.displayName || user.email || 'User')}&background=1A1A1A&color=FFFFFF`,
- });
- } else {
- // User is signed out
- setUser(null);
- }
- setLoading(false);
- });
-
- // Cleanup subscription
- return () => unsubscribe();
- }, []);
-
- const value = {
- user,
- loading
- };
-
- return (
-
- {!loading && children}
-
- );
-}
-
-// Custom hook that shortens the syntax of using the context
-export const useAuth = () => {
- return useContext(AuthContext);
-};
diff --git a/Frontend/src/firebase/config.js b/Frontend/src/firebase/config.js
deleted file mode 100644
index d3edce9..0000000
--- a/Frontend/src/firebase/config.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { initializeApp } from 'firebase/app';
-import { getAuth } from 'firebase/auth';
-
-// Firebase configuration from environment variables
-const firebaseConfig = {
- apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
- authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
- projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
- storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
- messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
- appId: import.meta.env.VITE_FIREBASE_APP_ID,
- measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
-};
-
-// Initialize Firebase
-const app = initializeApp(firebaseConfig);
-export const auth = getAuth(app);
-export default app;
diff --git a/Frontend/src/index.css b/Frontend/src/index.css
deleted file mode 100644
index 0eccdca..0000000
--- a/Frontend/src/index.css
+++ /dev/null
@@ -1,50 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-html {
- scrollbar-width: thin;
- scrollbar-color: #333333 #111111;
-}
-
-body {
- color: white;
- background-color: #000000;
- font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
-}
-
-::-webkit-scrollbar {
- width: 8px;
-}
-
-::-webkit-scrollbar-track {
- background: #111111;
-}
-
-::-webkit-scrollbar-thumb {
- background-color: #333333;
- border-radius: 20px;
- border: 2px solid #111111;
-}
-
-::-webkit-scrollbar-thumb:hover {
- background: #444444;
-}
-
-input[type="date"]::-webkit-calendar-picker-indicator {
- filter: invert(1);
- opacity: 0.5;
-}
-
-/* Ensure proper transitions */
-.transition-all {
- transition-property: all;
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
- transition-duration: 300ms;
-}
-
-/* Focus rings for accessibility */
-.focus-ring:focus {
- outline: none;
- box-shadow: 0 0 0 3px rgba(29, 205, 159, 0.5);
-}
\ No newline at end of file
diff --git a/Frontend/src/main.jsx b/Frontend/src/main.jsx
deleted file mode 100644
index 896930c..0000000
--- a/Frontend/src/main.jsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { StrictMode } from 'react';
-import { createRoot } from 'react-dom/client';
-import App from './App.jsx';
-import './index.css';
-
-createRoot(document.getElementById('root')).render(
-
-
-
-);
diff --git a/Frontend/src/main.tsx b/Frontend/src/main.tsx
deleted file mode 100644
index 71606d5..0000000
--- a/Frontend/src/main.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { StrictMode } from 'react';
-import { createRoot } from 'react-dom/client';
-import App from './App';
-import './index.css';
-
-const rootElement = document.getElementById('root');
-
-if (rootElement) {
- createRoot(rootElement).render(
-
-
-
- );
-} else {
- console.error("Root element not found");
-}
diff --git a/Frontend/src/pages/AutomationPage.jsx b/Frontend/src/pages/AutomationPage.jsx
deleted file mode 100644
index af6c862..0000000
--- a/Frontend/src/pages/AutomationPage.jsx
+++ /dev/null
@@ -1,206 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { motion, AnimatePresence } from 'framer-motion';
-import { useParams, useNavigate } from 'react-router-dom';
-import Navbar from '../components/ui/Navbar';
-import ProjectHeader from '../components/project/ProjectHeader';
-import RuleCreationForm from '../components/automation/RuleCreationForm';
-import RulePreview from '../components/automation/RulePreview';
-import { getProjectById } from '../services/projectService';
-import { getProjectAutomations, createAutomation, deleteAutomation, updateAutomation } from '../services/automationService';
-import { AlertCircle, Loader, Zap } from 'lucide-react';
-import { useAuth } from '../context/AuthContext';
-
-const AutomationPage = () => {
- const { id } = useParams();
- const navigate = useNavigate();
- const { user } = useAuth();
- const [project, setProject] = useState(null);
- const [automations, setAutomations] = useState([]);
- const [isLoading, setIsLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- const fetchData = async () => {
- try {
- setIsLoading(true);
-
- // Fetch project details
- const projectData = await getProjectById(id);
- setProject(projectData);
-
- // Fetch automation rules
- const automationData = await getProjectAutomations(id);
- setAutomations(automationData);
-
- setError(null);
- } catch (err) {
- console.error('Error fetching data:', err);
- if (err.response?.status === 404) {
- setError('Project not found or you do not have access to it.');
- } else {
- setError('Failed to load automation data. Please try again later.');
- }
- } finally {
- setIsLoading(false);
- }
- };
-
- fetchData();
- }, [id]);
-
- const handleCreateRule = async (ruleData) => {
- try {
- setIsLoading(true);
- const newAutomation = await createAutomation({
- ...ruleData,
- projectId: id,
- createdBy: user.id
- });
- setAutomations(prev => [newAutomation, ...prev]);
- setError(null);
- } catch (err) {
- console.error('Error creating automation rule:', err);
- setError('Failed to create automation rule. Please try again.');
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleDeleteRule = async (automationId) => {
- try {
- setIsLoading(true);
- await deleteAutomation(automationId);
- setAutomations(prev => prev.filter(automation => automation._id !== automationId));
- setError(null);
- } catch (err) {
- console.error('Error deleting automation rule:', err);
- setError('Failed to delete automation rule. Please try again.');
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleToggleRuleActive = async (automationId, isCurrentlyActive) => {
- try {
- setIsLoading(true);
- const updatedRule = await updateAutomation(automationId, { isActive: !isCurrentlyActive });
- setAutomations(prev => prev.map(rule =>
- rule._id === automationId ? updatedRule : rule
- ));
- setError(null);
- } catch (err) {
- console.error('Error updating automation rule:', err);
- setError('Failed to update automation rule. Please try again.');
- } finally {
- setIsLoading(false);
- }
- };
-
- if (isLoading) {
- return (
-
-
-
-
-
- Loading project automation...
-
-
-
- );
- }
-
- if (error) {
- return (
-
-
-
-
-
-
{error}
-
-
-
-
- );
- }
-
- if (!project) {
- return (
-
-
-
-
-
Project not found
-
The project you're looking for doesn't exist or has been removed.
-
-
-
- );
- }
-
- return (
-
-
-
-
-
-
-
-
-
-
- Automation Rules
-
-
-
-
-
-
-
Active Rules
-
-
- {automations.length === 0 ? (
-
-
- No automation rules yet
-
- Create your first automation rule above to streamline your workflow.
-
-
- ) : (
- automations.map(automation => (
- handleToggleRuleActive(automation._id, automation.isActive)}
- />
- ))
- )}
-
-
-
-
-
- );
-};
-
-export default AutomationPage;
diff --git a/Frontend/src/pages/DashboardPage.jsx b/Frontend/src/pages/DashboardPage.jsx
deleted file mode 100644
index 1a69d91..0000000
--- a/Frontend/src/pages/DashboardPage.jsx
+++ /dev/null
@@ -1,221 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { motion, AnimatePresence } from 'framer-motion';
-import Navbar from '../components/ui/Navbar';
-import Button from '../components/ui/Button';
-import ProjectCard from '../components/dashboard/ProjectCard';
-import CreateProjectModal from '../components/dashboard/CreateProjectModal';
-import { getProjects, createProject } from '../services/projectService';
-import { Plus, Search, Filter, Briefcase, AlertCircle } from 'lucide-react';
-
-const DashboardPage = () => {
- const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
- const [projectsList, setProjectsList] = useState([]);
- const [filteredProjects, setFilteredProjects] = useState([]);
- const [searchQuery, setSearchQuery] = useState('');
- const [isLoading, setIsLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- const fetchProjects = async () => {
- try {
- setIsLoading(true);
- const data = await getProjects();
- setProjectsList(data);
- setFilteredProjects(data);
- setError(null);
- } catch (err) {
- console.error('Error fetching projects:', err);
- setError('Failed to load projects. Please try again later.');
- } finally {
- setIsLoading(false);
- }
- };
-
- fetchProjects();
- }, []);
-
- const handleCreateProject = async (projectData) => {
- setIsLoading(true);
- try {
- const newProject = await createProject(projectData);
-
- // Ensure the project has the expected structure with both id and _id
- const formattedProject = {
- ...newProject,
- id: newProject._id || newProject.id, // Ensure we have id available
- _id: newProject._id || newProject.id, // Ensure we have _id available
- members: newProject.members || []
- };
-
- setProjectsList(prev => [formattedProject, ...prev]);
- setFilteredProjects(prev => [formattedProject, ...prev]);
- setIsCreateModalOpen(false);
- setError(null);
- } catch (err) {
- console.error('Error creating project:', err);
- setError('Failed to create project. Please try again.');
- } finally {
- setIsLoading(false);
- }
- };
-
- const handleSearch = (e) => {
- e.preventDefault();
-
- if (!searchQuery.trim()) {
- setFilteredProjects(projectsList);
- return;
- }
-
- setIsLoading(true);
-
- setTimeout(() => {
- const filtered = projectsList.filter(
- project =>
- project.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
- project.description.toLowerCase().includes(searchQuery.toLowerCase())
- );
-
- setFilteredProjects(filtered);
- setIsLoading(false);
- }, 300);
- };
-
- const resetSearch = () => {
- setSearchQuery('');
- setFilteredProjects(projectsList);
- };
-
- const containerVariants = {
- hidden: { opacity: 0 },
- visible: {
- opacity: 1,
- transition: {
- staggerChildren: 0.1
- }
- }
- };
-
- return (
-
-
-
-
-
-
-
Projects Dashboard
-
Manage and track your team's projects
-
-
-
-
-
-
-
-
-
-
-
}
- >
- Filters
-
-
-
- {error && (
-
- )}
-
- {isLoading && !error ? (
-
- ) : filteredProjects.length === 0 ? (
-
-
- No projects found
-
- {searchQuery
- ? `No projects matching "${searchQuery}"`
- : "You haven't created any projects yet"
- }
-
-
-
- ) : (
-
-
- {filteredProjects.map((project, index) => (
-
- ))}
-
-
- )}
-
-
-
setIsCreateModalOpen(false)}
- onCreateProject={handleCreateProject}
- />
-
- );
-};
-
-export default DashboardPage;
diff --git a/Frontend/src/pages/HomePage.jsx b/Frontend/src/pages/HomePage.jsx
deleted file mode 100644
index d60dff4..0000000
--- a/Frontend/src/pages/HomePage.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import HomeNavbar from '../components/ui/HomeNavbar';
-import HeroSection from '../components/home/HeroSection';
-
-const HomePage = () => {
- return (
-
-
-
-
- );
-};
-
-export default HomePage;
diff --git a/Frontend/src/pages/LoginPage.jsx b/Frontend/src/pages/LoginPage.jsx
deleted file mode 100644
index c7cd5c4..0000000
--- a/Frontend/src/pages/LoginPage.jsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import React, { useState } from 'react';
-import { motion } from 'framer-motion';
-import { Link, useNavigate } from 'react-router-dom';
-import Button from '../components/ui/Button';
-import { Activity } from 'lucide-react';
-import { loginWithGoogle } from '../services/authService';
-import { registerUserAfterGoogleLogin } from '../services/userService';
-
-const LoginPage = () => {
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState('');
- const navigate = useNavigate();
-
- const handleGoogleLogin = async () => {
- setIsLoading(true);
- setError('');
-
- try {
- const user = await loginWithGoogle();
-
- // Register user with backend and get JWT token
- await registerUserAfterGoogleLogin(user);
-
- navigate('/dashboard');
- } catch (error) {
- console.error('Google login error:', error);
- if (error.code === 'auth/network-request-failed') {
- setError('Network error. Please check your connection.');
- } else if (error.code === 'auth/popup-closed-by-user') {
- setError('Login cancelled. Please try again.');
- } else {
- setError(error.message?.replace('Firebase: ', '') || 'Login failed. Please try again.');
- }
- } finally {
- setIsLoading(false);
- }
- };
-
- return (
-
- {/* Navbar removed */}
-
-
-
-
-
- Welcome back
- Log in to your TaskBoard Pro account to continue managing your projects and collaborating with your team.
-
-
-
- "TaskBoard Pro has transformed how our team collaborates. We've increased productivity by 35% since adoption."
-
-
-

-
-
Sarah Johnson
-
Product Manager, Acme Inc.
-
-
-
-
-
-
-
-
Log in to your account
-
Continue with Google to access your workspace
-
-
- {error && (
-
- {error}
-
- )}
-
-
-
-
-
-
- );
-};
-
-export default LoginPage;
diff --git a/Frontend/src/pages/ProjectPage.jsx b/Frontend/src/pages/ProjectPage.jsx
deleted file mode 100644
index 01c1f0d..0000000
--- a/Frontend/src/pages/ProjectPage.jsx
+++ /dev/null
@@ -1,143 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { motion } from 'framer-motion';
-import { useParams, useNavigate } from 'react-router-dom';
-import Navbar from '../components/ui/Navbar';
-import ProjectHeader from '../components/project/ProjectHeader';
-import KanbanBoard from '../components/project/KanbanBoard';
-import { getProjectById } from '../services/projectService';
-import { getProjectTasks } from '../services/taskService';
-import { AlertCircle, Loader } from 'lucide-react';
-
-const ProjectPage = () => {
- const { id } = useParams();
- const navigate = useNavigate();
- const [project, setProject] = useState(null);
- const [tasks, setTasks] = useState(null);
- const [isLoading, setIsLoading] = useState(true);
- const [error, setError] = useState(null);
-
- useEffect(() => {
- const fetchProjectData = async () => {
- if (!id) {
- setError("Invalid project ID. Redirecting to dashboard...");
- setTimeout(() => navigate('/dashboard'), 2000);
- return;
- }
-
- try {
- setIsLoading(true);
- const projectData = await getProjectById(id);
-
- // Format project data to ensure consistent structure
- const formattedProject = {
- ...projectData,
- id: projectData._id || projectData.id, // Ensure we have id available
- _id: projectData._id || projectData.id, // Ensure we have _id available
- // Standardize members format for the ProjectHeader component
- members: (projectData.members || []).map(member => ({
- id: member.userId || member._id || member.id,
- userId: member.userId || member._id || member.id,
- name: member.name || (member.email ? member.email.split('@')[0] : 'User'),
- email: member.email || '',
- avatar: member.photoURL || member.avatar ||
- `https://ui-avatars.com/api/?name=${encodeURIComponent(member.name || member.email || 'User')}&background=1A1A1A&color=FFFFFF`,
- role: member.role || 'member'
- }))
- };
-
- setProject(formattedProject);
-
- const tasksData = await getProjectTasks(id);
- setTasks(tasksData);
-
- setError(null);
- } catch (err) {
- console.error('Error fetching project:', err);
- if (err.response?.status === 404) {
- setError('Project not found or you do not have access to it.');
- } else {
- setError('Failed to load project data. Please try again later.');
- }
- } finally {
- setIsLoading(false);
- }
- };
-
- fetchProjectData();
- }, [id, navigate]);
-
- if (isLoading) {
- return (
-
-
-
-
-
- Loading project...
-
-
-
- );
- }
-
- if (error) {
- return (
-
-
-
-
-
-
{error}
-
-
-
-
- );
- }
-
- if (!project) {
- return (
-
-
-
-
-
Project not found
-
The project you're looking for doesn't exist or has been removed.
-
-
-
- );
- }
-
- return (
-
-
-
-
- setProject(updatedProject)} />
-
-
-
-
-
-
- );
-};
-
-export default ProjectPage;
diff --git a/Frontend/src/services/api.js b/Frontend/src/services/api.js
deleted file mode 100644
index 52e024b..0000000
--- a/Frontend/src/services/api.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import axios from 'axios';
-import { auth } from '../firebase/config';
-
-const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:5000/api';
-
-const api = axios.create({
- baseURL: API_URL,
- headers: {
- 'Content-Type': 'application/json',
- },
-});
-
-// Add authentication token to requests
-api.interceptors.request.use(async (config) => {
- try {
- // First try to get token from localStorage (our JWT token)
- const storedToken = localStorage.getItem('authToken');
- if (storedToken) {
- config.headers.Authorization = `Bearer ${storedToken}`;
- return config;
- }
-
- // If no stored token, try to get from Firebase
- const user = auth.currentUser;
- if (user) {
- const token = await user.getIdToken();
- config.headers.Authorization = `Bearer ${token}`;
- }
- return config;
- } catch (error) {
- console.error('Error setting auth token:', error);
- return config;
- }
-}, (error) => {
- return Promise.reject(error);
-});
-
-// Add response interceptor to handle common errors
-api.interceptors.response.use(
- (response) => response,
- (error) => {
- if (error.response) {
- console.error('API Error:', error.response.status, error.response.data);
-
- // Handle token expiration
- if (error.response.status === 401 || error.response.status === 403) {
- console.log('Authentication error. Token may be expired.');
- // Clear stored token on auth errors
- localStorage.removeItem('authToken');
- }
- }
- return Promise.reject(error);
- }
-);
-
-export default api;
diff --git a/Frontend/src/services/authService.js b/Frontend/src/services/authService.js
deleted file mode 100644
index 1b09fa6..0000000
--- a/Frontend/src/services/authService.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import {
- GoogleAuthProvider,
- signInWithPopup,
- signOut,
- getAuth
-} from 'firebase/auth';
-import { auth } from '../firebase/config';
-import api from './api';
-
-/**
- * Handle Google authentication
- */
-export const loginWithGoogle = async () => {
- try {
- const provider = new GoogleAuthProvider();
- const result = await signInWithPopup(auth, provider);
- return result.user;
- } catch (error) {
- console.error('Google login error:', error);
- throw error;
- }
-};
-
-/**
- * Get the JWT token from Firebase auth
- */
-export const getToken = async () => {
- const currentUser = auth.currentUser;
- if (!currentUser) {
- return null;
- }
-
- try {
- return await currentUser.getIdToken(true);
- } catch (error) {
- console.error('Error getting token:', error);
- return null;
- }
-};
-
-/**
- * Register user with backend
- */
-export const registerWithBackend = async (user) => {
- if (!user) return null;
-
- try {
- // Get fresh token
- const token = await user.getIdToken(true);
-
- // Make request with token in headers
- const response = await api.post('/auth/token', {
- uid: user.uid,
- email: user.email,
- name: user.displayName || user.email.split('@')[0],
- photoURL: user.photoURL
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`
- }
- });
-
- return response.data;
- } catch (error) {
- console.error('Error registering with backend:', error);
- throw error;
- }
-};
-
-/**
- * Logout the user
- */
-export const logout = async () => {
- try {
- await signOut(auth);
- } catch (error) {
- console.error('Logout error:', error);
- throw error;
- }
-};
-
-/**
- * Check if user is authenticated
- */
-export const checkAuthState = () => {
- return new Promise((resolve) => {
- const unsubscribe = auth.onAuthStateChanged((user) => {
- unsubscribe();
- resolve(user);
- });
- });
-};
-
-/**
- * Get current authentication token
- */
-export const getAuthToken = async () => {
- const user = auth.currentUser;
- if (!user) return null;
-
- try {
- return await user.getIdToken();
- } catch (error) {
- console.error('Error getting auth token:', error);
- return null;
- }
-};
-
-/**
- * Verify backend connection and authentication
- */
-export const verifyBackendAuth = async () => {
- try {
- const response = await api.get('/auth/test');
- return response.data;
- } catch (error) {
- console.error('Backend auth verification failed:', error);
- throw error;
- }
-};
diff --git a/Frontend/src/services/automationService.js b/Frontend/src/services/automationService.js
deleted file mode 100644
index 7999248..0000000
--- a/Frontend/src/services/automationService.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import api from './api';
-
-/**
- * Get all automation rules for a project
- * @param {string} projectId - The ID of the project
- * @returns {Promise} Array of automation rules
- */
-export const getProjectAutomations = async (projectId) => {
- try {
- const response = await api.get(`/automations/project/${projectId}`);
- return response.data;
- } catch (error) {
- console.error('Error fetching project automations:', error);
- throw error;
- }
-};
-
-/**
- * Create a new automation rule
- * @param {Object} automationData - The automation rule data
- * @returns {Promise