Skip to content

Commit 39678b5

Browse files
authored
Merge pull request #55 from CS3219-AY2526Sem1/revert-52-fix/history/ui-for-profile-and-history
Revert "feat(frontend):add history-service to docker-compose and enhance RecentSessionsList "
2 parents 0464927 + b1d9514 commit 39678b5

File tree

22 files changed

+2441
-662
lines changed

22 files changed

+2441
-662
lines changed

docker-compose.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
services:
22
# --- DATABASES ---
33
# For local volume dockerized testing
4-
# Commented out - using MongoDB Atlas instead
54
# user-db-mongodb:
65
# image: mongo
76
# container_name: user-db-mongodb
@@ -78,7 +77,6 @@ services:
7877
- question-service
7978
- matching-service
8079
- collaboration-service
81-
- history-service
8280
networks:
8381
- app-network
8482

@@ -100,7 +98,7 @@ services:
10098
- /app/node_modules
10199
networks:
102100
- app-network
103-
# depends_on: # Commented out - using MongoDB Atlas instead of local container
101+
# depends_on: # Uncomment if local volume
104102
# - user-db-mongodb
105103
command: sh -c "npm run seed:admin || true && npm run dev" # for production change to npm start
106104

frontend/src/components/userMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ const UserMenu: React.FC = () => {
5353
</>
5454
) : (
5555
<>
56-
{/* <button className="icon-button">
56+
<button className="icon-button">
5757
<img src={NotificationIcon} alt="Notifications" className="notification-icon" />
58-
</button> */}
58+
</button>
5959

6060
{isVerified ? (
6161
<Link to="/profile/" className="icon-link">

frontend/src/features/progress/RecentSessionsList.tsx

Lines changed: 12 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect, useMemo } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import { useNavigate } from 'react-router-dom';
33
import { getAllAttemptSummaries } from '../../lib/api';
44
// --- FIX: Import both time formatters ---
@@ -22,66 +22,36 @@ interface SessionSummary {
2222
question_title: string;
2323
question_difficulty: "Easy" | "Medium" | "Hard";
2424
partner_id: string;
25-
partner_username?: string;
26-
is_solved_successfully: boolean | null;
25+
is_solved_successfully: boolean;
2726
has_penalty: boolean; // We need this to determine "Incomplete"
2827
started_at: string;
29-
time_taken_ms: number | null;
28+
time_taken_ms: number;
3029
}
3130

32-
interface RecentSessionsListProps {
33-
userId: string;
34-
limit?: number;
35-
summaries?: SessionSummary[];
36-
}
37-
38-
const RecentSessionsList: React.FC<RecentSessionsListProps> = ({ userId, limit, summaries: providedSummaries }) => {
31+
const RecentSessionsList: React.FC<{ userId: string, limit: number }> = ({ userId, limit }) => {
3932
const navigate = useNavigate();
4033
const [sessions, setSessions] = useState<SessionSummary[]>([]);
4134
const [loading, setLoading] = useState(true);
4235

43-
// Create a stable reference for providedSummaries to avoid dependency array issues
44-
const summariesKey = useMemo(() => {
45-
return providedSummaries ? JSON.stringify(providedSummaries.map(s => s.session_id)) : null;
46-
}, [providedSummaries]);
47-
4836
useEffect(() => {
49-
// If summaries are provided, use them directly
50-
if (providedSummaries && providedSummaries.length >= 0) {
51-
const sortedData = [...providedSummaries].sort((a:SessionSummary, b:SessionSummary) =>
52-
new Date(b.started_at).getTime() - new Date(a.started_at).getTime()
53-
);
54-
setSessions(limit ? sortedData.slice(0, limit) : sortedData);
55-
setLoading(false);
56-
return;
57-
}
58-
59-
// Otherwise, fetch from API
60-
if (!userId) {
61-
setLoading(false);
62-
setSessions([]);
63-
return;
64-
}
37+
if (!userId) return;
6538

6639
const fetchRecent = async () => {
6740
try {
6841
setLoading(true);
6942
const data = await getAllAttemptSummaries(userId);
7043
// Sort by date DESC (as getAllAttemptSummaries might not guarantee order)
71-
const sortedData = data ? data.sort((a:SessionSummary, b:SessionSummary) =>
72-
new Date(b.started_at).getTime() - new Date(a.started_at).getTime()
73-
) : [];
74-
setSessions(limit ? sortedData.slice(0, limit) : sortedData);
44+
const sortedData = data ? data.sort((a:SessionSummary, b:SessionSummary) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime()) : [];
45+
setSessions(sortedData.slice(0, limit));
7546
} catch (error) {
7647
console.error("Failed to fetch recent sessions:", error);
77-
setSessions([]);
7848
} finally {
7949
setLoading(false);
8050
}
8151
};
8252

8353
fetchRecent();
84-
}, [userId, limit, summariesKey]);
54+
}, [userId, limit]);
8555

8656
const handleSessionClick = (questionId: string) => {
8757
// Navigate to the detail page for that question
@@ -121,7 +91,7 @@ const RecentSessionsList: React.FC<RecentSessionsListProps> = ({ userId, limit,
12191
<div className="flex items-center gap-4 text-sm text-muted-foreground">
12292
<div className="flex items-center gap-1">
12393
<User className="h-3 w-3" />
124-
{session.partner_username || session.partner_id}
94+
{session.partner_id}
12595
</div>
12696
<div className="flex items-center gap-1">
12797
<Clock className="h-3 w-3" />
@@ -138,11 +108,11 @@ const RecentSessionsList: React.FC<RecentSessionsListProps> = ({ userId, limit,
138108

139109
{/* API provides booleans, we derive the status */}
140110
<Badge className={
141-
session.is_solved_successfully === true ? 'bg-green-500 text-white' : // "Passed" (green)
142-
session.has_penalty ? 'bg-orange-500 text-white' : // "Incomplete" (orange)
111+
session.is_solved_successfully ? 'bg-green-500 text-white' : // "Passed" (blue)
112+
session.has_penalty ? 'bg-orange-500 text-white' : // "Incomplete" (gray)
143113
'bg-red-500 text-white' // "Failed" (red)
144114
}>
145-
{session.is_solved_successfully === true ? "Passed" : (session.has_penalty ? "Incomplete" : "Failed")}
115+
{session.is_solved_successfully ? "Passed" : (session.has_penalty ? "Incomplete" : "Failed")}
146116
</Badge>
147117
</div>
148118
</Card>
Lines changed: 15 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,25 @@
11
import React from 'react';
2-
import { Card } from "@/components/ui/card";
3-
import {
4-
Trophy,
5-
Target,
6-
Clock,
7-
TrendingUp,
8-
} from "lucide-react";
9-
import { formatDuration } from '../../lib/timeFormatters';
10-
11-
interface Stat {
12-
label: string;
13-
value: string | number;
14-
icon: React.ComponentType<{ className?: string }>;
15-
color: string;
16-
}
2+
import StatBox from './statBox';
3+
import styles from './progressCard.module.css';
174

185
interface StatsGridProps {
19-
progress: {
20-
total_sessions_completed?: number;
21-
total_successes?: number;
22-
total_time_ms?: number;
23-
current_streak?: number;
24-
} | null;
6+
stats: {
7+
totalSessions: number;
8+
completed: number;
9+
successRate: number;
10+
dayStreak: number;
11+
};
2512
}
2613

27-
const StatsGrid: React.FC<StatsGridProps> = ({ progress }) => {
28-
const stats: Stat[] = [
29-
{
30-
label: "Sessions Completed",
31-
value: progress?.total_sessions_completed ?? 0,
32-
icon: Trophy,
33-
color: "text-yellow-500"
34-
},
35-
{
36-
label: "Problems Solved",
37-
value: progress?.total_successes ?? 0,
38-
icon: Target,
39-
color: "text-green-500"
40-
},
41-
{
42-
label: "Hours Practiced",
43-
value: formatDuration(progress?.total_time_ms),
44-
icon: Clock,
45-
color: "text-blue-500"
46-
},
47-
{
48-
label: "Current Streak",
49-
value: progress?.current_streak ?? 0,
50-
icon: TrendingUp,
51-
color: "text-purple-500"
52-
},
53-
];
54-
14+
const StatsGrid = ({ stats }: StatsGridProps) => {
5515
return (
56-
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6">
57-
{stats.map((stat) => (
58-
<Card key={stat.label} className="p-6 bg-card border-0 shadow-card hover:shadow-elegant transition-smooth">
59-
<div className="flex items-center justify-between">
60-
<div>
61-
<p className="text-3xl font-bold">{stat.value}</p>
62-
<p className="text-sm text-muted-foreground mt-1">{stat.label}</p>
63-
</div>
64-
<stat.icon className={`h-10 w-10 ${stat.color}`} />
65-
</div>
66-
</Card>
67-
))}
16+
<div className={styles.statsGrid}>
17+
<StatBox label="Total Sessions" value={stats.totalSessions} />
18+
<StatBox label="Completed" value={stats.completed} />
19+
<StatBox label="Success Rate" value={`${stats.successRate}%`} />
20+
<StatBox label="Day Streak" value={stats.dayStreak} />
6821
</div>
6922
);
7023
};
7124

72-
export default StatsGrid;
25+
export default StatsGrid;

frontend/src/lib/api.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const getTopics = async () => {
5858
* (For the stat bars on Home and Profile)
5959
*/
6060
export const getHistoryProgress = async (userId: string) => {
61-
const response = await historyApi.get(`/api/history/progress/${encodeURIComponent(userId)}`);
61+
const response = await historyApi.get(`/api/history/progress/${userId}`);
6262
return response.data;
6363
};
6464

@@ -67,7 +67,7 @@ export const getHistoryProgress = async (userId: string) => {
6767
* (For the main lists on Home and History Dashboard)
6868
*/
6969
export const getAllAttemptSummaries = async (userId: string) => {
70-
const response = await historyApi.get(`/api/history/all-summaries/${encodeURIComponent(userId)}`);
70+
const response = await historyApi.get(`/api/history/all-summaries/${userId}`);
7171
return response.data;
7272
};
7373

@@ -76,23 +76,23 @@ export const getAllAttemptSummaries = async (userId: string) => {
7676
* (For the "Question Detail" page - Pic 3)
7777
*/
7878
export const getQuestionAttempts = async (userId: string, questionId: string) => {
79-
const response = await historyApi.get(`/api/history/question-attempts/${encodeURIComponent(userId)}/${encodeURIComponent(questionId)}`);
79+
const response = await historyApi.get(`/api/history/question-attempts/${userId}/${questionId}`);
8080
return response.data;
8181
};
8282

8383
/**
8484
* Fetches the list of "active" question IDs for the reset page.
8585
*/
8686
export const getActiveAttempts = async (userId: string) => {
87-
const response = await historyApi.get(`/api/history/active-attempts/${encodeURIComponent(userId)}`);
87+
const response = await historyApi.get(`/api/history/active-attempts/${userId}`);
8888
return response.data;
8989
};
9090

9191
/**
9292
* Resets a list of questions, making them available for matching again.
9393
*/
9494
export const resetQuestions = async (userId: string, questionIds: string[]) => {
95-
const response = await historyApi.post(`/api/history/reset-questions/${encodeURIComponent(userId)}`, { questionIds });
95+
const response = await historyApi.post(`/api/history/reset-questions/${userId}`, { questionIds });
9696
return response.data;
9797
};
9898
export const cancelMatch = async data => matchingApi.delete(`/api/matches/${data.userId}`, data);

0 commit comments

Comments
 (0)