Skip to content

Commit 5fe6599

Browse files
committed
feat: resolve merge conflicts
2 parents 1b86612 + 1acc1b1 commit 5fe6599

44 files changed

Lines changed: 4892 additions & 443 deletions

Some content is hidden

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

src/actions/authActions.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,40 @@ export const getHeaderData = userId => {
115115
};
116116
};
117117

118-
export const logoutUser = () => dispatch => {
118+
export const logoutUser = (isCrossTabLogout = false) => dispatch => {
119119
// Clear any active force-logout timer before logging out
120120
dispatch(stopForceLogout());
121+
122+
// Only signal other tabs if this is NOT a cross-tab logout
123+
// (to prevent infinite loops when responding to storage events)
124+
if (!isCrossTabLogout) {
125+
// Set a flag to signal other tabs to log out
126+
// This flag will trigger a storage event in other tabs
127+
localStorage.setItem('logoutFlag', 'true');
128+
129+
// Use BroadcastChannel API for more reliable cross-tab communication
130+
if (typeof BroadcastChannel !== 'undefined') {
131+
try {
132+
const channel = new BroadcastChannel('auth_sync');
133+
channel.postMessage({ type: 'logout', timestamp: Date.now() });
134+
// Close the channel after sending
135+
setTimeout(() => channel.close(), 100);
136+
} catch (error) {
137+
// eslint-disable-next-line no-console
138+
console.warn('BroadcastChannel not available:', error);
139+
}
140+
}
141+
142+
// Clear the logout flag after a short delay to allow other tabs to detect it
143+
// We use setTimeout to ensure the storage event fires first
144+
setTimeout(() => {
145+
localStorage.removeItem('logoutFlag');
146+
}, 500);
147+
}
148+
149+
// Remove the token
121150
localStorage.removeItem(tokenKey);
151+
122152
httpService.setjwt(false);
123153
dispatch(setCurrentUser(null));
124154
};
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import axios from 'axios';
2+
import {
3+
FETCH_LESSON_PLANS_REQUEST,
4+
FETCH_LESSON_PLANS_SUCCESS,
5+
FETCH_LESSON_PLANS_FAILURE,
6+
FETCH_LESSON_PLAN_DETAIL_REQUEST,
7+
FETCH_LESSON_PLAN_DETAIL_SUCCESS,
8+
FETCH_LESSON_PLAN_DETAIL_FAILURE,
9+
SAVE_LESSON_PLAN_REQUEST,
10+
SAVE_LESSON_PLAN_SUCCESS,
11+
SAVE_LESSON_PLAN_FAILURE,
12+
REMOVE_LESSON_PLAN_REQUEST,
13+
REMOVE_LESSON_PLAN_SUCCESS,
14+
REMOVE_LESSON_PLAN_FAILURE,
15+
FETCH_SAVED_LESSON_PLANS_REQUEST,
16+
FETCH_SAVED_LESSON_PLANS_SUCCESS,
17+
FETCH_SAVED_LESSON_PLANS_FAILURE,
18+
CHECK_IF_SAVED_REQUEST,
19+
CHECK_IF_SAVED_SUCCESS,
20+
CHECK_IF_SAVED_FAILURE,
21+
SET_FILTERS,
22+
CLEAR_FILTERS,
23+
SET_SEARCH_QUERY,
24+
SET_VIEW_MODE,
25+
} from '~/constants/educationPortal/browselessonPlanConstant';
26+
import { ENDPOINTS } from '~/utils/URL';
27+
28+
const getAuthHeaders = () => {
29+
const token = localStorage.getItem('token');
30+
if (!token) {
31+
}
32+
return {
33+
'Content-Type': 'application/json',
34+
Accept: 'application/json',
35+
...(token ? { Authorization: token } : {}),
36+
};
37+
};
38+
39+
export const fetchLessonPlans = (params = {}) => async dispatch => {
40+
dispatch({ type: FETCH_LESSON_PLANS_REQUEST });
41+
try {
42+
const queryString = new URLSearchParams(params).toString();
43+
const url = `${ENDPOINTS.LESSON_PLANS}${queryString ? `?${queryString}` : ''}`;
44+
45+
const res = await axios.get(url, {
46+
headers: getAuthHeaders(),
47+
});
48+
49+
dispatch({
50+
type: FETCH_LESSON_PLANS_SUCCESS,
51+
payload: res.data.data,
52+
meta: res.data.meta,
53+
});
54+
} catch (error) {
55+
const errorMessage = error.response?.status === 401
56+
? 'Please log in to view lesson plans'
57+
: error.response?.data?.error || error.message;
58+
59+
dispatch({
60+
type: FETCH_LESSON_PLANS_FAILURE,
61+
error: errorMessage,
62+
});
63+
}
64+
};
65+
66+
export const fetchLessonPlanDetail = id => async dispatch => {
67+
dispatch({ type: FETCH_LESSON_PLAN_DETAIL_REQUEST });
68+
try {
69+
const res = await axios.get(`${ENDPOINTS.LESSON_PLANS}/${id}`, {
70+
headers: getAuthHeaders(),
71+
});
72+
dispatch({ type: FETCH_LESSON_PLAN_DETAIL_SUCCESS, payload: res.data.data });
73+
} catch (error) {
74+
const errorMessage = error.response?.status === 401
75+
? 'Please log in to view lesson plan details'
76+
: error.response?.data?.error || error.message;
77+
78+
dispatch({
79+
type: FETCH_LESSON_PLAN_DETAIL_FAILURE,
80+
error: errorMessage,
81+
});
82+
}
83+
};
84+
85+
export const saveLessonPlan = (studentId, lessonPlanId) => async dispatch => {
86+
dispatch({ type: SAVE_LESSON_PLAN_REQUEST });
87+
try {
88+
const res = await axios.post(
89+
ENDPOINTS.SAVE_INTEREST,
90+
{ studentId, lessonPlanId },
91+
{
92+
headers: getAuthHeaders(),
93+
}
94+
);
95+
dispatch({
96+
type: SAVE_LESSON_PLAN_SUCCESS,
97+
payload: res.data.data,
98+
lessonPlanId,
99+
});
100+
} catch (error) {
101+
const errorMessage = error.response?.status === 401
102+
? 'Please log in to save lesson plans'
103+
: error.response?.data?.error || error.message;
104+
105+
dispatch({
106+
type: SAVE_LESSON_PLAN_FAILURE,
107+
error: errorMessage,
108+
});
109+
}
110+
};
111+
112+
export const removeLessonPlan = (studentId, lessonPlanId) => async dispatch => {
113+
dispatch({ type: REMOVE_LESSON_PLAN_REQUEST });
114+
try {
115+
const res = await axios.delete(
116+
`${ENDPOINTS.REMOVE_INTEREST}/${lessonPlanId}?studentId=${studentId}`,
117+
{
118+
headers: getAuthHeaders(),
119+
}
120+
);
121+
dispatch({
122+
type: REMOVE_LESSON_PLAN_SUCCESS,
123+
payload: res.data.data,
124+
lessonPlanId,
125+
});
126+
} catch (error) {
127+
const errorMessage = error.response?.status === 401
128+
? 'Please log in to remove saved lesson plans'
129+
: error.response?.data?.error || error.message;
130+
131+
dispatch({
132+
type: REMOVE_LESSON_PLAN_FAILURE,
133+
error: errorMessage,
134+
});
135+
}
136+
};
137+
138+
export const fetchSavedLessonPlans = studentId => async dispatch => {
139+
dispatch({ type: FETCH_SAVED_LESSON_PLANS_REQUEST });
140+
try {
141+
const res = await axios.get(
142+
`${ENDPOINTS.GET_SAVED}?studentId=${encodeURIComponent(studentId)}`,
143+
{
144+
headers: getAuthHeaders(),
145+
}
146+
);
147+
dispatch({
148+
type: FETCH_SAVED_LESSON_PLANS_SUCCESS,
149+
payload: res.data.data,
150+
meta: res.data.meta,
151+
});
152+
} catch (error) {
153+
const errorMessage = error.response?.status === 401
154+
? 'Please log in to view saved lesson plans'
155+
: error.response?.data?.error || error.message;
156+
157+
dispatch({
158+
type: FETCH_SAVED_LESSON_PLANS_FAILURE,
159+
error: errorMessage,
160+
});
161+
}
162+
};
163+
164+
export const checkIfSaved = (studentId, lessonPlanId) => async dispatch => {
165+
dispatch({ type: CHECK_IF_SAVED_REQUEST });
166+
try {
167+
const res = await axios.get(
168+
`${ENDPOINTS.CHECK_IF_SAVED}?studentId=${studentId}&lessonPlanId=${lessonPlanId}`,
169+
{
170+
headers: getAuthHeaders(),
171+
}
172+
);
173+
dispatch({
174+
type: CHECK_IF_SAVED_SUCCESS,
175+
payload: res.data.isSaved,
176+
lessonPlanId,
177+
});
178+
} catch (error) {
179+
dispatch({
180+
type: CHECK_IF_SAVED_FAILURE,
181+
error: error.response?.data?.error || error.message,
182+
});
183+
}
184+
};
185+
186+
export const setFilters = filters => ({
187+
type: SET_FILTERS,
188+
payload: filters,
189+
});
190+
191+
export const clearFilters = () => ({
192+
type: CLEAR_FILTERS,
193+
});
194+
195+
export const setSearchQuery = query => ({
196+
type: SET_SEARCH_QUERY,
197+
payload: query,
198+
});
199+
200+
export const setViewMode = mode => ({
201+
type: SET_VIEW_MODE,
202+
payload: mode,
203+
});

0 commit comments

Comments
 (0)