Skip to content

Commit cd0c6b4

Browse files
authored
Merge branch 'development' into fix/bm-expenditure-charts
2 parents 91b26ba + e1eb951 commit cd0c6b4

93 files changed

Lines changed: 8725 additions & 5319 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.

.stylelintrc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@
99
"no-duplicate-selectors": true,
1010
"selector-pseudo-class-no-unknown": [
1111
true,
12-
{
13-
"ignorePseudoClasses": ["global", "local"]
14-
}
12+
{ "ignorePseudoClasses": ["global", "local"] }
1513
],
16-
"selector-class-pattern": null
14+
"selector-class-pattern": null,
15+
"selector-id-pattern": null
1716
}
18-
}
17+
}

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"leaflet": "^1.9.4",
7171
"leaflet.heat": "^0.2.0",
7272
"leaflet.markercluster": "^1.5.3",
73-
"libphonenumber-js": "^1.12.31",
73+
"libphonenumber-js": "^1.12.38",
7474
"lodash": "^4.17.21",
7575
"lucide-react": "^0.484.0",
7676
"micromatch": "^4.0.8",
@@ -216,4 +216,5 @@
216216
"optionalDependencies": {
217217
"@rollup/rollup-darwin-arm64": "^4.54.0"
218218
}
219-
}
219+
}
220+

postinstall.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// Script to copy tinymce to public folder. Read more: https://www.tiny.cloud/docs/tinymce/latest/react-pm-host/
22
const fse = require('fs-extra');
3-
const path = require('path');
3+
const path = require('node:path');
44

55
const topDir = __dirname;
6-
// const topDir = import.meta.dirname;
76
fse.emptyDirSync(path.join(topDir, 'public', 'tinymce'));
87
fse.copySync(path.join(topDir, 'node_modules', 'tinymce'), path.join(topDir, 'public', 'tinymce'), {
98
overwrite: true,

public/emailFormat.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<!DOCTYPE html>
2-
<html>
3-
<head>
2+
<html lang="en">
3+
<head>
44
<title>Hello, World</title>
5-
</head>
6-
<body>
5+
</head>
6+
<body>
77
<h1>Hello, World</h1>
8-
</body>
8+
</body>
99
</html>

public/index.css

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,12 @@ body.bm-dashboard-dark:not(.no-global-theme) {
1212
background-color: #1b2a41 !important;
1313
color: #ffffff !important;
1414
}
15-
1615
body.dark-mode:not(.no-global-theme) #root,
1716
body.bm-dashboard-dark:not(.no-global-theme) #root {
1817
background-color: #1b2a41 !important;
1918
color: #ffffff !important;
2019
}
2120

22-
/* SAFE BASE (dark mode) */
23-
body.dark-mode:not(.no-global-theme),
24-
body.bm-dashboard-dark:not(.no-global-theme) {
25-
color: #ffffff;
26-
}
27-
2821
/* ========================= */
2922
/* TYPOGRAPHY (DARK MODE) */
3023
/* ========================= */

refactor-css-classes.js

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// updated on june 11
22
/* eslint-disable import/no-extraneous-dependencies */
33
/* eslint-disable no-console */
4-
const fs = require('fs');
5-
const path = require('path');
4+
const fs = require('node:fs');
5+
const path = require('node:path');
66
const postcss = require('postcss');
77
const safeParser = require('postcss-safe-parser');
88

99
// Helper to convert kebab-case, snake_case, pascalcase to camelCase
1010
const toCamelCase = str => {
11-
const formatted = str.replace(/[-_](\w)/g, (_, char) => char.toUpperCase());
11+
const formatted = str.replaceAll(/[-_](\w)/gu, (_, char) => char.toUpperCase());
1212
return formatted.charAt(0).toLowerCase() + formatted.slice(1);
1313
};
1414

@@ -21,7 +21,7 @@ const convertCSSFile = filePath => {
2121

2222
root.walkRules(rule => {
2323
const updated = rule.selectors.map(selector => {
24-
return selector.replace(/\.(\w[\w-]*)/g, (_, className) => {
24+
return selector.replaceAll(/\.(\w[\w-]*)/gu, (_, className) => {
2525
const camel = toCamelCase(className);
2626
classMap[className] = camel;
2727
return `.${camel}`;
@@ -32,15 +32,12 @@ const convertCSSFile = filePath => {
3232
});
3333

3434
fs.writeFileSync(filePath, root.toString());
35-
// eslint-disable-next-line no-console
3635
console.log(`✅ Updated CSS: ${filePath}`);
37-
// eslint-disable-next-line no-console
38-
// console.log('classMap after CSS processing:', classMap);
3936
};
4037

4138
// Step 2: Replace import statement for CSS module in JSX
4239
const replaceImportStatement = code => {
43-
const importRegex = /import\s+['"](.+\/)?([a-zA-Z0-9_-]+)\.css['"];/;
40+
const importRegex = /import\s+['"](.+\/)?([a-zA-Z0-9_-]+)\.css['"];/u;
4441
// eslint-disable-next-line default-param-last
4542
return code.replace(importRegex, (_, pathPrefix = '', cssFileName) => {
4643
return `import styles from '${pathPrefix}${cssFileName}.module.css';`;
@@ -64,8 +61,8 @@ const replaceInCodeFile = filePath => {
6461
}
6562

6663
// Step 2: Replace className="text-light input-file-upload" → className={styles.textLight + " " + styles.inputFileUpload}
67-
code = code.replace(/className\s*=\s*["']([^"']+)["']/g, (_, classStr) => {
68-
const classList = classStr.trim().split(/\s+/);
64+
code = code.replaceAll(/className\s*=\s*["']([^"']+)["']/gu, (_, classStr) => {
65+
const classList = classStr.trim().split(/\s+/u);
6966

7067
// Skip transforming if no class in classList exists in classMap
7168
if (classList.every(cls => !classMap[cls])) {
@@ -98,36 +95,31 @@ const walkDir = dir => {
9895
if (stats.isDirectory()) {
9996
walkDir(fullPath);
10097
} else if (file.endsWith('.css')) {
101-
cssFiles.push(fullPath); // Add CSS file path to the array
98+
cssFiles.push(fullPath);
10299
} else if (
103100
file.endsWith('.js') ||
104101
file.endsWith('.jsx') ||
105102
file.endsWith('.ts') ||
106103
file.endsWith('.tsx') ||
107104
file.endsWith('.html')
108105
) {
109-
codeFiles.push(fullPath); // Add JS/JSX file path to the array
106+
codeFiles.push(fullPath);
110107
}
111108
});
112109

113110
// Now process CSS files first
114111
cssFiles.forEach(cssFile => {
115112
console.log('Processing CSS file:', cssFile);
116-
convertCSSFile(cssFile); // Process CSS files
113+
convertCSSFile(cssFile);
117114
});
118115

119116
// Then process code files (JS/JSX, etc.)
120117
codeFiles.forEach(codeFile => {
121118
console.log('Processing code file:', codeFile);
122-
replaceInCodeFile(codeFile); // Process JS/JSX files
119+
replaceInCodeFile(codeFile);
123120
});
124121
};
125122

126123
// 🚀 Start here: Replace with your actual project folder path
127124
const rootDir = 'src/components/HGNForm';
128125
walkDir(rootDir);
129-
130-
// const mapPath = path.join(__dirname, 'class-map.json');
131-
// fs.writeFileSync(mapPath, JSON.stringify(classMap, null, 2));
132-
// // eslint-disable-next-line no-console
133-
// console.log(`🗺️ Class map written to ${mapPath}`);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import axios from 'axios';
2+
import configureMockStore from 'redux-mock-store';
3+
import thunk from 'redux-thunk';
4+
5+
import * as types from '../../constants/WeeklySummaryEmailBccConstants';
6+
import { updateWeeklySummaryEmailAssignment } from '../weeklySummaryEmailBCCAction';
7+
8+
vi.mock('axios');
9+
10+
const mockStore = configureMockStore([thunk]);
11+
12+
describe('updateWeeklySummaryEmailAssignment action creator', () => {
13+
it('dispatches updated assignment when API returns wrapped assignment payload', async () => {
14+
const store = mockStore({});
15+
const updatedAssignment = {
16+
_id: 'assignment-id',
17+
email: 'updated@example.com',
18+
assignedTo: { _id: 'user-id', firstName: 'Updated', lastName: 'User' },
19+
};
20+
21+
axios.put.mockResolvedValue({
22+
status: 200,
23+
data: { assignment: updatedAssignment },
24+
});
25+
26+
await store.dispatch(updateWeeklySummaryEmailAssignment('assignment-id', 'updated@example.com'));
27+
28+
expect(store.getActions()).toContainEqual({
29+
type: types.UPDATE_WEEKLY_SUMMARY_EMAIL_ASSIGNMENT,
30+
payload: updatedAssignment,
31+
});
32+
});
33+
34+
it('dispatches updated assignment when API returns assignment directly', async () => {
35+
const store = mockStore({});
36+
const updatedAssignment = {
37+
_id: 'assignment-id',
38+
email: 'updated@example.com',
39+
};
40+
41+
axios.put.mockResolvedValue({
42+
status: 200,
43+
data: updatedAssignment,
44+
});
45+
46+
await store.dispatch(updateWeeklySummaryEmailAssignment('assignment-id', 'updated@example.com'));
47+
48+
expect(store.getActions()).toContainEqual({
49+
type: types.UPDATE_WEEKLY_SUMMARY_EMAIL_ASSIGNMENT,
50+
payload: updatedAssignment,
51+
});
52+
});
53+
54+
it('dispatches error action when update fails', async () => {
55+
const store = mockStore({});
56+
const error = new Error('Network Error');
57+
58+
axios.put.mockRejectedValue(error);
59+
60+
await store.dispatch(updateWeeklySummaryEmailAssignment('assignment-id', 'updated@example.com'));
61+
62+
expect(store.getActions()).toContainEqual({
63+
type: types.WEEKLY_SUMMARY_EMAIL_ASSIGNMENT_ERROR,
64+
payload: error,
65+
});
66+
});
67+
});

src/actions/bmdashboard/equipmentActions.js

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const setErrors = payload => {
3232
};
3333

3434
export const fetchEquipmentById = equipmentId => {
35-
const url = ENDPOINTS.BM_EQUIPMENT_BY_ID(equipmentId);
35+
const url = `${ENDPOINTS.BM_EQUIPMENT_BY_ID(equipmentId)}`;
3636
return async dispatch => {
3737
axios
3838
.get(url)
@@ -83,12 +83,12 @@ export const purchaseEquipment = async body => {
8383
export const updateMultipleEquipmentLogs = (projectId, bulkArr) => dispatch => {
8484
axios
8585
.put(
86-
`${ENDPOINTS.BM_EQUIPMENT_LOGS}?project=${projectId}`,
86+
`${ENDPOINTS.BM_EQUIPMENT_LOGS}?project=${projectId}`,
8787
bulkArr
8888
)
8989
.then(res => {
90-
dispatch(setEquipments(res.data));
91-
toast.success('Equipment logs updated successfully!');
90+
dispatch(setEquipments(res.data));
91+
toast.success('Equipment logs updated successfully!');
9292
return res.data;
9393
})
9494
.catch(err => {
@@ -98,6 +98,71 @@ export const updateMultipleEquipmentLogs = (projectId, bulkArr) => dispatch => {
9898
});
9999
}
100100

101+
export const updateEquipment = (equipmentId, updateData) => async (dispatch, getState) => {
102+
const url = `${ENDPOINTS.BM_EQUIPMENT_STATUS_UPDATE(equipmentId)}`;
103+
104+
try {
105+
const state = getState();
106+
let currentUserId = state?.auth?.user?.userid;
107+
108+
if (!currentUserId) {
109+
currentUserId = state?.auth?.user?._id ||
110+
state?.auth?.user?.id ||
111+
state?.auth?._id ||
112+
state?.auth?.id;
113+
}
114+
115+
if (!currentUserId) {
116+
const storedUserId = localStorage.getItem('userId');
117+
if (storedUserId) {
118+
currentUserId = storedUserId;
119+
}
120+
}
121+
122+
if (!currentUserId) {
123+
const errorMsg = 'User not authenticated. Please log in.';
124+
toast.error(errorMsg);
125+
throw new Error(errorMsg);
126+
}
127+
128+
const statusUpdateData = {
129+
condition: updateData.condition,
130+
lastUsedBy: updateData.lastUsedBy,
131+
lastUsedFor: updateData.lastUsedFor,
132+
replacementRequired: updateData.replacementRequired,
133+
description: updateData.description || '',
134+
notes: updateData.notes || '',
135+
createdBy: currentUserId,
136+
};
137+
138+
const res = await axios.put(url, statusUpdateData);
139+
140+
dispatch(setEquipment(res.data));
141+
toast.success('Equipment status updated successfully!');
142+
dispatch(fetchEquipmentById(equipmentId));
143+
144+
return res.data;
145+
} catch (err) {
146+
147+
let errorMessage = 'Failed to update equipment status.';
148+
149+
if (err.response) {
150+
errorMessage = err.response.data?.error ||
151+
err.response.data?.message ||
152+
err.response.statusText ||
153+
errorMessage;
154+
dispatch(setErrors(err.response.data));
155+
} else if (err.request) {
156+
errorMessage = 'No response from server. Please check your connection.';
157+
} else {
158+
errorMessage = err.message;
159+
}
160+
161+
toast.error(errorMessage);
162+
throw err;
163+
}
164+
};
165+
101166
export const updateEquipmentById = (equipmentId, updatedFields) => async dispatch => {
102167
dispatch({ type: UPDATE_EQUIPMENT_START });
103168
try {

0 commit comments

Comments
 (0)