Skip to content

Commit 9bfc8dc

Browse files
Merge pull request #3845 from OneCommunityGlobal/shashank-madan-page-refresh-frontend
Shashank Madan fix needing to refresh many pages when first visiting them
2 parents f4a04df + 90fd880 commit 9bfc8dc

9 files changed

Lines changed: 2022 additions & 555 deletions

File tree

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
"redux-concatenate-reducers": "^1.0.0",
107107
"redux-persist": "^5.10.0",
108108
"redux-thunk": "^2.4.2",
109+
"reselect": "^5.1.1",
109110
"semver": "^7.7.2",
110111
"stream-browserify": "^3.0.0",
111112
"tinymce": "^7.2.0",

src/components/Dashboard/Dashboard.jsx

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { useState, useEffect, useCallback, useMemo } from 'react';
22
import { Row, Col, Container } from 'reactstrap';
3+
import { useParams } from 'react-router-dom';
34
import { connect, useSelector, useDispatch } from 'react-redux';
45
import { cantUpdateDevAdminDetails } from '~/utils/permissions';
56
import {
@@ -10,7 +11,6 @@ import {
1011
import { updateSummaryBarData } from '~/actions/dashboardActions';
1112
import Leaderboard from '../LeaderBoard';
1213
import WeeklySummary from '../WeeklySummary/WeeklySummary';
13-
import Badge from '../Badge';
1414
import Timelog from '../Timelog/Timelog';
1515
import SummaryBar from '../SummaryBar/SummaryBar';
1616
import styles from './Dashboard.module.css';
@@ -19,22 +19,37 @@ import TimeOffRequestDetailModal from './TimeOffRequestDetailModal';
1919
import FeedbackModal from '../FeedbackModal/FeedbackModal';
2020
import { toast } from 'react-toastify';
2121

22-
export function Dashboard(props) {
22+
function Dashboard() {
23+
const dispatch = useDispatch();
24+
25+
// Use hooks instead of connect to access Redux state
26+
const authUser = useSelector(state => state.auth.user);
27+
const displayUserProfile = useSelector(state => state.userProfile);
28+
const darkMode = useSelector(state => state.theme.darkMode);
29+
30+
// Get userId from URL params
31+
const { userId: urlUserId } = useParams();
32+
33+
// Component state
2334
const [popup, setPopup] = useState(false);
2435
const [filteredUserTeamIds, setFilteredUserTeamIds] = useState([]);
2536
const [summaryBarData, setSummaryBarData] = useState(null);
26-
const { match, authUser } = props;
27-
const checkSessionStorage = () => JSON.parse(sessionStorage.getItem('viewingUser')) ?? false;
28-
const [viewingUser, setViewingUser] = useState(checkSessionStorage);
37+
38+
// Memoize this function to avoid recreating it on every render
39+
const checkSessionStorage = useCallback(() => {
40+
return JSON.parse(sessionStorage.getItem('viewingUser')) ?? false;
41+
}, []);
42+
43+
// State for viewing user
44+
const [viewingUser, setViewingUser] = useState(checkSessionStorage());
2945
const [displayUserId, setDisplayUserId] = useState(
30-
match.params.userId || viewingUser?.userId || authUser.userid,
46+
urlUserId || viewingUser?.userId || authUser.userid,
3147
);
32-
const isNotAllowedToEdit = cantUpdateDevAdminDetails(viewingUser?.email, authUser.email);
33-
const darkMode = useSelector(state => state.theme.darkMode);
3448

35-
const dispatch = useDispatch();
49+
const isNotAllowedToEdit = cantUpdateDevAdminDetails(viewingUser?.email, authUser.email);
3650

37-
const toggle = () => {
51+
// Toggle popup with memoization to prevent recreation
52+
const toggle = useCallback(() => {
3853
if (isNotAllowedToEdit) {
3954
const warningMessage =
4055
viewingUser?.email === DEV_ADMIN_ACCOUNT_EMAIL_DEV_ENV_ONLY
@@ -52,28 +67,37 @@ export function Dashboard(props) {
5267
elem.scrollIntoView();
5368
}
5469
}, 150);
55-
};
70+
}, [isNotAllowedToEdit, popup, viewingUser?.email]);
5671

57-
const handleStorageEvent = () => {
72+
// Memoize storage event handler
73+
const handleStorageEvent = useCallback(() => {
5874
const sessionStorageData = checkSessionStorage();
5975
setViewingUser(sessionStorageData || false);
6076
setDisplayUserId(sessionStorageData ? sessionStorageData.userId : authUser.userid);
61-
};
77+
}, [authUser.userid, checkSessionStorage]);
78+
79+
// Memoize summary bar update handler
80+
const handleSummaryBarDataUpdate = useCallback(data => {
81+
setSummaryBarData(data);
82+
}, []);
83+
84+
// Update Redux store when summaryBarData changes
85+
useEffect(() => {
86+
if (summaryBarData) {
87+
dispatch(updateSummaryBarData({ summaryBarData }));
88+
}
89+
}, [dispatch, summaryBarData]);
6290

91+
// Add storage event listener
6392
useEffect(() => {
6493
window.addEventListener('storage', handleStorageEvent);
6594
return () => {
6695
window.removeEventListener('storage', handleStorageEvent);
6796
};
68-
}, []);
69-
70-
useEffect(() => {
71-
dispatch(updateSummaryBarData({ summaryBarData }));
72-
}, [summaryBarData]);
97+
}, [handleStorageEvent]);
7398

7499
return (
75100
<Container fluid className={darkMode ? 'bg-oxford-blue' : ''}>
76-
{/* <FeedbackModal /> */}
77101
<SummaryBar
78102
displayUserId={displayUserId}
79103
toggleSubmitForm={toggle}
@@ -129,7 +153,7 @@ export function Dashboard(props) {
129153
<div className="my-2" id="wsummary">
130154
<Timelog
131155
isDashboard
132-
passSummaryBarData={setSummaryBarData}
156+
passSummaryBarData={handleSummaryBarDataUpdate}
133157
isNotAllowedToEdit={isNotAllowedToEdit}
134158
filteredUserTeamIds={filteredUserTeamIds}
135159
/>
@@ -141,9 +165,4 @@ export function Dashboard(props) {
141165
);
142166
}
143167

144-
const mapStateToProps = state => ({
145-
authUser: state.auth.user,
146-
displayUserProfile: state.userProfile,
147-
});
148-
149-
export default connect(mapStateToProps)(Dashboard);
168+
export default Dashboard;

src/components/Dashboard/Dashboard.test.jsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { render, screen } from '@testing-library/react';
33
import { Provider } from 'react-redux';
44
import configureMockStore from 'redux-mock-store';
55
import { vi } from 'vitest';
6+
import { MemoryRouter } from 'react-router';
67

78
vi.mock('../LeaderBoard', () => ({ default: () => <div data-testid="leaderboard" /> }));
89
vi.mock('../WeeklySummary/WeeklySummary', () => ({
@@ -28,17 +29,19 @@ describe('Dashboard', () => {
2829
beforeEach(() => {
2930
// Provide auth.user and theme.darkMode for connect + useSelector
3031
store = mockStore({
31-
auth: { user: { userid: 'user1', role: 'Admin', email: 'admin@example.com' } },
32+
auth: { user: { userid: 'user2', role: 'Admin', email: 'admin@example.com' } },
3233
theme: { darkMode: false },
3334
});
3435
});
3536

3637
it('renders all child components with correct props', () => {
3738
render(
38-
<Provider store={store}>
39-
{/* pass match prop for routing params */}
40-
<ConnectedDashboard match={match} />
41-
</Provider>,
39+
<MemoryRouter initialEntries={['/user/user2']}>
40+
<Provider store={store}>
41+
{/* pass match prop for routing params */}
42+
<ConnectedDashboard match={match} />
43+
</Provider>
44+
</MemoryRouter>,
4245
);
4346

4447
// SummaryBar should receive displayUserId from match.params.userId

0 commit comments

Comments
 (0)