Skip to content

Commit 0bed439

Browse files
committed
feat: Add cohort fetching in LeaguesPage and update enrollment logic to prioritize available cohorts
1 parent 8fdafef commit 0bed439

5 files changed

Lines changed: 37 additions & 19 deletions

File tree

src/components/features/dashboard/LeagueDetailPage.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ const LeagueDetailPage = ({ league, onBack }) => {
423423
};
424424

425425
loadResources();
426-
}, [leagueProgress]);
426+
// eslint-disable-next-line react-hooks/exhaustive-deps
427+
}, [leagueProgress]); // Intentionally excluding sectionResources to prevent infinite loop
427428

428429
// Set error from SWR
429430
useEffect(() => {

src/context/AuthContext.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ export const AuthProvider = ({ children }) => {
6464
clearInterval(tokenRefreshInterval);
6565
}
6666
};
67-
}, []);
67+
// eslint-disable-next-line react-hooks/exhaustive-deps
68+
}, []); // Intentionally empty - only run on mount, startTokenRefresh/tokenRefreshInterval would cause infinite loop
6869

6970
// Start automatic token refresh (refresh every 12 minutes, before 15-min expiry)
7071
const startTokenRefresh = () => {

src/hooks/useDashboard.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,14 @@ export const useUserProfile = () => {
4444
// Dedupe requests within 5 seconds
4545
dedupingInterval: 5000,
4646

47-
// Retry on error
48-
shouldRetryOnError: true,
47+
// Retry on error (don't retry if unauthorized)
48+
shouldRetryOnError: (error) => {
49+
return !error.message?.includes('401');
50+
},
4951
errorRetryCount: 2,
5052

5153
// Use cache when available
5254
revalidateIfStale: true,
53-
54-
// Don't revalidate if no token (user not logged in)
55-
shouldRetryOnError: (error) => {
56-
// Don't retry if unauthorized
57-
return !error.message?.includes('401');
58-
},
5955
}
6056
);
6157

src/pages/dashboard/LeaguesPage.jsx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,37 @@ import {
1414
} from 'lucide-react';
1515
import OptimizedDashboardService from '../../utils/api/optimizedDashboardService';
1616
import ProgressService from '../../utils/api/progressService';
17+
import DataService from '../../utils/api/dataService';
1718
import { PageHead } from "../../components/common";
1819
import { MotionDiv, MotionSection } from '../../components/common/MotionWrapper';
1920
import { useDashboard } from '../../hooks/useDashboard';
2021

2122
const LeaguesPage = () => {
2223
const navigate = useNavigate();
24+
const [cohorts, setCohorts] = useState([]);
2325

2426
// SWR: Automatic caching, revalidation, and state management
2527
const {
2628
dashboardData,
2729
leagues,
2830
basicLeagueStats: leagueStatistics,
2931
isLoading: loading,
30-
error: swrError,
31-
mutate: refreshDashboard
32+
error: swrError
3233
} = useDashboard();
3334

35+
// Fetch cohorts for enrollment
36+
useEffect(() => {
37+
const fetchCohorts = async () => {
38+
try {
39+
const data = await DataService.getCohorts();
40+
setCohorts(data.cohorts || []);
41+
} catch (err) {
42+
console.error('Failed to fetch cohorts:', err);
43+
}
44+
};
45+
fetchCohorts();
46+
}, []);
47+
3448
// Format error message
3549
const error = swrError ? `Failed to load leagues. Please try again later. (${swrError.message})` : null;
3650

@@ -49,14 +63,19 @@ const LeaguesPage = () => {
4963
return;
5064
}
5165

52-
// Get cohort from user's existing enrollments or use first available
53-
const cohortId = dashboardData?.enrollments?.[0]?.cohort?.id || 'default';
66+
// Get cohort: prioritize user's existing enrollment cohort, else use first available cohort
67+
const cohortId = dashboardData?.enrollments?.[0]?.cohort?.id || cohorts[0]?.id;
68+
69+
if (!cohortId) {
70+
alert('No cohort available for enrollment. Please contact support.');
71+
return;
72+
}
5473

5574
await ProgressService.enrollUser(cohortId, leagueId);
5675
alert('Enrollment successful! Welcome to your learning journey!');
5776

58-
// SWR: Trigger revalidation to refresh data
59-
await refreshDashboard();
77+
// Reload the page to refresh all data for newly enrolled user
78+
window.location.reload();
6079
} catch (err) {
6180
console.error('Enrollment error:', err);
6281
alert(`Enrollment failed: ${err.message}. Please try again.`);
@@ -167,7 +186,7 @@ const LeaguesPage = () => {
167186
const stats = enrollment?.progress || leagueStatistics[league.id] || {};
168187
const weeksCount = stats.weeksCount || league.weeksCount || league._count?.weeks || 0;
169188
const sectionsCount = stats.totalSections || league.sectionsCount || league._count?.sections || 0;
170-
const resourcesCount = stats.totalResources || league.totalResources || league._count?.resources || 0;
189+
const resourcesCount = stats.totalResources || league.resourcesCount || league._count?.resources || 0;
171190

172191
return (
173192
<MotionDiv

src/utils/api/progressService.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ class ProgressService {
5858
*/
5959
static async enrollUser(cohortId, leagueId, userId = null) {
6060
try {
61-
// First, fetch league information to check if enrollment is disabled
62-
const leagueResponse = await fetch(`${API_BASE_URL}/leagues/${leagueId}`, {
61+
// First, fetch league information from leagues API (not progress API)
62+
// to check if enrollment is disabled
63+
const leagueResponse = await fetch(`${BASE_URL}/api/leagues/${leagueId}`, {
6364
headers: getAuthHeaders()
6465
});
6566

0 commit comments

Comments
 (0)