Skip to content

Commit 5036993

Browse files
committed
TA Review Student Box/Ta Settings
1 parent 524282d commit 5036993

File tree

7 files changed

+250
-30
lines changed

7 files changed

+250
-30
lines changed

frontend/components/Course/Analytics/Analytics.tsx

+111-26
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import Link from "next/link";
22
import { useState } from "react";
3-
import { Segment, Grid, Dropdown } from "semantic-ui-react";
4-
import { Course, Queue } from "../../../types";
3+
import {
4+
Segment,
5+
Grid,
6+
Dropdown,
7+
Tab,
8+
Rating,
9+
Divider,
10+
} from "semantic-ui-react";
11+
import { Course, Membership, Queue } from "../../../types";
512
import Averages from "./Heatmaps/Averages";
613
import SummaryCards from "./Cards/SummaryCards";
714

815
interface AnalyticsProps {
916
course: Course;
1017
queues: Queue[];
18+
leadership: Membership[];
1119
}
1220

13-
const Analytics = ({ course, queues }: AnalyticsProps) => {
21+
const Analytics = ({ course, queues, leadership }: AnalyticsProps) => {
1422
const [queueId, setQueueId] = useState<number | undefined>(
1523
queues.length !== 0 ? queues[0].id : undefined
1624
);
@@ -23,30 +31,107 @@ const Analytics = ({ course, queues }: AnalyticsProps) => {
2331
};
2432
});
2533

34+
const taOptions = [
35+
{ key: -1, value: -1, text: "Filter by TA" },
36+
...leadership.map((leader) => {
37+
return {
38+
key: leader.id,
39+
value: leader.id,
40+
text: `${leader.user.firstName} ${leader.user.lastName}`,
41+
};
42+
}),
43+
];
44+
45+
const [tab, setTab] = useState(0);
46+
47+
const panes = [
48+
{ menuItem: "Analytics", render: () => <br /> },
49+
{ menuItem: "Student Feedback", render: () => <br /> },
50+
];
2651
return (
27-
<Grid.Row>
28-
{queueId ? (
29-
<>
30-
<Dropdown
31-
as="h3"
32-
inline
33-
options={queueOptions}
34-
defaultValue={queueId}
35-
onChange={(e, { value }) => {
36-
setQueueId(value as number);
37-
}}
38-
/>
39-
<SummaryCards courseId={course.id} queueId={queueId} />
40-
<Averages courseId={course.id} queueId={queueId} />
41-
</>
42-
) : (
43-
<Segment basic>
44-
You have no queues. Create a queue on the{" "}
45-
<Link href={`/courses/${course.id}`}>queue page</Link> to
46-
see analytics.
47-
</Segment>
48-
)}
49-
</Grid.Row>
52+
<>
53+
<Grid.Row>
54+
<Tab
55+
defaultActiveIndex={0}
56+
onTabChange={(_, { activeIndex }) =>
57+
setTab(activeIndex as number)
58+
}
59+
panes={panes}
60+
/>
61+
</Grid.Row>
62+
<Grid.Row>
63+
{tab === 0 &&
64+
(queueId ? (
65+
<>
66+
<Dropdown
67+
as="h3"
68+
inline
69+
options={queueOptions}
70+
defaultValue={queueId}
71+
onChange={(e, { value }) => {
72+
setQueueId(value as number);
73+
}}
74+
/>
75+
<SummaryCards
76+
courseId={course.id}
77+
queueId={queueId}
78+
/>
79+
<Averages courseId={course.id} queueId={queueId} />
80+
</>
81+
) : (
82+
<Segment basic>
83+
You have no queues. Create a queue on the{" "}
84+
<Link href={`/courses/${course.id}`}>
85+
queue page
86+
</Link>{" "}
87+
to see analytics.
88+
</Segment>
89+
))}
90+
{tab === 1 && (
91+
<div>
92+
<Dropdown
93+
as="h3"
94+
inline
95+
options={taOptions}
96+
defaultValue={-1}
97+
/>
98+
<Segment color="olive">
99+
<div>
100+
Student <b>Ryan Tanenholz </b>asked &quot;What
101+
is the difference between a stack and a
102+
queue?&quot;
103+
</div>
104+
<div>
105+
and provided the following feedback to TA{" "}
106+
<b>Ben Franklin</b>.
107+
</div>
108+
<Divider />
109+
<div>
110+
<b>Rating</b>{" "}
111+
<Rating
112+
icon="star"
113+
defaultRating={5}
114+
maxRating={5}
115+
disabled
116+
/>
117+
</div>
118+
<div>
119+
<b>Comment </b>
120+
{/* Default Text */}
121+
Ben Franklin was very helpful and explained the
122+
concepts clearly. I was struggling with
123+
understanding the problem, but Ben Franklin
124+
broke it down into manageable parts and guided
125+
me through each step. His patience and ability
126+
to simplify complex topics made a significant
127+
difference in my learning experience. Highly
128+
recommend!
129+
</div>
130+
</Segment>
131+
</div>
132+
)}
133+
</Grid.Row>
134+
</>
50135
);
51136
};
52137

frontend/components/Course/CourseSettings/CourseForm.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const CourseForm = (props: CourseFormProps) => {
5151
courseCode: course.courseCode,
5252
courseTitle: course.courseTitle,
5353
semester: course.semester,
54+
taReviews: course.taReviews,
5455
});
5556

5657
const [oldTags, setOldTags] = useState<TagMap>(toTagMap(tags!));
@@ -79,6 +80,7 @@ const CourseForm = (props: CourseFormProps) => {
7980
input.courseCode === course.courseCode &&
8081
input.courseTitle === course.courseTitle &&
8182
input.inviteOnly === course.inviteOnly &&
83+
input.taReviews === course.taReviews &&
8284
input.semester === course.semester &&
8385
addedTags.length === 0 &&
8486
deletedTags.length === 0),
@@ -101,6 +103,7 @@ const CourseForm = (props: CourseFormProps) => {
101103
setCourseTitleCharCount(value.length);
102104
}
103105
input[name] = name === "inviteOnly" ? !input[name] : value;
106+
input[name] = name === "taReviews" ? !input[name] : value;
104107
setInput({ ...input });
105108
};
106109

@@ -301,6 +304,17 @@ const CourseForm = (props: CourseFormProps) => {
301304
onChange={handleInputChange}
302305
/>
303306
</Form.Field>
307+
<Form.Field required>
308+
<label htmlFor="ta-reviews">TA Reviews?</label>
309+
<Form.Checkbox
310+
id="ta-reviews"
311+
defaultChecked={course.taReviews}
312+
name="taReviews"
313+
disabled={loading}
314+
toggle
315+
onChange={handleInputChange}
316+
/>
317+
</Form.Field>
304318
<Button
305319
color="blue"
306320
type="submit"

frontend/components/Course/StudentQueuePage/LastQuestionCard.tsx

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
import { Segment, Message } from "semantic-ui-react";
2-
import { Question } from "../../../types";
2+
import { useState } from "react";
3+
import { Course, Question } from "../../../types";
34
import { getFullName } from "../../../utils";
5+
import QuestionReview from "./QuestionReview";
46

5-
const LastQuestionCard = ({ question }: { question: Question }) => {
7+
const LastQuestionCard = ({
8+
question,
9+
course,
10+
}: {
11+
question: Question;
12+
course: Course;
13+
}) => {
14+
const [reviewed, setReviewed] = useState(false);
615
const timeString = (date) => {
716
return new Date(date).toLocaleString("en-US", {
817
// TODO: this isn't a good fix
@@ -95,6 +104,21 @@ const LastQuestionCard = ({ question }: { question: Question }) => {
95104
success={question.status === "ANSWERED"}
96105
info={question.status === "WITHDRAWN"}
97106
>
107+
{course.taReviews && reviewed ? (
108+
<div
109+
style={{
110+
padding: "0.5em 0",
111+
}}
112+
>
113+
Thank you for responding! Your feedback has been
114+
recieved.
115+
</div>
116+
) : (
117+
<>
118+
<QuestionReview setReviewed={setReviewed} />
119+
<br />
120+
</>
121+
)}
98122
If you believe this is an error, please contact course staff!
99123
</Message>
100124
</Segment>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { useState } from "react";
2+
import { Button, Form, Rating, TextArea } from "semantic-ui-react";
3+
4+
interface QuestionReviewInput {
5+
rating: number;
6+
review: String;
7+
}
8+
interface QuestionReviewProps {
9+
setReviewed: (reviewed: boolean) => void;
10+
}
11+
const QuestionReview = ({ setReviewed }: QuestionReviewProps) => {
12+
const [input, setInput] = useState<QuestionReviewInput>({
13+
rating: 0,
14+
review: "",
15+
});
16+
const canSubmit = () => {
17+
return (
18+
input.rating > 0 &&
19+
input.review.length > 0 &&
20+
input.review.length <= 1000
21+
);
22+
};
23+
const handleSubmit = () => {
24+
if (!canSubmit()) {
25+
return;
26+
}
27+
setReviewed(true);
28+
};
29+
return (
30+
<div>
31+
<Form>
32+
<Form.Field>
33+
<div
34+
style={{
35+
display: "flex",
36+
flexDirection: "row",
37+
gap: "1em",
38+
}}
39+
>
40+
<div>How was your experience?</div>
41+
<Rating
42+
required
43+
icon="star"
44+
defaultRating={0}
45+
maxRating={5}
46+
size="huge"
47+
onRate={(e, { rating }) =>
48+
setInput({
49+
...input,
50+
rating: rating as number,
51+
})
52+
}
53+
/>
54+
</div>
55+
</Form.Field>
56+
<Form.Field>
57+
<TextArea
58+
id="review-text-area"
59+
placeholder="Tell us more..."
60+
onChange={(e) =>
61+
setInput({ ...input, review: e.target.value })
62+
}
63+
/>
64+
</Form.Field>
65+
<div
66+
style={{
67+
textAlign: "right",
68+
fontSize: "0.8em",
69+
color: input.review.length > 1000 ? "red" : "",
70+
}}
71+
>
72+
Characters: {input.review.length ?? 0}/1000
73+
</div>
74+
<Button
75+
disabled={!canSubmit()}
76+
type="submit"
77+
color="green"
78+
size="small"
79+
onClick={() => handleSubmit()}
80+
>
81+
Submit
82+
</Button>
83+
</Form>
84+
</div>
85+
);
86+
};
87+
export default QuestionReview;

frontend/components/Course/StudentQueuePage/StudentQueue.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,10 @@ const StudentQueue = (props: StudentQueueProps) => {
256256
{lastQuestions && lastQuestions.length !== 0 && (
257257
<Grid.Row columns={1}>
258258
<Grid.Column>
259-
<LastQuestionCard question={lastQuestions[0]} />
259+
<LastQuestionCard
260+
question={lastQuestions[0]}
261+
course={course}
262+
/>
260263
</Grid.Column>
261264
</Grid.Row>
262265
)}

frontend/pages/courses/[course]/analytics.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ const AnalyticsPage = (props: AnalyticsPageProps) => {
2929
course={course}
3030
leadership={leadership}
3131
render={() => {
32-
return <Analytics course={course} queues={queues} />;
32+
return (
33+
<Analytics
34+
course={course}
35+
queues={queues}
36+
leadership={leadership}
37+
/>
38+
);
3339
}}
3440
/>
3541
</Grid>

frontend/types.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export interface Course {
1010
semesterPretty: string;
1111
archived: boolean;
1212
inviteOnly: boolean;
13+
taReviews: boolean;
1314
isMember: boolean;
1415
}
1516

0 commit comments

Comments
 (0)