Skip to content

Commit 5a5f7f5

Browse files
authored
Merge branch 'development' into Aditya-feat/Add-Smart-Insights-and-Predictive-Utilization-Analysis-to-the-Utilization-Chart
2 parents d5870b2 + be13abd commit 5a5f7f5

237 files changed

Lines changed: 6967 additions & 31784 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package-lock.json

Lines changed: 0 additions & 29194 deletions
This file was deleted.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"html-to-pdfmake": "^2.0.6",
6565
"html2canvas": "^1.4.1",
6666
"jest": "^30.2.0",
67-
"joi": "^18.1.2",
67+
"joi": "^18.2.1",
6868
"joi-browser": "^13.4.0",
6969
"jquery": "^3.7.1",
7070
"jspdf": "^4.2.1",
@@ -82,7 +82,7 @@
8282
"object-hash": "^3.0.0",
8383
"path-browserify": "^1.0.1",
8484
"pdfmake": "^0.2.20",
85-
"plotly.js": "^3.3.1",
85+
"plotly.js": "^3.5.0",
8686
"popper.js": "^1.16.1",
8787
"prop-types": "^15.7.2",
8888
"rc-slider": "^11.1.8",

src/actions/KIInventoryActions.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import axios from 'axios';
2+
import { ENDPOINTS } from '~/utils/URL';
3+
import {
4+
KI_INVENTORY_FETCH_REQUEST,
5+
KI_INVENTORY_FETCH_SUCCESS,
6+
KI_INVENTORY_FETCH_FAILURE,
7+
KI_INVENTORY_STATS_REQUEST,
8+
KI_INVENTORY_STATS_SUCCESS,
9+
KI_INVENTORY_STATS_FAILURE,
10+
KI_PRESERVED_ITEMS_REQUEST,
11+
KI_PRESERVED_ITEMS_SUCCESS,
12+
KI_PRESERVED_ITEMS_FAILURE,
13+
} from '../constants/KIInventoryConstants';
14+
15+
const createFetchAction = (requestType, successType, failureType, endpoint, defaultErrorMsg) => async dispatch => {
16+
dispatch({ type: requestType });
17+
try {
18+
const res = await axios.get(endpoint);
19+
dispatch({ type: successType, payload: res.data.data });
20+
} catch (err) {
21+
dispatch({
22+
type: failureType,
23+
payload: err.response?.data?.message || defaultErrorMsg,
24+
});
25+
}
26+
};
27+
28+
/**
29+
* Fetch all inventory items across all categories.
30+
* GET /api/kitchenandinventory/inventory/items
31+
*/
32+
export const fetchInventoryItems = () => createFetchAction(
33+
KI_INVENTORY_FETCH_REQUEST,
34+
KI_INVENTORY_FETCH_SUCCESS,
35+
KI_INVENTORY_FETCH_FAILURE,
36+
ENDPOINTS.KI_INVENTORY_ITEMS,
37+
'Failed to fetch inventory items.'
38+
);
39+
40+
/**
41+
* Fetch inventory stats — total items, critical stock count, low stock count.
42+
* GET /api/kitchenandinventory/inventory/items/stats
43+
*/
44+
export const fetchInventoryStats = () => createFetchAction(
45+
KI_INVENTORY_STATS_REQUEST,
46+
KI_INVENTORY_STATS_SUCCESS,
47+
KI_INVENTORY_STATS_FAILURE,
48+
ENDPOINTS.KI_INVENTORY_STATS,
49+
'Failed to fetch inventory stats.'
50+
);
51+
52+
/**
53+
* Fetch preserved ingredient items (expiry >= 1 year from now).
54+
* GET /api/kitchenandinventory/inventory/items/ingredients/preserved
55+
*/
56+
export const fetchPreservedItems = () => createFetchAction(
57+
KI_PRESERVED_ITEMS_REQUEST,
58+
KI_PRESERVED_ITEMS_SUCCESS,
59+
KI_PRESERVED_ITEMS_FAILURE,
60+
ENDPOINTS.KI_INVENTORY_PRESERVED,
61+
'Failed to fetch preserved items.'
62+
);

src/actions/badgeManagement.js

Lines changed: 34 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
import axios from 'axios';
22
import { toast } from 'react-toastify';
33
import { formatDate } from '~/utils/formatDate';
4+
import { ENDPOINTS } from '~/utils/URL';
45
import {
5-
GET_ALL_BADGE_DATA,
66
ADD_SELECT_BADGE,
7-
REMOVE_SELECT_BADGE,
87
CLEAR_NAME_AND_SELECTED,
98
CLEAR_SELECTED,
9+
CLOSE_ALERT,
10+
GET_ALL_BADGE_DATA,
11+
GET_BADGE_COUNT,
1012
GET_FIRST_NAME,
1113
GET_LAST_NAME,
1214
GET_MESSAGE,
13-
CLOSE_ALERT,
1415
GET_USER_ID,
15-
GET_BADGE_COUNT,
16+
REMOVE_SELECT_BADGE,
1617
RESET_BADGE_COUNT,
1718
SET_ACTIVE_TAB,
1819
} from '../constants/badge';
19-
import { ENDPOINTS } from '~/utils/URL';
2020

2121
export const ALERT_DELAY = process.env.NODE_ENV === 'test' ? 0 : 6000;
2222

2323
const getAllBadges = allBadges => {
2424
const action = {
2525
type: GET_ALL_BADGE_DATA,
2626
allBadges,
27-
};
27+
};
2828
return action;
2929
};
3030

@@ -34,13 +34,13 @@ export const fetchAllBadges = (forceRefresh = false) => {
3434
// Check the endpoint
3535
const baseUrl = ENDPOINTS.BADGE();
3636
const url = forceRefresh ? `${baseUrl}?t=${Date.now()}` : baseUrl;
37-
37+
3838
const response = await axios.get(url);
39-
39+
4040
const actionResult = getAllBadges(response.data);
41-
41+
4242
dispatch(actionResult);
43-
43+
4444
return response.status;
4545
} catch (err) {
4646
return err.response?.status || 500;
@@ -168,7 +168,7 @@ export const returnUpdatedBadgesCollection = (badgeCollection, selectedBadgesId)
168168
const currentTs = Date.now();
169169
const currentDate = formatDate();
170170

171-
for (let i = 0; i < newBadgeCollection.length; i+=1) {
171+
for (let i = 0; i < newBadgeCollection.length; i += 1) {
172172
const badgeObj = newBadgeCollection[i];
173173
if (badgeId === badgeObj.badge) {
174174
// If the badge is found, increment the count and mark it as included
@@ -200,45 +200,30 @@ export const returnUpdatedBadgesCollection = (badgeCollection, selectedBadgesId)
200200
};
201201

202202
export const returnUpdatedBadgesCollectionSingleUser = (badgeCollection, selectedBadgesId) => {
203-
let newBadgeCollection = Array.from(badgeCollection);
204-
205-
const updatedOrAddedBadges = {};
203+
const newBadgeCollection = badgeCollection.map(b => ({
204+
...b,
205+
earnedDate: [...(b.earnedDate || [])],
206+
badge: b.badge && typeof b.badge === 'object' ? b.badge._id : b.badge,
207+
}));
208+
const currentTs = Date.now();
209+
const currentDate = formatDate();
206210

207211
selectedBadgesId.forEach(originalBadgeId => {
208212
let badgeId = originalBadgeId;
209213
if (badgeId.includes('assign-badge-')) badgeId = badgeId.replace('assign-badge-', '');
210214

211-
if (!updatedOrAddedBadges[badgeId]) {
212-
let included = false;
213-
const currentTs = Date.now();
214-
const currentDate = formatDate();
215-
216-
newBadgeCollection = newBadgeCollection.map(badgeObj => {
217-
if (badgeId === badgeObj.badge) {
218-
if (!included) {
219-
included = true;
220-
updatedOrAddedBadges[badgeId] = true;
221-
return {
222-
...badgeObj,
223-
count: badgeObj.count ? badgeObj.count + 1 : 1,
224-
lastModified: currentTs,
225-
earnedDate: [...badgeObj.earnedDate, currentDate]
226-
};
227-
}
228-
updatedOrAddedBadges[badgeId] = true;
229-
}
230-
return badgeObj;
231-
});
232-
233-
if (!included) {
234-
newBadgeCollection.push({
235-
badge: badgeId,
236-
count: 1,
237-
lastModified: currentTs,
238-
earnedDate: [currentDate],
239-
});
240-
updatedOrAddedBadges[badgeId] = true;
241-
}
215+
const existing = newBadgeCollection.find(b => b.badge === badgeId);
216+
if (existing) {
217+
existing.count = (existing.count || 0) + 1;
218+
existing.lastModified = currentTs;
219+
existing.earnedDate.push(currentDate);
220+
} else {
221+
newBadgeCollection.push({
222+
badge: badgeId,
223+
count: 1,
224+
lastModified: currentTs,
225+
earnedDate: [currentDate],
226+
});
242227
}
243228
});
244229

@@ -276,8 +261,10 @@ export const assignBadgesByUserID = (userId, selectedBadges) => {
276261
return;
277262
}
278263
const { badgeCollection } = res.data;
279-
for (let i = 0; i < badgeCollection.length; i+=1) {
280-
badgeCollection[i].badge = badgeCollection[i].badge._id;
264+
for (let i = 0; i < badgeCollection.length; i += 1) {
265+
if (badgeCollection[i].badge && typeof badgeCollection[i].badge === 'object') {
266+
badgeCollection[i].badge = badgeCollection[i].badge._id;
267+
}
281268
}
282269

283270
const userToBeAssignedBadge = res.data._id;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import axios from 'axios';
2+
import { ENDPOINTS } from '../../utils/URL';
3+
import {
4+
FETCH_COST_BREAKDOWN_START,
5+
FETCH_COST_BREAKDOWN_SUCCESS,
6+
FETCH_COST_BREAKDOWN_ERROR,
7+
FETCH_COST_DETAIL_START,
8+
FETCH_COST_DETAIL_SUCCESS,
9+
FETCH_COST_DETAIL_ERROR,
10+
CLEAR_COST_DETAIL,
11+
} from '../../constants/bmdashboard/costBreakdownConstants';
12+
13+
export const fetchCostBreakdown = ({ projectId, startDate, endDate } = {}) => {
14+
return async dispatch => {
15+
dispatch({ type: FETCH_COST_BREAKDOWN_START });
16+
try {
17+
const url = ENDPOINTS.BM_COST_BREAKDOWN(projectId, startDate, endDate);
18+
const res = await axios.get(url);
19+
dispatch({ type: FETCH_COST_BREAKDOWN_SUCCESS, payload: res.data });
20+
} catch (error) {
21+
const msg = error.response?.data?.error || 'Failed to load cost breakdown';
22+
dispatch({ type: FETCH_COST_BREAKDOWN_ERROR, payload: msg });
23+
}
24+
};
25+
};
26+
27+
export const fetchCostDetail = ({ projectId, startDate, endDate } = {}) => {
28+
return async dispatch => {
29+
dispatch({ type: FETCH_COST_DETAIL_START });
30+
try {
31+
const url = ENDPOINTS.BM_COST_BREAKDOWN(projectId, startDate, endDate, true);
32+
const res = await axios.get(url);
33+
dispatch({ type: FETCH_COST_DETAIL_SUCCESS, payload: res.data });
34+
} catch (error) {
35+
const msg = error.response?.data?.error || 'Failed to load category details';
36+
dispatch({ type: FETCH_COST_DETAIL_ERROR, payload: msg });
37+
}
38+
};
39+
};
40+
41+
export const clearCostDetail = () => ({
42+
type: CLEAR_COST_DETAIL,
43+
});

src/components/App.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable no-undef */
2-
import { Component, useEffect } from 'react';
2+
import { Component, useEffect, Suspense } from 'react';
33
import { Provider, useSelector } from 'react-redux';
44
import { BrowserRouter as Router, useLocation } from 'react-router-dom';
55
import { PersistGate } from 'redux-persist/integration/react';
@@ -234,7 +234,7 @@ class App extends Component {
234234
<Router>
235235
<ThemeManager />
236236
<UpdateDocumentTitle />
237-
{routes}
237+
<Suspense fallback={<Loading />}>{routes}</Suspense>
238238
</Router>
239239
</ModalProvider>
240240
</QueryClientProvider>

src/components/AttendanceSystem/mockData.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const events = [
1212
registrations: 100,
1313
attendees: 78,
1414
completed: 75,
15-
walkouts: 5,
15+
walkouts: 3,
1616
date: getDateString(-30), // Past date - will show as Completed
1717
time: '09:00 AM - 05:00 PM',
1818
link: 'https://conferencea.com',
@@ -27,7 +27,7 @@ export const events = [
2727
registrations: 50,
2828
attendees: 44,
2929
completed: 38,
30-
walkouts: 2,
30+
walkouts: 6,
3131
date: getDateString(7), // Future date - will show as Upcoming
3232
time: '10:00 AM - 02:00 PM',
3333
link: 'https://workshopb.com',
@@ -42,7 +42,7 @@ export const events = [
4242
registrations: 75,
4343
attendees: 63,
4444
completed: 55,
45-
walkouts: 5,
45+
walkouts: 8,
4646
date: getDateString(0), // Today - will show as In Progress if current time is within range
4747
time: '12:00 AM - 11:59 PM',
4848
link: 'https://seminarc.com',

src/components/BMDashboard/Equipment/Detail/EquipmentDetail.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function DescriptionItem({ label, value, title }) {
3737

3838
return (
3939
<div>
40-
<Button onClick={toggle} color="link" className="descriptionItem_button">
40+
<Button onClick={toggle} color="link" className={styles.descriptionItem_button}>
4141
{label}
4242
</Button>
4343
<EquipmentModal modal={modal} toggle={toggle} title={title} value={value} />

src/components/BMDashboard/Equipment/List/EquipmentsInputs.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ function EquipmentsInputs({ equipment, setEquipment, project, setProject }) {
112112
};
113113

114114
return (
115-
<div className="container">
115+
<div className={styles.container}>
116116
<Form>
117117
<Row className={`align-items-center ${styles.InputsMargin}`}>
118118
<Col className={`${styles.InputsMargin}`}>

src/components/BMDashboard/Equipment/Update/UpdateEquipment.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ export default function UpdateEquipment() {
546546
onChange={e => setStatus(e.target.value)}
547547
required
548548
style={selectInputStyle}
549-
className="custom-select"
549+
className={styles['custom-select']}
550550
>
551551
<option value="">Select status</option>
552552
<option value="Working well">Working well</option>
@@ -571,7 +571,7 @@ export default function UpdateEquipment() {
571571
onChange={e => setLastUsedBy(e.target.value)}
572572
required
573573
style={selectInputStyle}
574-
className="custom-select"
574+
className={styles['custom-select']}
575575
>
576576
<option value="">Select user</option>
577577
<option value="Jane Doe (Volunteer #1)">Jane Doe (Volunteer #1)</option>
@@ -611,7 +611,7 @@ export default function UpdateEquipment() {
611611
onChange={e => setLastUsedFor(e.target.value)}
612612
required
613613
style={selectInputStyle}
614-
className="custom-select"
614+
className={styles['custom-select']}
615615
>
616616
<option value="">Select usage</option>
617617
<option value="Kitchen - tiling">Kitchen - tiling</option>

0 commit comments

Comments
 (0)