From 218b142b1007a029748b3846e4e0bfc632d960bf Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Tue, 24 Mar 2026 23:04:25 -0500 Subject: [PATCH 1/7] "bmdashboard header persistence" --- src/components/Header/Header.jsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 9a171d540e..9b8f2821c0 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -53,6 +53,7 @@ import { ACTUAL_COST_BREAKDOWN, BLUE_SQUARE_EMAIL_MANAGEMENT, JOB_ANALYTICS_REPORT, + BM_DASHBOARD } from '../../languages/en/ui'; import Logout from '../Logout/Logout'; import '../../App.module.css'; @@ -403,6 +404,9 @@ export function Header(props) { if (location.pathname === '/login') return null; const viewingUser = JSON.parse(window.sessionStorage.getItem('viewingUser')); + + const showBMDashboard = location.pathname.startsWith('/bmdashboard'); + return (
@@ -488,6 +492,13 @@ export function Header(props) { {DASHBOARD} + + {showBMDashboard && ( + + {BM_DASHBOARD} + + + )} From 7a1faed4b10261d31798b1fa960f756f97675703 Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Thu, 26 Mar 2026 20:54:22 -0500 Subject: [PATCH 2/7] =?UTF-8?q?add=20links=20to=20categories=20in=20?= =?UTF-8?q?=E2=80=9CAll=20Inventory=20Types=E2=80=9D=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConsumableList/ConsumableListView.jsx | 22 +++-- .../Equipment/List/EquipmentList.jsx | 40 ++++---- .../InventoryTypesList/InventoryTypesList.jsx | 98 ++++++++----------- .../MaterialList/MaterialListView.jsx | 77 ++++++++------- .../ReusableList/ReusableListView.jsx | 21 ++-- .../BMDashboard/Tools/ToolsList.jsx | 21 ++-- 6 files changed, 147 insertions(+), 132 deletions(-) diff --git a/src/components/BMDashboard/ConsumableList/ConsumableListView.jsx b/src/components/BMDashboard/ConsumableList/ConsumableListView.jsx index 230a12ccb4..438b256240 100644 --- a/src/components/BMDashboard/ConsumableList/ConsumableListView.jsx +++ b/src/components/BMDashboard/ConsumableList/ConsumableListView.jsx @@ -3,6 +3,8 @@ import { useDispatch, useSelector } from 'react-redux'; import { fetchAllConsumables } from '../../../actions/bmdashboard/consumableActions'; import ItemListView from '../ItemList/ItemListView'; import UpdateConsumableModal from '../UpdateConsumables/UpdateConsumableModal'; +import { Link } from 'react-router-dom'; +import styles from '../InventoryTypesList/TypesList.module.css'; function ConsumableListView() { const dispatch = useDispatch(); @@ -50,13 +52,19 @@ function ConsumableListView() { ]; return ( - + <> + + All Inventory Types + + + + ); } diff --git a/src/components/BMDashboard/Equipment/List/EquipmentList.jsx b/src/components/BMDashboard/Equipment/List/EquipmentList.jsx index fd4f7fbd32..b27b11b116 100644 --- a/src/components/BMDashboard/Equipment/List/EquipmentList.jsx +++ b/src/components/BMDashboard/Equipment/List/EquipmentList.jsx @@ -3,6 +3,7 @@ import useTheme from '../../../../hooks/useTheme'; import EquipmentsTable from './EquipmentsTable'; import EquipmentsInputs from './EquipmentsInputs'; import styles from './Equipments.module.css'; +import { Link } from 'react-router-dom'; function EquipmentList() { const [equipment, setEquipment] = useState({ label: 'All Equipments', value: '0' }); @@ -12,25 +13,30 @@ function EquipmentList() { useTheme(); return ( -
-
-
-
EQUIPMENTS
- - + <> + + All Inventory Types + +
+
+
+
EQUIPMENTS
+ + +
-
+ ); } diff --git a/src/components/BMDashboard/InventoryTypesList/InventoryTypesList.jsx b/src/components/BMDashboard/InventoryTypesList/InventoryTypesList.jsx index bc1bc415e2..56ab32c39b 100644 --- a/src/components/BMDashboard/InventoryTypesList/InventoryTypesList.jsx +++ b/src/components/BMDashboard/InventoryTypesList/InventoryTypesList.jsx @@ -1,31 +1,25 @@ import { useState, useEffect } from 'react'; import { connect } from 'react-redux'; -import { useHistory } from 'react-router-dom'; - +import { Link } 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 { Accordion, Card } from 'react-bootstrap'; import BMError from '../shared/BMError'; -import TypesTable from './TypesTable'; import UnitsTable from './invUnitsTable'; import AccordionToggle from './AccordionToggle'; import styles from './TypesList.module.css'; +const categories = [ + { label: 'Materials', route: '/bmdashboard/materials' }, + { label: 'Consumables', route: '/bmdashboard/consumables' }, + { label: 'Equipments', route: '/bmdashboard/equipment' }, + { label: 'Reusables', route: '/bmdashboard/reusables' }, + { label: 'Tools', route: '/bmdashboard/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()); - - const handleBack = () => { - history.goBack(); - }; useEffect(() => { dispatch(fetchInvTypeByType('Materials')); @@ -50,52 +44,38 @@ export function InventoryTypesList(props) { } return ( -
-

All Inventory Types

- -
- Time: - setCurrentTime(date)} - dateFormat="MM-dd-yyyy hh:mm:ss" - id="timestamp" - showTimeInput - /> +
+ {/* Page Header */} +
+

All Inventory Types

+

Select a category to view and manage inventory

- - {categories?.map((category, index) => { - return ( - - - {category} - - - - - - - - ); - })} - - - - Unit of Measurement - - - - - - - - + {/* Category Cards Grid */} +
+ {categories.map(({ label, route }) => ( + + {label} +
+ + ))} +
-
- + {/* Unit of Measurement */} +
+

Unit of Measurement

+ + + + View all units + + + + + + + +
); diff --git a/src/components/BMDashboard/MaterialList/MaterialListView.jsx b/src/components/BMDashboard/MaterialList/MaterialListView.jsx index 4b6baa5edb..c005ab663d 100644 --- a/src/components/BMDashboard/MaterialList/MaterialListView.jsx +++ b/src/components/BMDashboard/MaterialList/MaterialListView.jsx @@ -12,6 +12,8 @@ import { import { fetchAllMaterials, resetMaterialUpdate } from '~/actions/bmdashboard/materialsActions'; import ItemListView from '../ItemList/ItemListView'; import UpdateMaterialModal from '../UpdateMaterials/UpdateMaterialModal'; +import { Link } from 'react-router-dom'; +import styles from '../InventoryTypesList/TypesList.module.css'; function MaterialListView() { const dispatch = useDispatch(); @@ -82,42 +84,47 @@ function MaterialListView() { ]; return ( - - - - - - - setSearchTerm(e.target.value)} - /> - {searchTerm && ( - - - - )} - - - + type="text" + placeholder="Search Material, PID, Unit..." + value={searchTerm} + onChange={e => setSearchTerm(e.target.value)} + /> + {searchTerm && ( + + + + )} + + + + ); } diff --git a/src/components/BMDashboard/ReusableList/ReusableListView.jsx b/src/components/BMDashboard/ReusableList/ReusableListView.jsx index 01ee88ff08..37fea5b56e 100644 --- a/src/components/BMDashboard/ReusableList/ReusableListView.jsx +++ b/src/components/BMDashboard/ReusableList/ReusableListView.jsx @@ -3,6 +3,8 @@ import { useDispatch, useSelector } from 'react-redux'; import { fetchAllReusables } from '~/actions/bmdashboard/reusableActions'; import ItemListView from '../ItemList/ItemListView'; import UpdateReusableModal from '../UpdateReusables/UpdateReusableModal'; +import { Link } from 'react-router-dom'; +import styles from '../InventoryTypesList/TypesList.module.css'; function ReusableListView() { const dispatch = useDispatch(); @@ -44,13 +46,18 @@ function ReusableListView() { ]; return ( - + <> + + All Inventory Types + + + ); } diff --git a/src/components/BMDashboard/Tools/ToolsList.jsx b/src/components/BMDashboard/Tools/ToolsList.jsx index 66d1889946..bda4e26e5a 100644 --- a/src/components/BMDashboard/Tools/ToolsList.jsx +++ b/src/components/BMDashboard/Tools/ToolsList.jsx @@ -3,6 +3,8 @@ import { useDispatch, useSelector } from 'react-redux'; import { fetchTools } from '../../../actions/bmdashboard/toolActions'; import ToolItemListView from '../ToolItemList/ToolItemListView'; import UpdateToolModal from '../UpdateTools/UpdateToolModal'; +import { Link } from 'react-router-dom'; +import styles from '../InventoryTypesList/TypesList.module.css'; function ToolsList() { const dispatch = useDispatch(); @@ -47,13 +49,18 @@ function ToolsList() { ]; return ( - + <> + + All Inventory Types + + + ); } From ee98c96dfccab51cb0c80546822f2bc0f6c7c5ca Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Thu, 26 Mar 2026 21:51:08 -0500 Subject: [PATCH 3/7] "fixed css of typeslist" --- .../InventoryTypesList/TypesList.module.css | 206 ++++++++++++++---- 1 file changed, 162 insertions(+), 44 deletions(-) diff --git a/src/components/BMDashboard/InventoryTypesList/TypesList.module.css b/src/components/BMDashboard/InventoryTypesList/TypesList.module.css index 476ebde5c4..54849d3fd4 100644 --- a/src/components/BMDashboard/InventoryTypesList/TypesList.module.css +++ b/src/components/BMDashboard/InventoryTypesList/TypesList.module.css @@ -1,15 +1,17 @@ +:root { + --color-h50: #e8f4f9; + --color-h100: #78bdda; + --color-h500: #0d5675; + --color-n0: #fff; + --color-text: #1c8bcc; + --font-clickable: roboto; +} + .typesListContainer { width: 100%; max-width: 1080px; margin: 1rem auto; padding: 0 1rem; - - --color-h50: #e8f4f9; - --color-h100: #78bdda; - --color-h500: #0d5675; - --color-n0: #ffffff; - --color-text: #1c8bcc; - --font-clickable: Roboto; } /* Dark mode support */ @@ -96,7 +98,7 @@ } .tableHeader { - border-bottom: 1px solid rgba(0, 0, 0, 0.125); + border-bottom: 1px solid rgb(0 0 0 / 12.5%); } :global(.dark-mode) .tableHeader, @@ -258,16 +260,86 @@ font-size: 10px; } -/* Dark mode table styling */ -:global(.dark-mode) .typesListContainer table, -:global(.bm-dashboard-dark) .typesListContainer table { - color: #ffffff; +/* ---- Page Header ---- */ +.pageHeader { + margin-bottom: 28px; + padding-bottom: 16px; + border-bottom: 2px solid var(--color-h50); } -:global(.dark-mode) .typesListContainer table tbody tr, -:global(.bm-dashboard-dark) .typesListContainer table tbody tr { - background-color: #2a2a2a; - color: #ffffff; +.pageTitle { + font-size: 2rem; + font-weight: 700; + color: var(--color-h500); + margin: 0 0 6px; +} + +.pageSubtitle { + font-size: 14px; + color: #6c757d; + margin: 0; +} + +/* ---- Category Cards Grid ---- */ +.categoryGrid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 16px; + margin-bottom: 36px; +} + +.categoryCard { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20px 24px; + background-color: var(--color-n0); + border: 1.5px solid var(--color-h50); + border-radius: 12px; + text-decoration: none !important; + color: inherit !important; + transition: all 0.2s ease; + box-shadow: 0 1px 4px rgb(0 0 0 / 6%); +} + +.categoryCardLabel { + font-size: 16px; + font-weight: 700; + color: var(--color-h500); +} + +.categoryCardArrow { + font-size: 22px; + color: var(--color-h100); + font-weight: 300; + flex-shrink: 0; +} + +/* ---- Unit Section ---- */ +.unitSection { + margin-top: 8px; +} + +.unitSectionTitle { + font-size: 1.1rem; + font-weight: 600; + color: var(--color-h500); + margin-bottom: 12px; +} + +.unitCard { + border: 1.5px solid var(--color-h50) !important; + border-radius: 10px !important; + overflow: hidden; +} + +/* Main container dark mode */ +:global(.bm-dashboard-dark) .typesListContainer { + color: #fff; +} + +:global(.bm-dashboard-dark) .typesListContainer h1 { + color: #fff !important; } :global(.dark-mode) .typesListContainer table tbody tr:hover, @@ -319,19 +391,17 @@ :global(.dark-mode) .timestampContainer, :global(.bm-dashboard-dark) .timestampContainer { - color: #ffffff; + color: #fff; } :global(.bm-dashboard-dark) .timestampContainer span { - color: #ffffff !important; + color: #fff !important; } -/* Dark mode react-datepicker styling */ -:global(.dark-mode) .timestampContainer :global(.react-datepicker-wrapper) input, -:global(.bm-dashboard-dark) .timestampContainer :global(.react-datepicker-wrapper) input { - background-color: #3a3a3a !important; - color: #ffffff !important; - border-color: rgba(255, 255, 255, 0.2) !important; +:global(.bm-dashboard-dark) #timestamp { + background-color: #2e5061 !important; + color: #fff !important; + border-color: #3a506b !important; } :global(.dark-mode) :global(.react-datepicker), @@ -414,7 +484,7 @@ /* Dark mode card header - Bootstrap override */ :global(.bm-dashboard-dark) .cardHeader { background-color: #2e5061 !important; - color: #ffffff !important; + color: #fff !important; border-color: #3a506b !important; } @@ -425,7 +495,7 @@ /* Accordion collapse body dark mode */ :global(.bm-dashboard-dark) .accordionCollapse { background-color: #1c2541 !important; - color: #ffffff !important; + color: #fff !important; scrollbar-width: thin; scrollbar-color: #3a506b #1c2541; } @@ -457,13 +527,13 @@ } :global(.bm-dashboard-dark) .tableHeader th { - color: #ffffff !important; + color: #fff !important; background-color: #1c2541 !important; } /* Table dark mode (bm-dashboard specific) */ :global(.bm-dashboard-dark) .typesListContainer :global(table) { - color: #ffffff !important; + color: #fff !important; background-color: #1c2541 !important; } @@ -472,7 +542,7 @@ } :global(.bm-dashboard-dark) .typesListContainer :global(table) :global(thead) th { - color: #ffffff !important; + color: #fff !important; background-color: #1c2541 !important; border-color: #3a506b !important; } @@ -482,7 +552,7 @@ } :global(.bm-dashboard-dark) .typesListContainer :global(table) td { - color: #ffffff !important; + color: #fff !important; background-color: transparent !important; } @@ -497,20 +567,20 @@ /* Card header - Bootstrap override (bm-dashboard specific) */ :global(.bm-dashboard-dark) .typesListContainer :global(.card-header) { background-color: #2e5061 !important; - color: #ffffff !important; + color: #fff !important; border-color: #3a506b !important; } /* Card body - Bootstrap override (bm-dashboard specific) */ :global(.bm-dashboard-dark) .typesListContainer :global(.card-body) { background-color: #1c2541 !important; - color: #ffffff !important; + color: #fff !important; } /* Buttons dark mode (bm-dashboard specific) */ :global(.bm-dashboard-dark) .btnTypes { background-color: #3a506b !important; - color: #ffffff !important; + color: #fff !important; border-color: #5a7a9b !important; } @@ -522,7 +592,7 @@ /* Back button dark mode */ :global(.bm-dashboard-dark) .buttonContainer a { background-color: #2e5061 !important; - color: #ffffff !important; + color: #fff !important; } :global(.bm-dashboard-dark) .buttonContainer a:hover { @@ -532,7 +602,7 @@ /* Input measurement dark mode */ :global(.bm-dashboard-dark) #input-measurement { background-color: #2e5061 !important; - color: #ffffff !important; + color: #fff !important; border-color: #3a506b !important; } @@ -543,7 +613,7 @@ /* All inputs in the container */ :global(.bm-dashboard-dark) .typesListContainer input { background-color: #2e5061 !important; - color: #ffffff !important; + color: #fff !important; border-color: #3a506b !important; } @@ -554,15 +624,21 @@ :global(.bm-dashboard-dark) .typesListContainer input:focus { background-color: #3a506b !important; border-color: #5a7a9b !important; - box-shadow: 0 0 0 0.2rem rgba(106, 241, 234, 0.25) !important; + box-shadow: 0 0 0 0.2rem rgb(106 241 234 / 25%) !important; +} + +:global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker-time__input) input { + background-color: #1c2541 !important; + color: #fff !important; + border-color: #3a506b !important; } /* Autocomplete styling */ :global(.bm-dashboard-dark) .typesListContainer input:-webkit-autofill, :global(.bm-dashboard-dark) .typesListContainer input:-webkit-autofill:hover, :global(.bm-dashboard-dark) .typesListContainer input:-webkit-autofill:focus { - -webkit-box-shadow: 0 0 0 30px #2e5061 inset !important; - -webkit-text-fill-color: #ffffff !important; + box-shadow: 0 0 0 30px #2e5061 inset !important; + -webkit-text-fill-color: #fff !important; } /* Bootstrap Card dark mode */ @@ -585,7 +661,7 @@ :global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker__current-month), :global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker__day-name), :global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker__day) { - color: #ffffff !important; + color: #fff !important; } :global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker__day:hover) { @@ -606,7 +682,7 @@ } :global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker__time-list-item) { - color: #ffffff !important; + color: #fff !important; } :global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker__time-list-item:hover) { @@ -614,11 +690,53 @@ } :global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker__input-time-container) { - color: #ffffff !important; + color: #fff !important; } -:global(.bm-dashboard-dark) .typesListContainer :global(.react-datepicker-time__input) input { +/* ---- New page element dark mode (before hover rules) ---- */ +:global(.bm-dashboard-dark) .pageTitle { + color: #fff !important; +} + +:global(.bm-dashboard-dark) .pageSubtitle { + color: #b5bac5 !important; +} + +:global(.bm-dashboard-dark) .pageHeader { + border-color: #3a506b !important; +} + +:global(.bm-dashboard-dark) .categoryCard { background-color: #1c2541 !important; - color: #ffffff !important; border-color: #3a506b !important; + color: #fff !important; +} + +:global(.bm-dashboard-dark) .categoryCardLabel { + color: #fff !important; +} + +:global(.bm-dashboard-dark) .categoryCardArrow { + color: #6af1ea !important; +} + +:global(.bm-dashboard-dark) .unitSectionTitle { + color: #fff !important; +} + +:global(.bm-dashboard-dark) .unitCard { + border-color: #3a506b !important; +} + +/* ---- Hover rules AFTER dark mode overrides ---- */ +.categoryCard:hover { + border-color: var(--color-h100); + box-shadow: 0 4px 12px rgb(13 86 117 / 12%); + transform: translateY(-2px); + text-decoration: none !important; +} + +:global(.bm-dashboard-dark) .categoryCard:hover { + border-color: #5a7a9b !important; + box-shadow: 0 4px 12px rgb(0 0 0 / 30%) !important; } From 9408b61bedc918ba5a3352b9e9edffbba51870e8 Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Thu, 26 Mar 2026 22:02:52 -0500 Subject: [PATCH 4/7] fixed css typelist --- .../InventoryTypesList/TypesList.module.css | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/components/BMDashboard/InventoryTypesList/TypesList.module.css b/src/components/BMDashboard/InventoryTypesList/TypesList.module.css index 54849d3fd4..5f5449aeef 100644 --- a/src/components/BMDashboard/InventoryTypesList/TypesList.module.css +++ b/src/components/BMDashboard/InventoryTypesList/TypesList.module.css @@ -740,3 +740,64 @@ border-color: #5a7a9b !important; box-shadow: 0 4px 12px rgb(0 0 0 / 30%) !important; } + +/* ---- Back link ---- */ +.backLink { + display: inline-flex; + align-items: center; + gap: 6px; + margin-bottom: 20px; + padding: 8px 16px; + background-color: #e8f4f9; + color: #0d5675 !important; + text-decoration: none !important; + font-size: 14px; + font-weight: 600; + border-radius: 25px; + border: 1.5px solid #78bdda; + transition: all 0.2s ease; +} + +.backLink::before { + content: ''; + display: inline-block; + width: 8px; + height: 8px; + border-left: 2px solid #0d5675; + border-bottom: 2px solid #0d5675; + transform: rotate(45deg); + transition: border-color 0.2s ease; + margin-right: 2px; +} + +.backLink:hover { + background-color: #0d5675; + color: #fff !important; + border-color: #0d5675; + text-decoration: none !important; + transform: translateX(-2px); +} + +.backLink:hover::before { + border-color: #fff; +} + +:global(.bm-dashboard-dark) .backLink { + background-color: #1c2541 !important; + color: #6af1ea !important; + border-color: #3a506b !important; +} + +:global(.bm-dashboard-dark) .backLink::before { + border-color: #6af1ea !important; +} + +:global(.bm-dashboard-dark) .backLink:hover { + background-color: #2e5061 !important; + color: #fff !important; + border-color: #5a7a9b !important; +} + +:global(.bm-dashboard-dark) .backLink:hover::before { + border-color: #fff !important; +} From 39b96ad7fe0e1b719ddac46f785d02d9708e6e5b Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Thu, 26 Mar 2026 22:56:43 -0500 Subject: [PATCH 5/7] fixed css equipments --- src/components/BMDashboard/Equipment/List/EquipmentList.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/BMDashboard/Equipment/List/EquipmentList.jsx b/src/components/BMDashboard/Equipment/List/EquipmentList.jsx index b27b11b116..a591890eea 100644 --- a/src/components/BMDashboard/Equipment/List/EquipmentList.jsx +++ b/src/components/BMDashboard/Equipment/List/EquipmentList.jsx @@ -4,6 +4,7 @@ import EquipmentsTable from './EquipmentsTable'; import EquipmentsInputs from './EquipmentsInputs'; import styles from './Equipments.module.css'; import { Link } from 'react-router-dom'; +import stylesList from '../../InventoryTypesList/TypesList.module.css'; function EquipmentList() { const [equipment, setEquipment] = useState({ label: 'All Equipments', value: '0' }); @@ -14,7 +15,7 @@ function EquipmentList() { return ( <> - + All Inventory Types
From a33ab99dae0e16a0c88240c7aeb2319bc5eade81 Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Thu, 26 Mar 2026 23:14:07 -0500 Subject: [PATCH 6/7] "added all inventory types to project dropdown" --- src/components/Header/Header.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 9b8f2821c0..98af8396f2 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -517,6 +517,9 @@ export function Header(props) { }`} disabled={headerDisabled} > + + All Inventory Types + Add Material From ff13ed73b2274052585598d989e2391668485181 Mon Sep 17 00:00:00 2001 From: Manoj Puttaswamy Date: Wed, 22 Apr 2026 17:54:22 -0400 Subject: [PATCH 7/7] fix: resolve Header.jsx conflict with bmdashboard header persistence --- src/components/Header/Header.jsx | 258 +++++++++++++++++++------------ 1 file changed, 163 insertions(+), 95 deletions(-) diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 98af8396f2..e5cced19d0 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -1,75 +1,74 @@ -import { useState, useEffect, useMemo, React, useRef } from 'react'; -import { ENDPOINTS } from '~/utils/URL'; import axios from 'axios'; -import { getWeeklySummaries } from '~/actions/weeklySummaries'; -import { Link, useLocation, useHistory } from 'react-router-dom'; +import PropTypes from 'prop-types'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { connect, useDispatch } from 'react-redux'; +import { Link, useHistory, useLocation } from 'react-router-dom'; +import { toast } from 'react-toastify'; import { - Collapse, - Navbar, + Button, + Card, NavbarToggler, - Nav, - NavItem, - NavLink, - UncontrolledDropdown, - DropdownToggle, - DropdownMenu, DropdownItem, + DropdownMenu, + DropdownToggle, Modal, - ModalHeader, ModalBody, ModalFooter, - Button, - Card, + ModalHeader, + Nav, + Navbar, + NavItem, + NavLink, + UncontrolledDropdown } from 'reactstrap'; +import { getWeeklySummaries } from '~/actions/weeklySummaries'; import PopUpBar from '~/components/PopUpBar'; import { fetchTaskEditSuggestions } from '~/components/TaskEditSuggestions/thunks'; -import { toast } from 'react-toastify'; +import { ENDPOINTS } from '~/utils/URL'; import { getHeaderData } from '../../actions/authActions'; +import { + getUnreadUserNotifications, + resetNotificationError, +} from '../../actions/notificationAction'; import { getAllRoles } from '../../actions/role'; -import Timer from '../Timer/Timer'; -import OwnerMessage from '../OwnerMessage/OwnerMessage'; +import { getUserProfile } from '../../actions/userProfile'; +import '../../App.module.css'; import { - DASHBOARD, - TIMELOG, - REPORTS, - WEEKLY_SUMMARIES_REPORT, - TEAM_LOCATIONS, - OTHER_LINKS, - USER_MANAGEMENT, + ACTUAL_COST_BREAKDOWN, BADGE_MANAGEMENT, - PROJECTS, - TEAMS, - WELCOME, - VIEW_PROFILE, - UPDATE_PASSWORD, + BLUE_SQUARE_EMAIL_MANAGEMENT, + DASHBOARD, + JOB_ANALYTICS_REPORT, + BM_DASHBOARD, LOGOUT, + OTHER_LINKS, PERMISSIONS_MANAGEMENT, + PR_PROMOTIONS, + PROJECTS, + REPORTS, SEND_EMAILS, + TEAM_LOCATIONS, + TEAMS, + TIMELOG, + TOTAL_CONSTRUCTION_SUMMARY, TOTAL_ORG_SUMMARY, TOTAL_ORG_SUMMARY_EMAIL, - TOTAL_CONSTRUCTION_SUMMARY, - PR_PROMOTIONS, - ACTUAL_COST_BREAKDOWN, - BLUE_SQUARE_EMAIL_MANAGEMENT, - JOB_ANALYTICS_REPORT, - BM_DASHBOARD + UPDATE_PASSWORD, + USER_MANAGEMENT, + VIEW_PROFILE, + WEEKLY_SUMMARIES_REPORT, + WELCOME, } from '../../languages/en/ui'; -import Logout from '../Logout/Logout'; -import '../../App.module.css'; -import styles from './Header.module.css'; import hasPermission, { cantUpdateDevAdminDetails } from '../../utils/permissions'; -import { - getUnreadUserNotifications, - resetNotificationError, -} from '../../actions/notificationAction'; -import NotificationCard from '../Notification/notificationCard'; -import DarkModeButton from './DarkModeButton'; -import BellNotification from './BellNotification'; -import { getUserProfile } from '../../actions/userProfile'; import PermissionWatcher from '../Auth/PermissionWatcher'; +import Logout from '../Logout/Logout'; +import NotificationCard from '../Notification/notificationCard'; +import OwnerMessage from '../OwnerMessage/OwnerMessage'; import DisplayBox from '../PRPromotions/DisplayBox'; -import PropTypes from 'prop-types'; +import Timer from '../Timer/Timer'; +import BellNotification from './BellNotification'; +import DarkModeButton from './DarkModeButton'; +import styles from './Header.module.css'; export function Header(props) { const location = useLocation(); @@ -158,6 +157,9 @@ export function Header(props) { // Blue Square Email Management const canAccessBlueSquareEmailManagement = props.hasPermission('resendBlueSquareAndSummaryEmails', !isAuthUser); + // PR Dashboard + const canAccessPRDashboard = props.hasPermission('accessPRTeamDashboard', !isAuthUser); + const userId = user.userid; const [isModalVisible, setModalVisible] = useState(false); @@ -251,11 +253,12 @@ export function Header(props) { if (roles.length === 0 && isAuthenticated) { props.getAllRoles(); } - // Fetch unread notification - if (isAuthenticated && displayUserId) { - dispatch(getUnreadUserNotifications(displayUserId)); + // Fetch unread notification - always use the logged-in user's ID, + // not displayUserId, which may be a viewed user (causing a 403 error) + if (isAuthenticated && user.userid) { + dispatch(getUnreadUserNotifications(user.userid)); } - }, [isAuthenticated, displayUserId, roles.length]); + }, [isAuthenticated, user.userid, roles.length]); useEffect(() => { if (props.notification?.error) { @@ -265,8 +268,8 @@ export function Header(props) { }, [props.notification?.error]); const toggle = () => { - setIsOpen(prevIsOpen => !prevIsOpen); - }; + setIsOpen(prevIsOpen => !prevIsOpen); +}; const openModal = () => { setLogoutPopup(true); @@ -379,25 +382,25 @@ export function Header(props) { setShowProjectDropdown(location.pathname.startsWith('/bmdashboard/projects/')); }, [location.pathname]); - useEffect(() => { - const handleClickOutside = (event) => { - if ( - collapseRef.current && - !collapseRef.current.contains(event.target) && - !toggleRef.current?.contains(event.target) - ) { - setIsOpen(false); - } - }; + useEffect(() => { + if (!isOpen) return; - if (isOpen) { - document.addEventListener('mousedown', handleClickOutside); - } + const handleClickOutside = (event) => { + if (collapseRef.current?.contains(event.target)) return; + if (toggleRef.current?.contains(event.target)) return; + setIsOpen(false); + }; - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [isOpen]); + // Defer adding listener until after current click event finishes + 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}`; @@ -407,9 +410,10 @@ export function Header(props) { const showBMDashboard = location.pathname.startsWith('/bmdashboard'); + return (
- + {logoutPopup && } {showPromotionsPopup && setShowPromotionsPopup(false)} />} @@ -422,8 +426,17 @@ export function Header(props) { {isAuthenticated && }
- -
@@ -919,9 +982,13 @@ export function Header(props) {
)} - {props.auth.isAuthenticated && unreadNotifications?.length > 0 ? ( - - ) : null} + {props.auth.isAuthenticated && ( +
+ {unreadNotifications?.length > 0 ? ( + + ) : null} +
+ )}
); @@ -964,3 +1031,4 @@ export default connect(mapStateToProps, { getWeeklySummaries, getUserProfile, })(Header); +