- {/* Render stars for late count selection */}
- {[...Array(5)].map((_, i) => (
-
setLateCount(i + 1)}>
- {i < lateCount ? '★' : '☆'}
-
- ))}
+
+ {isLoading && (
+
+
+ Loading questionnaire...
+
+ )}
+
+ {!isLoading && items.length === 0 && (
+
+ No questionnaire items found for this review type. The assignment may not have a{' '}
+ {resolvedQuestionnaireType} questionnaire configured yet.
+
+ )}
+
+ {draftLoading && (
+
+ Loading saved draft...
+
+ )}
+
+ {draftIsSubmitted && (
+
+ This {isQuizMode ? 'quiz' : 'review'} has already been submitted. The form is read-only.
+
+ )}
+
+ {submitSuccess && isQuizMode && (
+
+
+ Quiz submitted!
+
+
+ Your score: {quizScore !== null ? quizScore : '\u2014'}
+
+ {redirectAfter && (
+
+ )}
+
+ )}
+
+ {items.length > 0 && (
+
+ )}
);
};
diff --git a/src/pages/StudentTasks/AssignedReviews.tsx b/src/pages/StudentTasks/AssignedReviews.tsx
new file mode 100644
index 00000000..cde330dc
--- /dev/null
+++ b/src/pages/StudentTasks/AssignedReviews.tsx
@@ -0,0 +1,452 @@
+import React, { useEffect, useState, useCallback, useMemo } from "react";
+import { Container, Row, Col, Alert, Button, Nav } from "react-bootstrap";
+import { useNavigate, useParams, Link } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { RootState } from "../../store/store";
+import axiosClient from "../../utils/axios_client";
+import useAPI from "../../hooks/useAPI";
+
+interface ReviewerPersistParticipant {
+ id: number;
+ user_id: number;
+ parent_id: number;
+ team_id?: number | null;
+}
+
+interface ReviewerPersistResponseMap {
+ id: number;
+ reviewer_id: number;
+ reviewee_id: number;
+ reviewed_object_id: number;
+ reviewee_team_id?: number | null;
+}
+
+interface ReviewerPersistResponse {
+ id: number;
+ map_id: number;
+ is_submitted: boolean | 0 | 1;
+ created_at?: string | null;
+ updated_at?: string | null;
+}
+
+interface ReviewerPersistTeam {
+ id: number;
+ name: string;
+}
+
+interface ReviewerPersist {
+ participants?: ReviewerPersistParticipant[];
+ response_maps?: ReviewerPersistResponseMap[];
+ responses?: ReviewerPersistResponse[];
+ teams?: ReviewerPersistTeam[];
+}
+
+interface AssignedReviewRow {
+ mapId: number;
+ responseId?: number;
+ teamName: string;
+ revieweeTeamId?: number;
+ assignmentId?: number;
+ assignmentName?: string;
+ status: "Not saved" | "Saved" | "Submitted";
+ questionnaireType: "Review" | "Teammate Review";
+ questionnaireId?: number;
+ questionnaireName: string;
+ // per-team quiz state
+ quizQuestionnaireId?: number;
+ quizTaken: boolean;
+}
+
+const AssignedReviews: React.FC = () => {
+ const navigate = useNavigate();
+ const { assignmentId: assignmentIdParam } = useParams<{ assignmentId?: string }>();
+ const { data: assignmentResponse, sendRequest: fetchAssignment } = useAPI();
+
+ const auth = useSelector((state: RootState) => state.authentication);
+ const currentUser = auth.user;
+
+ const [assignedReviews, setAssignedReviews] = useState