Skip to content

Commit f26ee5c

Browse files
authored
Merge branch 'development' into som-fix/broken-pr-analytic-link
2 parents 84350a4 + 9461992 commit f26ee5c

249 files changed

Lines changed: 29512 additions & 8245 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: 233 additions & 1489 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/index.css

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,13 +171,21 @@ body.bm-dashboard-dark .table {
171171
}
172172

173173
body.dark-mode .table th,
174-
body.dark-mode .table td,
174+
body.dark-mode .table td {
175+
color: #ffffff !important;
176+
border-color: #3a506b;
177+
}
178+
175179
body.bm-dashboard-dark .table th,
176180
body.bm-dashboard-dark .table td {
177181
color: #ffffff !important;
178182
border-color: #3a506b;
179183
}
180184

185+
body.bm-dashboard-dark .table th{
186+
background-color: #2e5061 !important;
187+
}
188+
181189
body.dark-mode .table-striped > tbody > tr:nth-of-type(odd),
182190
body.bm-dashboard-dark .table-striped > tbody > tr:nth-of-type(odd) {
183191
background-color: rgba(46, 80, 97, 0.5);
@@ -234,10 +242,6 @@ body.bm-dashboard-dark .nav-link {
234242
color: #ffffff !important;
235243
}
236244

237-
body.dark-mode .navbar,
238-
body.bm-dashboard-dark .navbar {
239-
background-color: #1b2a41 !important;
240-
}
241245

242246
body.dark-mode .navbar-brand,
243247
body.bm-dashboard-dark .navbar-brand {

src/actions/__tests__/userManagement.test.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const mockStore = configureMockStore(middlewares);
1414

1515
describe('User Management Actions', () => {
1616
let store;
17-
17+
1818
beforeEach(() => {
1919
store = mockStore({});
2020
vi.clearAllMocks();
@@ -46,7 +46,7 @@ describe('User Management Actions', () => {
4646

4747
it('should update user to active status', async () => {
4848
const reactivationDate = null;
49-
49+
5050
axios.patch.mockResolvedValueOnce({ data: {} });
5151

5252
await store.dispatch(actions.updateUserStatus(mockUser, UserStatus.Active, reactivationDate));
@@ -143,7 +143,7 @@ describe('User Management Actions', () => {
143143
);
144144
});
145145

146-
146+
147147
});
148148

149149
describe('updateUserFinalDayStatus', () => {
@@ -205,6 +205,7 @@ describe('User Management Actions', () => {
205205
{ id: 1, name: 'John Doe', email: 'john@example.com' },
206206
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
207207
];
208+
const mockSource = 'Report';
208209

209210
axios.get.mockResolvedValueOnce({ data: mockBasicInfo });
210211

@@ -213,20 +214,20 @@ describe('User Management Actions', () => {
213214
{ type: 'RECEIVE_USER_PROFILE_BASIC_INFO', payload: mockBasicInfo }
214215
];
215216

216-
await store.dispatch(actions.getUserProfileBasicInfo());
217+
await store.dispatch(actions.getUserProfileBasicInfo({source: mockSource}));
217218
expect(store.getActions()).toEqual(expectedActions);
218-
expect(axios.get).toHaveBeenCalledWith(ENDPOINTS.USER_PROFILE_BASIC_INFO);
219+
expect(axios.get).toHaveBeenCalledWith(ENDPOINTS.USER_PROFILE_BASIC_INFO(mockSource));
219220
});
220221

221222
it('should handle errors when fetching basic info', async () => {
222223
axios.get.mockRejectedValueOnce(new Error('Network error'));
223-
224+
const mockSource = '';
224225
const expectedActions = [
225226
{ type: 'FETCH_USER_PROFILE_BASIC_INFO' },
226227
{ type: 'FETCH_USER_PROFILE_BASIC_INFO_ERROR' }
227228
];
228229

229-
await store.dispatch(actions.getUserProfileBasicInfo());
230+
await store.dispatch(actions.getUserProfileBasicInfo({ source: mockSource }));
230231
expect(store.getActions()).toEqual(expectedActions);
231232
});
232233
});
@@ -276,4 +277,4 @@ describe('User Management Actions', () => {
276277
expect(store.getActions()).toContainEqual(expectedAction);
277278
});
278279
});
279-
});
280+
});

src/actions/allTeamsAction.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ export const getAllUserTeams = () => {
122122
.then(res => {
123123
dispatch(teamMembersFectchACtion(res.data));
124124
return res.data;
125-
// console.log("getAllUserTeams: res:", res.data)
126125
})
127126
.catch(() => {
128127
dispatch(teamMembersFectchACtion(undefined));

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+
};
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/browseLPConstant';
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+
});

src/actions/eventActions.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import axios from 'axios';
2+
import { ENDPOINTS } from '~/utils/URL';
3+
4+
/**
5+
* Fetch events with optional filtering
6+
* @param {Object} params - Query parameters
7+
* @param {string} params.type - Filter by event type
8+
* @param {string} params.location - Filter by location
9+
* @param {number} params.page - Page number
10+
* @param {number} params.limit - Items per page
11+
* @param {string} params.sortBy - Sort field
12+
* @returns {Promise} API response
13+
*/
14+
export async function getEvents(params = {}) {
15+
try {
16+
const { type = '', location = '', page = 1, limit = 9, sortBy = 'date' } = params;
17+
const queryParams = new URLSearchParams();
18+
if (type) queryParams.append('type', type);
19+
if (location) queryParams.append('location', location);
20+
queryParams.append('page', page);
21+
queryParams.append('limit', limit);
22+
queryParams.append('sortBy', sortBy);
23+
24+
const url = `${ENDPOINTS.EVENTS}?${queryParams.toString()}`;
25+
const response = await axios.get(url);
26+
return Promise.resolve(response);
27+
} catch (error) {
28+
return {
29+
message: error.response?.data?.error || error.message,
30+
errorCode: error.response?.status,
31+
status: error.response?.status || 500,
32+
};
33+
}
34+
}
35+
36+
/**
37+
* Fetch available event types
38+
* @returns {Promise} API response
39+
*/
40+
export async function getEventTypes() {
41+
try {
42+
const url = ENDPOINTS.EVENT_TYPES;
43+
const response = await axios.get(url);
44+
return Promise.resolve(response);
45+
} catch (error) {
46+
return {
47+
message: error.response?.data?.error || error.message,
48+
errorCode: error.response?.status,
49+
status: error.response?.status || 500,
50+
};
51+
}
52+
}
53+
54+
/**
55+
* Fetch available event locations
56+
* @returns {Promise} API response
57+
*/
58+
export async function getEventLocations() {
59+
try {
60+
const url = ENDPOINTS.EVENT_LOCATIONS;
61+
const response = await axios.get(url);
62+
return Promise.resolve(response);
63+
} catch (error) {
64+
return {
65+
message: error.response?.data?.error || error.message,
66+
errorCode: error.response?.status,
67+
status: error.response?.status || 500,
68+
};
69+
}
70+
}

0 commit comments

Comments
 (0)