Skip to content

Commit 3787516

Browse files
committed
Make ReviewBox collapsible
1 parent 3d75e41 commit 3787516

File tree

3 files changed

+71
-48
lines changed

3 files changed

+71
-48
lines changed

frontend/src/components/ReviewBox.jsx

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { useState, useEffect, useRef } from 'react';
22
import {
33
Card,
44
CardContent,
@@ -15,6 +15,8 @@ import {
1515
Button,
1616
} from '@mui/material';
1717
import DeleteIcon from '@mui/icons-material/Delete';
18+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
19+
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
1820

1921
import theme from '../theme';
2022
import ReviewInput from './ReviewInput';
@@ -73,7 +75,7 @@ const Review = ({ review, endpoint, onUpdate }) => {
7375
color="text.secondary"
7476
sx={{ fontStyle: 'italic' }}
7577
>
76-
Your review (this is only visible to you)
78+
Your review (this line is only visible to you)
7779
</Typography>
7880
<IconButton onClick={handleDialogOpen} color="error" size="small">
7981
<DeleteIcon />
@@ -115,22 +117,40 @@ const Review = ({ review, endpoint, onUpdate }) => {
115117
);
116118
};
117119

118-
const ReviewBox = ({ children, endpoint }) => {
120+
const ReviewBox = ({ children, title, endpoint, initExpanded }) => {
119121
const [reviewsList, setReviewsList] = useState(null);
122+
const [isExpanded, setIsExpanded] = useState(initExpanded);
123+
const cache = useRef({}); // Cache for reviews data
124+
120125
const fetchReviews = async () => {
121126
setReviewsList(null);
122127
try {
123128
const response = await api.get(endpoint);
129+
cache.current[endpoint] = response.data;
124130
setReviewsList(response.data);
125131
} catch (error) {
126132
// TODO: report error in frontend
127133
console.error('Error during search:', error);
128134
}
129135
};
130136

137+
const toggleExpand = () => {
138+
setIsExpanded(!isExpanded);
139+
};
140+
131141
useEffect(() => {
132-
fetchReviews();
133-
}, [endpoint]);
142+
if (isExpanded) {
143+
if (cache.current[endpoint]) {
144+
setReviewsList(cache.current[endpoint]);
145+
}
146+
else {
147+
fetchReviews();
148+
}
149+
}
150+
else {
151+
setReviewsList(null);
152+
}
153+
}, [endpoint, isExpanded]);
134154

135155
return (
136156
<Card
@@ -143,35 +163,47 @@ const ReviewBox = ({ children, endpoint }) => {
143163
}}
144164
>
145165
<CardContent>
146-
{children}
147-
<Typography variant="h6" gutterBottom color="secondary" sx={{ mt: 1 }}>
148-
Reviews
149-
</Typography>
150-
{reviewsList === null ? (
151-
<Box
152-
sx={{
153-
display: 'flex',
154-
alignItems: 'center',
155-
justifyContent: 'center',
156-
height: '150px',
157-
}}
158-
>
159-
<CircularProgress />
160-
</Box>
161-
) : !reviewsList || reviewsList.length === 0 ? (
162-
<Typography variant="body1" color="text.secondary">
163-
No reviews available.
166+
<Box display="flex" justifyContent="space-between" alignItems="center">
167+
<Typography variant="h5" color="primary">
168+
{title}
164169
</Typography>
165-
) : (
166-
reviewsList.map((review, index) => (
167-
<Review
168-
review={review}
169-
endpoint={endpoint}
170-
onUpdate={fetchReviews}
171-
/>
172-
))
170+
<IconButton onClick={toggleExpand} size="small">
171+
{isExpanded ? <ExpandLessIcon /> : <ExpandMoreIcon />}
172+
</IconButton>
173+
</Box>
174+
{isExpanded && (
175+
<>
176+
{children}
177+
<Typography variant="h6" gutterBottom color="secondary" sx={{ mt: 1 }}>
178+
Reviews
179+
</Typography>
180+
{reviewsList === null ? (
181+
<Box
182+
sx={{
183+
display: 'flex',
184+
alignItems: 'center',
185+
justifyContent: 'center',
186+
height: '150px',
187+
}}
188+
>
189+
<CircularProgress />
190+
</Box>
191+
) : !reviewsList || reviewsList.length === 0 ? (
192+
<Typography variant="body1" color="text.secondary">
193+
No reviews available.
194+
</Typography>
195+
) : (
196+
reviewsList.map((review, index) => (
197+
<Review
198+
review={review}
199+
endpoint={endpoint}
200+
onUpdate={fetchReviews}
201+
/>
202+
))
203+
)}
204+
<ReviewInput endpoint={endpoint} onUpdate={fetchReviews} />
205+
</>
173206
)}
174-
<ReviewInput endpoint={endpoint} onUpdate={fetchReviews} />
175207
</CardContent>
176208
</Card>
177209
);

frontend/src/pages/Courses.jsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,22 +164,13 @@ const Courses = ({ courseList, profMap }) => {
164164
>
165165
No match found for given filters.
166166
</Typography>
167-
) : filteredCourses.length > 50 ? (
168-
<Typography
169-
variant="body2"
170-
color="text.primary"
171-
sx={{ fontStyle: 'italic' }}
172-
>
173-
Too many matches for given filters, please narrow them down.
174-
</Typography>
175167
) : (
176168
filteredCourses.map((course, index) => (
177169
<ReviewBox
170+
title={`[${course.code}] ${course.name} (${course.sem})`}
178171
endpoint={`/courses/reviews/${course.sem}/${course.code}`}
172+
initExpanded={filteredCourses.length < 10}
179173
>
180-
<Typography variant="h5" gutterBottom color="primary">
181-
[{course.code}] {course.name} ({course.sem})
182-
</Typography>
183174
{course.profs.map((email) => {
184175
const prof = profMap.get(email);
185176
return prof ? (

frontend/src/pages/Profs.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ const Profs = ({ profList }) => {
6262
</Tooltip>
6363
</Box>
6464
{reviewProf ? (
65-
<ReviewBox endpoint={`/members/reviews/${reviewProf.email}`}>
66-
<Typography variant="h5" gutterBottom color="primary">
67-
{reviewProf.name} &lt;{reviewProf.email}&gt;
68-
</Typography>
69-
</ReviewBox>
65+
<ReviewBox
66+
title={`${reviewProf.name} <${reviewProf.email}>`}
67+
endpoint={`/members/reviews/${reviewProf.email}`}
68+
initExpanded={true}
69+
/>
7070
) : (
7171
<Typography
7272
variant="body2"

0 commit comments

Comments
 (0)