@@ -11,6 +11,16 @@ import {
1111import '../styles/components.css'
1212import '../styles/pages.css'
1313
14+ function formatDaysOfCover ( value ) {
15+ if ( ! Number . isFinite ( value ) ) {
16+ return 'N/A'
17+ }
18+ if ( value >= 999 ) {
19+ return '999+ days'
20+ }
21+ return `${ value . toFixed ( 1 ) } days`
22+ }
23+
1424function DashboardPage ( ) {
1525 const { accessToken } = useAuth ( )
1626
@@ -96,6 +106,30 @@ function DashboardPage() {
96106 ]
97107 } , [ stockOverview , lowStockAlerts , consumptionSummary , supplierSummary , consumptionDays ] )
98108
109+ const consumptionByItemId = useMemo ( ( ) => {
110+ const map = new Map ( )
111+ consumptionSummary . forEach ( ( row ) => {
112+ map . set ( String ( row . item_id ) , Number ( row . avg_daily_consumption || 0 ) )
113+ } )
114+ return map
115+ } , [ consumptionSummary ] )
116+
117+ const actionItems = useMemo ( ( ) => {
118+ const sortedAlerts = [ ...lowStockAlerts ] . sort ( ( a , b ) => Number ( b . shortage || 0 ) - Number ( a . shortage || 0 ) )
119+ return sortedAlerts . slice ( 0 , 4 ) . map ( ( alert ) => {
120+ const stock = stockOverview . find ( ( row ) => String ( row . item_id ) === String ( alert . item_id ) )
121+ const avgDaily = consumptionByItemId . get ( String ( alert . item_id ) ) || 0
122+ const qtyAvailable = Number ( stock ?. quantity_available || 0 )
123+ const daysOfCover = avgDaily > 0 ? qtyAvailable / avgDaily : Number . POSITIVE_INFINITY
124+
125+ return {
126+ ...alert ,
127+ daysOfCover,
128+ avgDaily,
129+ }
130+ } )
131+ } , [ lowStockAlerts , stockOverview , consumptionByItemId ] )
132+
99133 if ( loading ) {
100134 return < section className = "page-stack" > < p className = "page-state" > Loading dashboard data...</ p > </ section >
101135 }
@@ -107,8 +141,8 @@ function DashboardPage() {
107141 return (
108142 < section className = "page-stack" >
109143 < PageHeader
110- title = "Operations Dashboard "
111- subtitle = "Historical and current view: stock levels, consumption trends, and reorder risk ."
144+ title = "What Needs Action Today? "
145+ subtitle = "Historical and current view of stock, usage trends, and immediate reorder risks ."
112146 />
113147
114148 < div className = "stats-grid" >
@@ -122,6 +156,29 @@ function DashboardPage() {
122156 ) ) }
123157 </ div >
124158
159+ < section className = "content-card" >
160+ < h3 > Priority Action Queue</ h3 >
161+ < p className = "section-subtitle" > Most urgent items to reorder based on shortage and current cover.</ p >
162+ { actionItems . length === 0 ? (
163+ < p className = "page-state" > No urgent reorder action right now.</ p >
164+ ) : (
165+ < div className = "action-grid" >
166+ { actionItems . map ( ( item ) => (
167+ < article key = { item . item_id } className = "action-card" >
168+ < div className = "action-head" >
169+ < p className = "action-item" > { item . item_name } </ p >
170+ < span className = "status-pill status-critical" > Order now</ span >
171+ </ div >
172+ < p > Shortage: < strong > { item . shortage } </ strong > </ p >
173+ < p > Avg daily usage: < strong > { item . avgDaily . toFixed ( 2 ) } </ strong > </ p >
174+ < p > Days of cover: < strong > { formatDaysOfCover ( item . daysOfCover ) } </ strong > </ p >
175+ < p > Supplier: < strong > { item . supplier_name || 'N/A' } </ strong > </ p >
176+ </ article >
177+ ) ) }
178+ </ div >
179+ ) }
180+ </ section >
181+
125182 < section className = "content-card" >
126183 < h3 > Current Stock Levels</ h3 >
127184 < p className = "section-subtitle" > What has happened now: quantity available vs reorder thresholds.</ p >
@@ -132,25 +189,35 @@ function DashboardPage() {
132189 < th > Item</ th >
133190 < th > Category</ th >
134191 < th > Available</ th >
192+ < th > Days of Cover</ th >
135193 < th > Reorder</ th >
136194 < th > Safety</ th >
137195 < th > Status</ th >
138196 </ tr >
139197 </ thead >
140198 < tbody >
141199 { stockOverview . map ( ( row ) => (
142- < tr key = { row . item_id } >
200+ ( ( ) => {
201+ const avgDaily = consumptionByItemId . get ( String ( row . item_id ) ) || 0
202+ const daysOfCover = avgDaily > 0
203+ ? Number ( row . quantity_available || 0 ) / avgDaily
204+ : Number . POSITIVE_INFINITY
205+ return (
206+ < tr key = { row . item_id } >
143207 < td > { row . item_name } </ td >
144208 < td > { row . category } </ td >
145209 < td > { row . quantity_available } </ td >
210+ < td > { formatDaysOfCover ( daysOfCover ) } </ td >
146211 < td > { row . reorder_level } </ td >
147212 < td > { row . safety_stock } </ td >
148213 < td >
149214 < span className = { `status-pill status-${ row . status ?. toLowerCase ( ) } ` } >
150215 { row . status }
151216 </ span >
152217 </ td >
153- </ tr >
218+ </ tr >
219+ )
220+ } ) ( )
154221 ) ) }
155222 </ tbody >
156223 </ table >
0 commit comments