From 6b8818894aaf3f830951ff89793770374b9ad5eb Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Thu, 14 May 2026 12:55:23 -0500 Subject: [PATCH 01/24] "feat: added icons to the inventory types" --- .../InventoryTypesList/InventoryTypesList.jsx | 28 +++++++++++++------ .../InventoryTypesList/TypesList.module.css | 15 ++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/components/BMDashboard/InventoryTypesList/InventoryTypesList.jsx b/src/components/BMDashboard/InventoryTypesList/InventoryTypesList.jsx index bc1bc415e2..fc9a985dfe 100644 --- a/src/components/BMDashboard/InventoryTypesList/InventoryTypesList.jsx +++ b/src/components/BMDashboard/InventoryTypesList/InventoryTypesList.jsx @@ -1,25 +1,37 @@ import { useState, useEffect } from 'react'; import { connect } from 'react-redux'; import { useHistory } from 'react-router-dom'; - import { fetchInvTypeByType } from '~/actions/bmdashboard/invTypeActions'; import { fetchInvUnits } from '~/actions/bmdashboard/invUnitActions'; import { Accordion, Card, Button } from 'react-bootstrap'; import DatePicker from 'react-datepicker'; import 'react-datepicker/dist/react-datepicker.css'; - +import { + FaBoxes, + FaShoppingCart, + FaTools, + FaRecycle, + FaWrench, + FaRulerCombined, +} from 'react-icons/fa'; import BMError from '../shared/BMError'; import TypesTable from './TypesTable'; import UnitsTable from './invUnitsTable'; import AccordionToggle from './AccordionToggle'; import styles from './TypesList.module.css'; +const categoryIcons = { + Materials: , + Consumables: , + Equipments: , + Reusables: , + Tools: , +}; + export function InventoryTypesList(props) { const { invUnits, errors, dispatch } = props; const history = useHistory(); - const categories = ['Materials', 'Consumables', 'Equipments', 'Reusables', 'Tools']; - const [isError, setIsError] = useState(false); const [currentTime, setCurrentTime] = useState(new Date()); @@ -52,7 +64,6 @@ export function InventoryTypesList(props) { return (

All Inventory Types

-
Time:
- {categories?.map((category, index) => { return ( + {categoryIcons[category]} {category} @@ -79,9 +90,11 @@ export function InventoryTypesList(props) { ); })} - + + + Unit of Measurement @@ -91,7 +104,6 @@ export function InventoryTypesList(props) { -
{' '} - + {' '} +
@@ -1001,6 +809,7 @@ const mapStateToProps = state => ({ notification: state.notification, darkMode: state.theme.darkMode, }); + Header.propTypes = { hasPermission: PropTypes.func.isRequired, auth: PropTypes.shape({ @@ -1023,10 +832,11 @@ Header.propTypes = { darkMode: PropTypes.bool, taskEditSuggestionCount: PropTypes.number, }; + export default connect(mapStateToProps, { getHeaderData, getAllRoles, hasPermission, getWeeklySummaries, getUserProfile, -})(Header); +})(Header); \ No newline at end of file diff --git a/src/components/Header/Header.module.css b/src/components/Header/Header.module.css index a2deae1ca9..6bf8685535 100644 --- a/src/components/Header/Header.module.css +++ b/src/components/Header/Header.module.css @@ -406,4 +406,31 @@ width: 100% !important; justify-content: center !important; } +} + +/* ── BM Dashboard Accordion Styles ── */ + +.accordionToggle { + display: flex !important; + justify-content: space-between !important; + align-items: center !important; + cursor: pointer !important; +} + +.accordionArrow { + font-size: 0.65rem; + transition: transform 0.2s ease; + display: inline-block; +} + +.accordionArrowOpen { + transform: rotate(90deg); +} + +.bmSubItem { + padding-left: 1.8rem !important; +} + +.bmSubSubItem { + padding-left: 3rem !important; } \ No newline at end of file From d601bcdcfd9bedc709a33a322d478fee6d775638 Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Wed, 20 May 2026 00:24:01 -0500 Subject: [PATCH 07/24] "change BM Projects visibility" --- src/components/Header/Header.jsx | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 8159030457..a40d3ad05e 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -86,6 +86,7 @@ export function Header(props) { const [showPromotionsPopup, setShowPromotionsPopup] = useState(false); // BM Dashboard accordion state + const [showProjectDropdown, setShowProjectDropdown] = useState(false); const [bmProjectsOpen, setBmProjectsOpen] = useState(false); const [expandedSection, setExpandedSection] = useState(null); @@ -177,7 +178,9 @@ export function Header(props) { const dispatch = useDispatch(); const history = useHistory(); - const showBMDashboard = location.pathname.startsWith('/bmdashboard'); + useEffect(() => { + setShowProjectDropdown(location.pathname.startsWith('/bmdashboard/projects/')); + }, [location.pathname]); useEffect(() => { const handleStorageEvent = () => { @@ -539,13 +542,16 @@ export function Header(props) { {BLUE_SQUARE_EMAIL_MANAGEMENT} )} + {/* ── BM Dashboard Section ── */} + + {/* BM Dashboard main link */} BM Dashboard - {/* BM Projects accordion — only shown when on /bmdashboard/* */} - {showBMDashboard && ( + {/* BM Projects accordion — only shown when a project is selected */} + {showProjectDropdown && ( <> {/* BM Projects toggle */} {expandedSection === 'consumables' && ( - <> - - Consumable List - - + + Consumable List + )} {/* Equipment accordion */} @@ -643,11 +647,9 @@ export function Header(props) { {expandedSection === 'reusables' && ( - <> - - Reusable List - - + + Reusable List + )} {/* Tools accordion */} @@ -660,11 +662,9 @@ export function Header(props) { {expandedSection === 'tools' && ( - <> - - Tool List - - + + Tool List + )} {/* Other BM pages */} From 4fe06032d43548b839236484da79f88529db7134 Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Fri, 22 May 2026 09:48:10 -0500 Subject: [PATCH 08/24] "added all the available routes for Consumables, Reusables and Tools" --- src/components/Header/Header.jsx | 362 ++++++++----------------------- 1 file changed, 88 insertions(+), 274 deletions(-) diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index a40d3ad05e..ea34aedf34 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -101,13 +101,11 @@ export function Header(props) { ); const headerDisabled = isAuthUser ? false : !canInteractWithViewingUser; - // Reports const canGetReports = props.hasPermission('getReports', !isAuthUser); const canGetWeeklySummaries = props.hasPermission('getWeeklySummaries', !isAuthUser); const canGetWeeklyVolunteerSummary = props.hasPermission('getWeeklySummaries'); const canGetJobAnalytics = props.hasPermission('getJobReports'); - // Users const canAccessUserManagement = props.hasPermission('postUserProfile', !isAuthUser) || props.hasPermission('deleteUserProfile', !isAuthUser) || @@ -116,14 +114,12 @@ export function Header(props) { props.hasPermission('setFinalDay', !isAuthUser) || props.hasPermission('interactWithPauseUserButton', !isAuthUser); - // Badges const canAccessBadgeManagement = props.hasPermission('seeBadges', !isAuthUser) || props.hasPermission('createBadges', !isAuthUser) || props.hasPermission('updateBadges', !isAuthUser) || props.hasPermission('deleteBadges', !isAuthUser); - // Projects const canAccessProjects = props.hasPermission('postProject', !isAuthUser) || props.hasPermission('deleteProject', !isAuthUser) || @@ -136,35 +132,27 @@ export function Header(props) { props.hasPermission('updateTask', !isAuthUser) || props.hasPermission('deleteTask', !isAuthUser); - // Tasks const canUpdateTask = props.hasPermission('updateTask', !isAuthUser); - // Teams const canAccessTeams = props.hasPermission('postTeam', !isAuthUser) || props.hasPermission('putTeam', !isAuthUser) || props.hasPermission('deleteTeam', !isAuthUser) || props.hasPermission('assignTeamToUsers', !isAuthUser); - // Popups const canAccessPopups = props.hasPermission('createPopup', !isAuthUser) || props.hasPermission('updatePopup', !isAuthUser); - // SendEmails const canAccessSendEmails = props.hasPermission('sendEmails', !isAuthUser); - // Permissions const canAccessPermissionsManagement = props.hasPermission('postRole', !isAuthUser) || props.hasPermission('putRole', !isAuthUser) || props.hasPermission('deleteRole', !isAuthUser) || props.hasPermission('putUserProfilePermissions', !isAuthUser); - // Blue Square Email Management const canAccessBlueSquareEmailManagement = props.hasPermission('resendBlueSquareAndSummaryEmails', !isAuthUser); - - // PR Dashboard const canAccessPRDashboard = props.hasPermission('accessPRTeamDashboard', !isAuthUser); const userId = user.userid; @@ -197,12 +185,9 @@ export function Header(props) { setIsAuthUser(true); } }; - handleStorageEvent(); window.addEventListener('storage', handleStorageEvent); - return () => { - window.removeEventListener('storage', handleStorageEvent); - }; + return () => window.removeEventListener('storage', handleStorageEvent); }, [user.userid, props.auth.firstName]); useEffect(() => { @@ -227,12 +212,9 @@ export function Header(props) { console.log(`[Header Debug] Breakpoint: Mobile - Compact vertical layout`); } }; - handleResize(); window.addEventListener('resize', handleResize); - return () => { - window.removeEventListener('resize', handleResize); - }; + return () => window.removeEventListener('resize', handleResize); }, []); useEffect(() => { @@ -247,12 +229,8 @@ export function Header(props) { const roles = props.role?.roles; useEffect(() => { - if (roles.length === 0 && isAuthenticated) { - props.getAllRoles(); - } - if (isAuthenticated && user.userid) { - dispatch(getUnreadUserNotifications(user.userid)); - } + if (roles.length === 0 && isAuthenticated) props.getAllRoles(); + if (isAuthenticated && user.userid) dispatch(getUnreadUserNotifications(user.userid)); }, [isAuthenticated, user.userid, roles.length]); useEffect(() => { @@ -262,33 +240,16 @@ export function Header(props) { } }, [props.notification?.error]); - const toggle = () => { - setIsOpen(prevIsOpen => !prevIsOpen); - }; - - const openModal = () => { - setLogoutPopup(true); - }; + const toggle = () => setIsOpen(prevIsOpen => !prevIsOpen); + const openModal = () => setLogoutPopup(true); const handlePermissionChangeAck = async () => { try { setIsAckLoading(true); const { firstName: name, lastName, personalLinks, adminLinks, _id } = props.userProfile; - axios - .put(ENDPOINTS.USER_PROFILE(_id), { - firstName: name, - lastName, - personalLinks, - adminLinks, - isAcknowledged: true, - }) - .then(() => { - setIsAckLoading(false); - dispatch(getUserProfile(_id)); - }); - } catch (e) { - // console.log('update ack', e); - } + axios.put(ENDPOINTS.USER_PROFILE(_id), { firstName: name, lastName, personalLinks, adminLinks, isAcknowledged: true }) + .then(() => { setIsAckLoading(false); dispatch(getUserProfile(_id)); }); + } catch (e) { /* silent */ } }; const removeViewingUser = () => { @@ -308,10 +269,7 @@ export function Header(props) { const getMostRecentThursday = date => { const mostRecentThursday = new Date(date); - if (date.getDay() === 4) { - mostRecentThursday.setHours(0, 0, 0, 0); - return mostRecentThursday; - } + if (date.getDay() === 4) { mostRecentThursday.setHours(0, 0, 0, 0); return mostRecentThursday; } mostRecentThursday.setDate(date.getDate() - ((date.getDay() + 3) % 7)); mostRecentThursday.setHours(0, 0, 0, 0); return mostRecentThursday; @@ -321,8 +279,7 @@ export function Header(props) { if (!userId || hasProfileLoaded) return; try { const response = await axios.get(ENDPOINTS.USER_PROFILE(userId)); - const newUserProfile = response?.data; - setUserDashboardProfile(newUserProfile); + setUserDashboardProfile(response?.data); setHasProfileLoaded(true); } catch (err) { // eslint-disable-next-line no-console @@ -332,54 +289,32 @@ export function Header(props) { useEffect(() => { loadUserDashboardProfile(); - - if (user.role === 'Owner' || user.role === 'Administrator' || user.role === 'Mentor') { - setModalVisible(false); - return; - } - + if (user.role === 'Owner' || user.role === 'Administrator' || user.role === 'Mentor') { setModalVisible(false); return; } const today = new Date(); const lastDismissedDate = lastDismissed ? new Date(lastDismissed) : null; - - if (lastDismissedDate > today) { - setLastDismissed(null); - localStorage.removeItem(dismissalKey); - } - + if (lastDismissedDate > today) { setLastDismissed(null); localStorage.removeItem(dismissalKey); } if (!lastDismissed || lastDismissedDate < getMostRecentThursday(today)) { if (userDashboardProfile?.teams?.length > 0) { if (user.role === 'Assistant Manager' || user.role === 'Volunteer') { setModalVisible(true); - setModalContent( - `If you are seeing this, it's because you are on a team! As a member of a team, you need to turn in your work 24 hours earlier, i.e. FRIDAY night at midnight Pacific Time. This is so your manager has time to review it and submit and report on your entire team's work by the usual Saturday night deadline. For any work you plan on completing Saturday, please take pictures as best you can and include it in your summary as if it were already done.\n\nBy dismissing this notice, you acknowledge you understand and will do this.`, - ); + setModalContent(`If you are seeing this, it's because you are on a team! As a member of a team, you need to turn in your work 24 hours earlier, i.e. FRIDAY night at midnight Pacific Time. This is so your manager has time to review it and submit and report on your entire team's work by the usual Saturday night deadline. For any work you plan on completing Saturday, please take pictures as best you can and include it in your summary as if it were already done.\n\nBy dismissing this notice, you acknowledge you understand and will do this.`); } else if (user.role === 'Manager') { setModalVisible(true); setModalContent(`If you are seeing this, it's because you are a Manager of a team! Remember to turn in your team's work by the Saturday night at midnight (Pacific Time) deadline. Every member of your team gets a notice like this too. Theirs tells them to get you their work 24 hours early so you have time to review it and submit it. If you have to remind them repeatedly (4+ times, track it on their Google Doc), they should receive a blue square.`); } } - } else { - setModalVisible(false); - } + } else { setModalVisible(false); } }, [lastDismissed, userId, userDashboardProfile]); useEffect(() => { if (!isOpen) return; - const handleClickOutside = (event) => { if (collapseRef.current?.contains(event.target)) return; if (toggleRef.current?.contains(event.target)) return; setIsOpen(false); }; - - const timer = setTimeout(() => { - document.addEventListener('click', handleClickOutside); - }, 0); - - return () => { - clearTimeout(timer); - document.removeEventListener('click', handleClickOutside); - }; + const timer = setTimeout(() => { document.addEventListener('click', handleClickOutside); }, 0); + return () => { clearTimeout(timer); document.removeEventListener('click', handleClickOutside); }; }, [isOpen]); const fontColor = darkMode ? `${styles.darkDropdownText} ${styles.darkDropdownItem}` : `${styles.mobileDropdownText} ${styles.mobileDropdownItem}`; @@ -395,14 +330,8 @@ export function Header(props) { {showPromotionsPopup && setShowPromotionsPopup(false)} />}
-
- {isAuthenticated && } -
- -
- {isAuthenticated && } -
- +
{isAuthenticated && }
+
{isAuthenticated && }
{ - if (e.key === 'Escape') setIsOpen(false); - }} + onKeyDown={(e) => { if (e.key === 'Escape') setIsOpen(false); }} >