From 3457dfd86c4eabfd2b12b3529c5860996af89b5e Mon Sep 17 00:00:00 2001 From: Adithya Cherukuri Date: Fri, 22 May 2026 18:12:57 -0400 Subject: [PATCH 1/3] fix: resolve ItemsTable crash and re-apply Consumables table usability features --- .../BMDashboard/ItemList/ItemListView.jsx | 1 + .../BMDashboard/ItemList/ItemsTable.jsx | 133 ++++++++++++------ .../ItemList/RecordsModal.module.css | 5 + .../BMDashboard/ItemList/SelectItem.jsx | 77 ++++++++-- 4 files changed, 158 insertions(+), 58 deletions(-) diff --git a/src/components/BMDashboard/ItemList/ItemListView.jsx b/src/components/BMDashboard/ItemList/ItemListView.jsx index 118146a9f5..53c423260d 100644 --- a/src/components/BMDashboard/ItemList/ItemListView.jsx +++ b/src/components/BMDashboard/ItemList/ItemListView.jsx @@ -253,6 +253,7 @@ export function ItemListView({ UpdateItemModal={UpdateItemModal} dynamicColumns={dynamicColumns} darkMode={darkMode} + itemType={itemType} sortConfig={sortConfig} onSort={handleSort} totalItems={totalItems} diff --git a/src/components/BMDashboard/ItemList/ItemsTable.jsx b/src/components/BMDashboard/ItemList/ItemsTable.jsx index 278962e77f..74ce83933b 100644 --- a/src/components/BMDashboard/ItemList/ItemsTable.jsx +++ b/src/components/BMDashboard/ItemList/ItemsTable.jsx @@ -1,25 +1,17 @@ import { useState } from 'react'; -import { Table, Button } from 'reactstrap'; +import { Table, Button, Badge } from 'reactstrap'; import { BiPencil } from 'react-icons/bi'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSortDown, faSort, faSortUp } from '@fortawesome/free-solid-svg-icons'; import RecordsModal from './RecordsModal'; +import styles from './ItemListView.module.css'; const rowsPerPageOptions = [25, 50, 100]; function generatePageNumbers(current, total) { - if (total <= 7) { - return Array.from({ length: total }, (_, i) => i + 1); - } - - if (current <= 3) { - return [1, 2, 3, 4, 5, '...', total]; - } - - if (current >= total - 2) { - return [1, '...', total - 4, total - 3, total - 2, total - 1, total]; - } - + if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1); + if (current <= 3) return [1, 2, 3, 4, 5, '...', total]; + if (current >= total - 2) return [1, '...', total - 4, total - 3, total - 2, total - 1, total]; return [1, '...', current - 1, current, current + 1, '...', total]; } @@ -30,6 +22,7 @@ export default function ItemsTable({ UpdateItemModal, dynamicColumns, darkMode = false, + itemType, sortConfig, onSort, totalItems, @@ -60,9 +53,8 @@ export default function ItemsTable({ setRecordType(type); }; - const getNestedValue = (obj, path) => { - return path.split('.').reduce((acc, part) => (acc ? acc[part] : null), obj); - }; + const getNestedValue = (obj, path) => + path.split('.').reduce((acc, part) => (acc ? acc[part] : null), obj); const getIconFor = key => { if (!sortConfig?.key || sortConfig.key !== key) return faSort; @@ -77,6 +69,28 @@ export default function ItemsTable({ Hold: 'hold', }; + const numericKeys = ['stockBought', 'stockUsed', 'stockAvailable', 'stockWasted']; + + const headerStyle = (key, isAction = false) => { + const base = { verticalAlign: 'middle' }; + if (numericKeys.includes(key)) base.textAlign = 'right'; + if (isAction) { + base.borderLeft = '2px solid #dee2e6'; + base.textAlign = 'center'; + } + return base; + }; + + const cellStyle = (key, isAction = false) => { + const base = { verticalAlign: 'middle' }; + if (numericKeys.includes(key)) base.textAlign = 'right'; + if (isAction) { + base.borderLeft = '2px solid #dee2e6'; + base.textAlign = 'center'; + } + return base; + }; + return ( <> - onSort?.('project')} className={styles.sortableTh}> + onSort?.('project')} + className={styles.sortableTh} + style={{ verticalAlign: 'middle' }} + > Project - - onSort?.('name')} className={styles.sortableTh}> + onSort?.('name')} + className={styles.sortableTh} + style={{ verticalAlign: 'middle' }} + > Name - - {dynamicColumns.map(({ label }) => { + {dynamicColumns.map(({ label, key }) => { const sortKey = dynamicSortKeyByLabel[label]; const clickable = Boolean(sortKey); - return ( onSort?.(sortKey) : undefined} className={clickable ? styles.sortableTh : undefined} + style={headerStyle(key)} > {label} {clickable && } ); })} - - Usage Record - Updates - Purchases + + Usage Record + + + Updates + + + Purchases + - {filteredItems && filteredItems.length > 0 ? ( filteredItems.map(el => ( - {el.project?.name} - {el.itemType?.name} - - {dynamicColumns.map(({ label, key }) => ( - {getNestedValue(el, key)} - ))} - - + {el.project?.name} + {el.itemType?.name} + {dynamicColumns.map(({ label, key }) => { + const value = getNestedValue(el, key); + if (key === 'stockAvailable' && Number(value) < 10) { + return ( + + + Low + + {value} + + ); + } + return ( + + {value} + + ); + })} + - - + - - + - - {generatePageNumbers(currentPage, totalPages).map((p, idx) => typeof p === 'number' ? ( - - - @@ -294,7 +306,7 @@ ItemListView.propTypes = { errors: PropTypes.shape({ message: PropTypes.string, }), - UpdateItemModal: PropTypes.elementType.isRequired, + UpdateItemModal: PropTypes.elementType, dynamicColumns: PropTypes.arrayOf( PropTypes.shape({ label: PropTypes.string.isRequired, diff --git a/src/components/BMDashboard/ItemList/ItemsTable.jsx b/src/components/BMDashboard/ItemList/ItemsTable.jsx index 5f106f8f07..a880ebadbd 100644 --- a/src/components/BMDashboard/ItemList/ItemsTable.jsx +++ b/src/components/BMDashboard/ItemList/ItemsTable.jsx @@ -55,7 +55,7 @@ export default function ItemsTable({ }; const getNestedValue = (obj, path) => - path.split('.').reduce((acc, part) => (acc ? acc[part] : null), obj); + path ? path.split('.').reduce((acc, part) => (acc ? acc[part] : null), obj) : null; const getIconFor = key => { if (!sortConfig?.key || sortConfig.key !== key) return faSort; @@ -74,7 +74,7 @@ export default function ItemsTable({ const getColumnStyle = (key, isAction = false) => { const base = { verticalAlign: 'middle' }; - if (numericKeys.has(key)) base.textAlign = 'right'; + if (key && numericKeys.has(key)) base.textAlign = 'right'; if (isAction) { base.borderLeft = '2px solid #dee2e6'; base.textAlign = 'center'; @@ -92,7 +92,9 @@ export default function ItemsTable({ recordType={recordType} itemType={itemType} /> - + {UpdateItemModal && ( + + )}
@@ -112,12 +114,12 @@ export default function ItemsTable({ > Name - {dynamicColumns.map(({ label, key }) => { + {(dynamicColumns || []).map(({ label, key }) => { const sortKey = dynamicSortKeyByLabel[label]; const clickable = Boolean(sortKey); return ( - {dynamicColumns.map(({ label, key }) => { + {(dynamicColumns || []).map(({ label, key }) => { const value = getNestedValue(el, key); - if (key === 'stockAvailable' && Number(value) < 10) { + if ( + key === 'stockAvailable' && + value !== null && + value !== undefined && + Number(value) < 10 + ) { return ( - ); @@ -223,7 +230,7 @@ export default function ItemsTable({ )) ) : ( - diff --git a/src/components/BMDashboard/ItemList/SelectItem.jsx b/src/components/BMDashboard/ItemList/SelectItem.jsx index f0634dcc49..93527c1e30 100644 --- a/src/components/BMDashboard/ItemList/SelectItem.jsx +++ b/src/components/BMDashboard/ItemList/SelectItem.jsx @@ -52,7 +52,7 @@ export default function SelectItem({ }) { let itemSet = []; - if (items?.length) { + if (items && items.length > 0) { if (label === 'Consumables') { itemSet = getConsumablesSet(items, selectedProject); } else if (label === 'Tool Status') { @@ -99,7 +99,7 @@ export default function SelectItem({ disabled={!itemSet.length} style={darkStyle} > - {itemSet.length ? ( + {itemSet.length > 0 ? ( <> {itemSet.map(name => (
onSort?.(sortKey) : undefined} className={clickable ? styles.sortableTh : undefined} style={getColumnStyle(key)} @@ -149,11 +151,16 @@ export default function ItemsTable({
{el.project?.name} {el.itemType?.name} + + {value}
+ No items data