All files / components/Scaffold ScaffoldTopBar.tsx

85.71% Statements 6/7
100% Branches 8/8
75% Functions 3/4
85.71% Lines 6/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125                          12x 12x                                                                     156x 156x   156x                           1x                                                                                                                    
import { useState } from "react";
import type { Assessment, Question, Course } from "main/types/conceptGraph";
import type { CourseAccess } from "main/components/Courses/CourseMenu";
import AssessmentSelect from "main/components/Scaffold/AssessmentSelect";
import QuestionSearch from "main/components/Scaffold/QuestionSearch";
import LinkToSettings from "main/components/Scaffold/LinkToSettings";
import StarStatus from "main/components/Scaffold/StarStatus";
import UnlockAssessmentsModal from "main/components/Scaffold/UnlockAssessmentsModal";
import { useStaffTools } from "main/utils/useStaffTools";
 
// Formats the course-identifying banner text shown above the top bar, e.g.
// "CMPSC 5B, S26, UCSB, phtcon@ucsb.edu (3)".
function formatCourseInfo(courseInfo: CourseAccess): string {
  const { courseName, term, school, instructorEmail, id } = courseInfo;
  return `${courseName}, ${term}, ${school.displayName}, ${instructorEmail} (${id})`;
}
 
interface ScaffoldTopBarProps {
  // Undefined while the course is still loading; the settings link is
  // omitted until it arrives.
  course?: Course;
  // Undefined while still loading; the course-identifying banner above the
  // bar is omitted until it arrives. Unlike `course` (staff-only), this is
  // available to any user with access to the course.
  courseInfo?: CourseAccess;
  courseId: number;
  assessments: Assessment[];
  selectedAssessmentId: string;
  onSelectAssessment: (id: string) => void;
  questions: Question[];
  selectedQuestionId: string;
  onSelectQuestion: (id: string) => void;
  numStarredConcepts: number;
  numTotalConcepts: number;
}
 
export default function ScaffoldTopBar({
  course,
  courseInfo,
  courseId,
  assessments,
  selectedAssessmentId,
  onSelectAssessment,
  questions,
  selectedQuestionId,
  onSelectQuestion,
  numStarredConcepts,
  numTotalConcepts,
}: ScaffoldTopBarProps) {
  const { enableEditing } = useStaffTools();
  const [showUnlockModal, setShowUnlockModal] = useState(false);
 
  return (
    <div className="scaffold-top-bar-wrapper">
      {courseInfo && (
        <div
          className="scaffold-top-bar-course-info"
          data-testid="ScaffoldTopBar-courseInfo"
        >
          {formatCourseInfo(courseInfo)}
        </div>
      )}
      <div className="scaffold-top-bar" data-testid="ScaffoldTopBar">
        {enableEditing && (
          <button
            data-testid="ScaffoldTopBar-unlockAssessments"
            onClick={() => setShowUnlockModal(true)}
            style={{
              height: 28,
              padding: "0px 10px",
              fontFamily: "Helvetica, Arial, sans-serif",
              fontSize: 13,
              background: "#ffffff",
              color: "#1E293B",
              border: "1px solid #000000",
              borderRadius: 6,
              cursor: "pointer",
              whiteSpace: "nowrap",
            }}
          >
            Unlock Assessments
          </button>
        )}
        <AssessmentSelect
          assessments={assessments}
          selectedAssessmentId={selectedAssessmentId}
          onSelect={onSelectAssessment}
        />
        <UnlockAssessmentsModal
          show={showUnlockModal}
          onHide={() => setShowUnlockModal(false)}
          courseId={courseId}
        />
        <div style={{ width: 300 }}>
          <QuestionSearch
            questions={questions}
            selectedQuestionId={selectedQuestionId}
            onSelect={onSelectQuestion}
            disabled={!selectedAssessmentId || questions.length === 0}
          />
        </div>
        <div
          style={{
            marginLeft: "auto",
            display: "flex",
            alignItems: "center",
            gap: 12,
          }}
        >
          {course && (
            <LinkToSettings
              course={course}
              testId="ScaffoldTopBar-linkToSettings"
            />
          )}
          <StarStatus
            numStarredConcepts={numStarredConcepts}
            numTotalConcepts={numTotalConcepts}
          />
        </div>
      </div>
    </div>
  );
}