+
+
+
+
);
};
diff --git a/client/src/components/manageProjects/editProject.jsx b/client/src/components/manageProjects/editProject.jsx
index d859c80fa..863eed85d 100644
--- a/client/src/components/manageProjects/editProject.jsx
+++ b/client/src/components/manageProjects/editProject.jsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useCallback } from 'react';
import EditMeetingTimes from './editMeetingTimes';
import CreateNewEvent from './createNewEvent';
import readableEvent from './utilities/readableEvent';
@@ -6,15 +6,92 @@ import ProjectForm from '../ProjectForm';
import { simpleInputs, additionalInputsForEdit } from '../data';
import TitledBox from '../parts/boxes/TitledBox';
import TitledBoxIFrame from '../parts/boxes/TitledBoxIFrame';
-
+import { styled } from '@mui/material/styles';
import EditIcon from '../../svg/Icon_Edit.svg?react';
import PlusIcon from '../../svg/PlusIcon.svg?react';
-import { Typography, Box } from '@mui/material';
+import {
+ Typography,
+ Box,
+ Button,
+ List,
+ ListItem,
+ ListItemButton,
+ ListItemText,
+} from '@mui/material';
import EditProjectMembers from './editPMs/editProjectMembers';
-// Need to hold user state to check which type of user they are and conditionally render editing fields in this component
-// for user level block access to all except for the ones checked
+// --- Styled Components: Centralized & Reusable UI Elements ---
+// Leverages MUI's `styled` utility for cleaner, component-specific styles
+// enhancing maintainability and adherence to design principles
+
+// StyledListItem: Base style for each event row
+// Padding is applied to the clickable `ListItemButton` for full-width hover effect
+const StyledListItem = styled(ListItem)(({ theme }) => ({
+ display: 'flex',
+ flexDirection: 'column',
+ borderBottom: `1px solid ${theme.palette.grey[200] || '#ecebed'}`,
+ padding: 0,
+}));
+
+// StyledListItemButton: The clickable area for each event row
+// Contains core text and hover styling for consistent UX
+const StyledListItemButton = styled(ListItemButton)(({ theme }) => ({
+ padding: '8px 0',
+ fontFamily:
+ "'aliseoregular', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
+ WebkitFontSmoothing: 'antialiased',
+ MozOsxFontSmoothing: 'grayscale',
+ textAlign: 'left',
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ '&:hover': {
+ backgroundColor: '#f2f2f2',
+ },
+}));
+
+// DetailsText: Consistent typography for secondary event details
+const DetailsText = styled(Typography)(({ theme }) => ({
+ fontFamily: 'Arial, Helvetica, sans-serif',
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontSize: '14px',
+ lineHeight: '24px',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ display: 'block',
+}));
+
+// DescriptionText: Specific typography for the event description line
+const DescriptionText = styled(Typography)(({ theme }) => ({
+ fontFamily: 'Arial, Helvetica, sans-serif',
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontSize: '14px',
+ lineHeight: '24px',
+ color: '#5c5c5c',
+ height: '24px',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ display: 'block',
+}));
+
+/**
+ * EditProject: A component for managing and editing project details
+ * @param {Object} projectToEdit - The project to be edited
+ * @param {Array} recurringEvents - All recurring events associated with the current project
+ * @param {Function} createNewRecurringEvent - Function to create a new recurring event
+ * @param {Function} deleteRecurringEvent - Function to delete a recurring event
+ * @param {Function} updateRecurringEvent - Function to update a recurring event
+ * @param {Array} regularEvents - All regular events associated with the current project
+ * @param {Function} updateRegularEvent - Function to update a regular event
+ * @returns {ReactElement} - A component with the project form, recurring events, and regular
+ * events sections
+ */
const EditProject = ({
projectToEdit,
recurringEvents,
@@ -33,26 +110,66 @@ const EditProject = ({
slackUrl: projectToEdit.slackUrl,
googleDriveUrl: projectToEdit.googleDriveUrl,
hflaWebsiteUrl: projectToEdit.hflaWebsiteUrl,
- // this feature is commented out as per the PR #1577
- // partners: projectToEdit.partners,
- // managedByUsers: projectToEdit.managedByUsers,
- // projectStatus: projectToEdit.projectStatus,
- // comment out as per PR #1584
- // googleDriveId: projectToEdit.googleDriveId,
- // createdDate: new Date(projectToEdit.createdDate)
+ // Note: 'partners', 'managedByUsers', 'projectStatus', and 'googleDriveId' fields
+ // are commented out as per recent PRs (#1577, #1584) to streamline project data
});
// eslint-disable-next-line no-unused-vars
const [rEvents, setREvents] = useState([]);
const [regularEventsState, setRegularEventsState] = useState([]);
- const [selectedEvent, setSelectedEvent] = useState();
- const [isCreateNew, setIsCreateNew] = useState();
+ const [selectedEvent, setSelectedEvent] = useState(null);
+ const [isCreateNew, setIsCreateNew] = useState(false);
- // States for alerts
+ // State for displaying event-related alerts (e.g., success messages)
const [eventAlert, setEventAlert] = useState(null);
- // test
+ // `buttonKey`: Manages the key for the "Add New Event" button
+ // Incrementing this key forces the button to re-mount, fixing a stuck ripple
+ // effect when the CreateNewEvent modal is closed via the Escape key
+ const [buttonKey, setButtonKey] = useState(0);
+
+ // --- Ripple Effect Fix for List Items (Scalable Solution) ---
+ // These states prevent stuck ripple/hover effects on ListItemButtons
+ // when associated modals close via the Escape key, leveraging React's `key` prop
+ // for targeted component re-mounting.
+
+ // `lastOpenedEventId`: Tracks the ID of the specific event whose modal was last opened
+ const [lastOpenedEventId, setLastOpenedEventId] = useState(null);
+
+ // `forceRemountEventId`: Signals which specific ListItemButton needs to be re-mounted
+ // Changing its key value forces a full component reset for that item only
+ const [forceRemountEventId, setForceRemountEventId] = useState(null);
+ // --- End Ripple Effect Fix States ---
+
+ // `handleSelectEvent`: Opens the Edit Meeting Times modal.
+ // It captures the clicked event's ID to track which list item should be reset
+ // if the modal closes via the Escape key.
+ const handleSelectEvent = useCallback((event) => {
+ setSelectedEvent(event);
+ // Determine the correct unique ID for the selected event
+ const idToTrack = event._id || event.event_id;
+ setLastOpenedEventId(idToTrack);
+ setForceRemountEventId(null); // Clear any pending re-mounts for other items
+ }, []);
+
+ // `handleOpenCreateNewModal`: Sets the state to open the Create New Event modal
+ const handleOpenCreateNewModal = useCallback(() => {
+ setIsCreateNew(true);
+ }, []);
+
+ // `handleCloseCreateNewModal`: Closes the Create New Event modal.
+ // If closed by Escape key, it triggers a `buttonKey` change for the "Add New Event"
+ // button, forcing its re-mount to clear any stuck ripple effect.
+ const handleCloseCreateNewModal = useCallback((event, reason) => {
+ setIsCreateNew(false);
+ if (reason === 'escapeKeyDown') {
+ setButtonKey((prevKey) => prevKey + 1);
+ }
+ }, []);
+
+ // Populates `regularEventsState` by filtering and mapping regular events
+ // associated with the current project, sorting them by most recent first.
useEffect(() => {
if (regularEvents) {
setRegularEventsState(
@@ -65,7 +182,8 @@ const EditProject = ({
}
}, [projectToEdit, regularEvents, setRegularEventsState]);
- // Get project recurring events when component loads
+ // Populates `rEvents` (recurring events) by filtering and mapping them
+ // for the current project, sorting by day of the week.
useEffect(() => {
if (recurringEvents) {
setREvents(
@@ -80,26 +198,26 @@ const EditProject = ({
return (
-
-
-
-
-
-
+ {/* Edit Meeting Times component handles its own Modal */}
+
+
+ {/* Create New Event component handles its own Modal */}
+
+
+ {/* Main project form for editing project details */}
+ {/* Section for displaying and managing recurring events */}
}
sx={{
- display: 'flex',
- '&:hover': { color: 'red', cursor: 'pointer' },
- }}
- onClick={(e) => {
- e.stopPropagation();
- setIsCreateNew(true);
+ fontSize: '14px',
+ fontWeight: '600',
+ color: 'black',
+ textTransform: 'none',
+ '&:hover': {
+ color: 'error.main',
+ },
+ maxWidth: '138px',
+ width: '138px',
+ justifyContent: 'center',
}}
>
-
-
- Add New Event
-
-
+ Add New Event
+
}
expandable={true}
>
-