Skip to content

Commit 52dda5f

Browse files
Merge pull request #4735 from OneCommunityGlobal/development
Frontend Release to Main [4.71]
2 parents 219e69e + 2281ca6 commit 52dda5f

170 files changed

Lines changed: 11611 additions & 5402 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.

index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
To create a production bundle, use `npm run build` or `yarn build`.
3838
-->
3939
<script type="module" src="/src/index.jsx"></script>
40-
<a class="top" href="#">Back to Top ↑</a>
40+
<a class="back-to-top" href="#" aria-label="Back to top">
41+
42+
</a>
4143
</body>
4244
</html>

package-lock.json

Lines changed: 1953 additions & 505 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"@react-leaflet/core": "^2.1.0",
3030
"@reduxjs/toolkit": "^2.4.0",
3131
"@sentry/browser": "^9.15.0",
32-
"@tanstack/react-query": "^5.85.3",
32+
"@tanstack/react-query": "^5.90.16",
3333
"@tinymce/miniature": "^6.0.0",
3434
"@tinymce/tinymce-react": "^6.1.0",
3535
"ajv": "^8.0.0",
@@ -54,7 +54,7 @@
5454
"date-fns": "^2.14.0",
5555
"date-fns-tz": "^2.0.1",
5656
"dayjs": "^1.11.13",
57-
"diff": "^5.0.0",
57+
"diff": "^8.0.3",
5858
"dompurify": "^3.2.5",
5959
"elliptic": "^6.6.1",
6060
"font-awesome": "^4.7.0",
@@ -65,7 +65,7 @@
6565
"html2canvas": "^1.4.1",
6666
"jest": "^30.2.0",
6767
"jquery": "^3.7.1",
68-
"jspdf": "^3.0.3",
68+
"jspdf": "^4.0.0",
6969
"jwt-decode": "^2.2.0",
7070
"leaflet": "^1.9.4",
7171
"leaflet.heat": "^0.2.0",
@@ -206,4 +206,4 @@
206206
],
207207
"**/*.{css,scss,sass}": "stylelint"
208208
}
209-
}
209+
}

public/index.css

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,33 @@ body.bm-dashboard-dark .page-item.active .page-link {
325325
}
326326

327327
/* Fix the position of the header at the top */
328-
.top {
329-
position: fixed;
330-
right: 10px;
331-
bottom: 10px;
332-
}
328+
.back-to-top {
329+
position: fixed;
330+
bottom: 24px;
331+
right: 24px;
332+
333+
width: 48px;
334+
height: 48px;
335+
336+
display: flex;
337+
align-items: center;
338+
justify-content: center;
339+
340+
background-color: #2A1B3D;
341+
color: #ffffff;
342+
343+
border-radius: 50%;
344+
font-size: 22px;
345+
text-decoration: none;
346+
347+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
348+
z-index: 1000;
349+
}
350+
351+
.back-to-top:hover {
352+
transform: translateY(-4px);
353+
opacity: 0.9;
354+
}
333355

334356
/* Allow the page content to scroll horizontally */
335357
.container-fluid {
@@ -339,4 +361,9 @@ body.bm-dashboard-dark .page-item.active .page-link {
339361
/* Hide the horizontal scrollbar */
340362
.container-fluid::-webkit-scrollbar {
341363
display: none;
342-
}
364+
}
365+
366+
.tab-content {
367+
background-color: transparent;
368+
border: none;
369+
}

src/actions/authActions.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import jwtDecode from 'jwt-decode';
22
import axios from 'axios';
33
import httpService from '../services/httpService';
44
import config from '../config.json';
5-
import { ENDPOINTS } from '~/utils/URL';
5+
import { ENDPOINTS } from '../utils/URL';
66
import { GET_ERRORS } from '../constants/errors';
77
import {
88
SET_CURRENT_USER,

src/actions/bmdashboard/projectActions.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,11 @@ export const fetchBMProjects = () => {
3030
});
3131
};
3232
};
33+
34+
export const getProjectGlobalDistribution = async (payload) => {
35+
const url = ENDPOINTS.PROJECT_GLOBAL_DISTRIBUTION
36+
37+
const res = await axios.get(url, {params: payload});
38+
39+
return res.data
40+
};

src/actions/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ export function getProjectById(projectId) {
142142
};
143143
}
144144

145+
145146
export function getProjectsByUser(userId) {
146147
const request = httpService.get(`${APIEndpoint}/projects/user/${userId}`);
147148

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
2+
import { ENDPOINTS } from '~/utils/URL';
3+
import axios from 'axios';
4+
import { normalizeFilter } from "~/utils/weeklySummariesFilterHelper";
5+
6+
export const weeklySummariesFiltersApi = createApi({
7+
reducerPath: "weeklySummariesFiltersApi",
8+
baseQuery: fetchBaseQuery({
9+
prepareHeaders: (headers) => {
10+
const token = axios.defaults.headers.common.Authorization;
11+
if (token) headers.set("Authorization", token);
12+
return headers;
13+
},
14+
}),
15+
tagTypes: ["WeeklySummariesFilters"], // <-- Add tag type
16+
endpoints: (builder) => ({
17+
18+
// ---------------------------------------
19+
// GET Filter List
20+
// ---------------------------------------
21+
getWeeklySummariesFilters: builder.query({
22+
query: () => ENDPOINTS.WEEKLY_SUMMARIES_FILTERS,
23+
transformResponse: (response) => {
24+
const filterList = response;
25+
const updatedFilterChoices = [];
26+
27+
filterList.forEach(filter => {
28+
updatedFilterChoices.push(normalizeFilter(filter));
29+
});
30+
31+
return updatedFilterChoices;
32+
},
33+
providesTags: ["WeeklySummariesFilters"], // <-- Cache tag
34+
}),
35+
36+
// ---------------------------------------
37+
// CREATE New Filter
38+
// ---------------------------------------
39+
createWeeklySummariesFilter: builder.mutation({
40+
query: ({data}) => ({
41+
url: ENDPOINTS.WEEKLY_SUMMARIES_FILTERS,
42+
method: "POST",
43+
body: data,
44+
}),
45+
invalidatesTags: ["WeeklySummariesFilters"], // <-- Refresh cache
46+
}),
47+
48+
// ---------------------------------------
49+
// UPDATE Existing Filter
50+
// ---------------------------------------
51+
updateWeeklySummariesFilter: builder.mutation({
52+
query: ({ id, data }) => ({
53+
url: ENDPOINTS.WEEKLY_SUMMARIES_FILTER_BY_ID(id),
54+
method: "PATCH",
55+
body: data,
56+
}),
57+
invalidatesTags: ["WeeklySummariesFilters"], // <-- Refresh cache
58+
}),
59+
60+
// ---------------------------------------
61+
// REPLACE Existing Filter
62+
// ---------------------------------------
63+
replaceWeeklySummariesFilter: builder.mutation({
64+
query: ({ id, data }) => ({
65+
url: ENDPOINTS.WEEKLY_SUMMARIES_FILTER_BY_ID(id),
66+
method: "PUT",
67+
body: data,
68+
}),
69+
invalidatesTags: ["WeeklySummariesFilters"], // <-- Refresh cache
70+
}),
71+
72+
// ---------------------------------------
73+
// DELETE Existing Filter
74+
// ---------------------------------------
75+
deleteWeeklySummariesFilter: builder.mutation({
76+
query: ({ id }) => ({
77+
url: ENDPOINTS.WEEKLY_SUMMARIES_FILTER_BY_ID(id),
78+
method: "DELETE",
79+
}),
80+
invalidatesTags: ["WeeklySummariesFilters"], // <-- Refresh cache
81+
}),
82+
83+
// ---------------------------------------
84+
// UPDATE Existing Filter with Replaced Team codes
85+
// ---------------------------------------
86+
updateFiltersWithReplacedTeamCodes: builder.mutation({
87+
query: ({oldTeamCodes, newTeamCode}) => ({
88+
url: ENDPOINTS.WEEKLY_SUMMARIES_FILTER_REPLACE_CODES,
89+
method: "POST",
90+
body: { oldTeamCodes, newTeamCode },
91+
}),
92+
invalidatesTags: ["WeeklySummariesFilters"], // <-- Refresh cache
93+
}),
94+
95+
// ---------------------------------------
96+
// UPDATE Existing Filter with Individual Codes changes
97+
// ---------------------------------------
98+
updateFiltersWithIndividualCodesChange: builder.mutation({
99+
query: ({oldTeamCode, newTeamCode, userId}) => ({
100+
url: ENDPOINTS.WEEKLY_SUMMARIES_FILTER_REPLACE_INDIVIDUAL_CODES,
101+
method: "POST",
102+
body: { oldTeamCode, newTeamCode, userId },
103+
}),
104+
invalidatesTags: ["WeeklySummariesFilters"], // <-- Refresh cache
105+
}),
106+
107+
}),
108+
});
109+
110+
export const {
111+
useGetWeeklySummariesFiltersQuery,
112+
useCreateWeeklySummariesFilterMutation,
113+
useUpdateWeeklySummariesFilterMutation,
114+
useReplaceWeeklySummariesFilterMutation,
115+
useDeleteWeeklySummariesFilterMutation,
116+
useUpdateFiltersWithReplacedTeamCodesMutation,
117+
useUpdateFiltersWithIndividualCodesChangeMutation,
118+
} = weeklySummariesFiltersApi;

src/components/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ function UpdateDocumentTitle() {
107107
{ pattern: /^\/Logout$/, title: 'Logout' },
108108
{ pattern: /^\/forcePasswordUpdate\/[^/]+$/, title: 'Force Password Update' },
109109
{ pattern: /^\/$/, title: `Dashboard - ${fullName}` },
110+
{ pattern: /^\/kitchenandinventory\/login$/, title: 'Kitchen and Inventory Login' },
111+
{ pattern: /^\/kitchenandinventory$/, title: 'Kitchen and Inventory Dashboard' },
110112
{ pattern: /.*/, title: 'HGN APP' }, // Default case
111113
{
112114
pattern: /^\/communityportal\/activity\/activityid\/feedback$/,

src/components/AutoUpdate/AutoUpdate.jsx

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,48 +17,63 @@ function AutoUpdate() {
1717
headers: noCacheHeaders,
1818
};
1919

20-
// Create the hash request with proper URL handling for test environment
21-
const hashRequest = (() => {
22-
try {
23-
return new Request('/hash.txt');
24-
} catch (error) {
25-
// In test environment, use a fallback URL
26-
return new Request('http://localhost/hash.txt');
20+
const resolveHashUrl = () => {
21+
const isTestEnv =
22+
(typeof import.meta !== 'undefined' && import.meta.env?.MODE === 'test') ||
23+
(typeof process !== 'undefined' && process.env?.NODE_ENV === 'test');
24+
25+
if (isTestEnv || typeof window === 'undefined' || !window.location) {
26+
return null;
2727
}
28-
})();
28+
return new URL('/hash.txt', window.location.origin).toString();
29+
};
2930

3031
useEffect(() => {
31-
fetch(hashRequest, requestParams)
32-
.then(response => {
33-
response.text().then(text => {
32+
const hashUrl = resolveHashUrl();
33+
if (!hashUrl || typeof fetch === 'undefined') {
34+
return undefined;
35+
}
36+
37+
let isMounted = true;
38+
fetch(hashUrl, requestParams)
39+
.then(response => response.text())
40+
.then(text => {
41+
if (isMounted) {
3442
setHash(text);
35-
});
43+
}
3644
})
3745
.catch(err => {
3846
console.error(err); // eslint-disable-line no-console
3947
});
48+
49+
return () => {
50+
isMounted = false;
51+
};
4052
}, []);
4153

4254
useEffect(() => {
43-
if (hash !== undefined) {
44-
const interval = setInterval(() => {
45-
fetch(hashRequest, requestParams)
46-
.then(response => {
47-
response.text().then(text => {
48-
if (text !== hash) {
49-
setUpdated(true);
50-
}
51-
});
52-
})
53-
.catch(err => {
54-
console.error(err); // eslint-disable-line no-console
55-
});
56-
}, 5 * MINUTE);
57-
return () => clearInterval(interval);
55+
if (hash === undefined) {
56+
return undefined;
57+
}
58+
59+
const hashUrl = resolveHashUrl();
60+
if (!hashUrl || typeof fetch === 'undefined') {
61+
return undefined;
5862
}
5963

60-
// No cleanup needed if the hash is undefined.
61-
return () => {};
64+
const interval = setInterval(() => {
65+
fetch(hashUrl, requestParams)
66+
.then(response => response.text())
67+
.then(text => {
68+
if (text !== hash) {
69+
setUpdated(true);
70+
}
71+
})
72+
.catch(err => {
73+
console.error(err); // eslint-disable-line no-console
74+
});
75+
}, 5 * MINUTE);
76+
return () => clearInterval(interval);
6277
}, [hash]);
6378

6479
if (!updated) return null;

0 commit comments

Comments
 (0)