All files / components AssessmentSelect.tsx

0% Statements 0/19
0% Branches 0/21
0% Functions 0/11
0% Lines 0/16

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                                                                                                                                                                                                                                                       
import { useState, useEffect, useRef } from "react";
import type { Assessment } from "../api/client";
 
interface AssessmentSelectProps {
  assessments: Assessment[];
  selectedAssessmentId: string;
  onSelect: (id: string) => void;
}
 
export default function AssessmentSelect({
  assessments,
  selectedAssessmentId,
  onSelect,
}: AssessmentSelectProps) {
  const [isOpen, setIsOpen] = useState(false);
  const containerRef = useRef<HTMLDivElement>(null);
 
  const selectedName =
    assessments.find((a) => a.id === selectedAssessmentId)?.name ?? "";
 
  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (
        containerRef.current &&
        !containerRef.current.contains(e.target as Node)
      ) {
        setIsOpen(false);
      }
    };
    document.addEventListener("mousedown", handler, true);
    return () => document.removeEventListener("mousedown", handler, true);
  }, []);
 
  return (
    <div ref={containerRef} style={{ position: "relative", minWidth: 200 }}>
      <div
        onClick={() => setIsOpen((o) => !o)}
        style={{
          width: "100%",
          height: 28,
          padding: "0px 10px",
          fontFamily: "Helvetica, Arial, sans-serif",
          fontSize: 13,
          background: "#ffffff",
          color: selectedAssessmentId ? "#1E293B" : "#94A3B8",
          border: "1px solid #000000",
          borderRadius: 6,
          cursor: "pointer",
          boxSizing: "border-box",
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          userSelect: "none",
        }}
      >
        <span>{selectedName || "Select assessment…"}</span>
        <svg
          width="12"
          height="12"
          viewBox="0 0 24 24"
          fill="none"
          stroke="#94A3B8"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
          style={{
            flexShrink: 0,
            transform: isOpen ? "rotate(180deg)" : "none",
            transition: "transform 0.15s",
          }}
        >
          <polyline points="6 9 12 15 18 9" />
        </svg>
      </div>
 
      {isOpen && assessments.length > 0 && (
        <div
          style={{
            position: "absolute",
            top: "calc(100% + 4px)",
            left: 0,
            right: 0,
            background: "#fff",
            border: "1px solid #E2E8F0",
            borderRadius: 6,
            boxShadow: "0 4px 16px rgba(0,0,0,0.1)",
            zIndex: 100,
            maxHeight: 260,
            overflowY: "auto",
          }}
        >
          {assessments.map((a, i) => (
            <div
              key={a.id}
              onMouseDown={() => {
                onSelect(a.id);
                setIsOpen(false);
              }}
              style={{
                padding: "4px 8px",
                fontSize: 12,
                cursor: "pointer",
                color: "#1E293B",
                background: a.id === selectedAssessmentId ? "#EFF6FF" : "#fff",
                borderBottom:
                  i < assessments.length - 1 ? "1px solid #F1F5F9" : "none",
              }}
              onMouseEnter={(e) =>
                (e.currentTarget.style.background = "#F8FAFC")
              }
              onMouseLeave={(e) =>
                (e.currentTarget.style.background =
                  a.id === selectedAssessmentId ? "#EFF6FF" : "#fff")
              }
            >
              {a.name}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}