Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/course/common/handout-header.tsx
10799 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Input } from "antd";
7
import { useEffect, useState } from "react";
8
import { DebounceInput } from "react-debounce-input";
9
import { useIntl } from "react-intl";
10
11
import { CourseActions } from "../actions";
12
import type { HandoutRecord } from "../store";
13
import { CopyRunAllAlert } from "./copy-run-all";
14
import { filterPlaceholder, runAllAriaLabel } from "./course-unit-strings";
15
import type { HandoutStatus } from "./course-unit-types";
16
import { Progress } from "./progress";
17
import { RunAllPopover } from "./run-all-popover";
18
import { StudentAssignmentInfoHeader } from "./student-assignment-info-header";
19
20
interface HandoutHeaderProps {
21
handout: HandoutRecord;
22
status: HandoutStatus | null;
23
numStudents: number;
24
actions: CourseActions;
25
studentSearch: string;
26
setStudentSearch: (value: string) => void;
27
}
28
29
export function HandoutHeader({
30
handout,
31
status,
32
numStudents,
33
actions,
34
studentSearch,
35
setStudentSearch,
36
}: HandoutHeaderProps) {
37
const intl = useIntl();
38
const [openedRunAll, setOpenedRunAll] = useState<"distribution" | null>(null);
39
40
useEffect(() => {
41
setOpenedRunAll(null);
42
}, [handout.get("handout_id")]);
43
44
if (status == null) {
45
return null;
46
}
47
// Keep a narrowed alias since nested closures use this value and TS can
48
// lose the non-null guard on `status` across those closures.
49
const handoutStatus = status;
50
51
function renderDistributionRunAll() {
52
return (
53
<RunAllPopover
54
id="distribution"
55
open={openedRunAll === "distribution"}
56
onOpenChange={(next) => setOpenedRunAll(next ? "distribution" : null)}
57
type={handoutStatus.not_handout > 0 ? "primary" : "default"}
58
content={
59
<CopyRunAllAlert
60
id="copy_confirm_handout"
61
step="distribution"
62
status={{
63
done: handoutStatus.handout,
64
not_done: handoutStatus.not_handout,
65
total: numStudents,
66
}}
67
onRun={({ scope, overwrite }) => {
68
// handout to all (non-deleted) students
69
actions.handouts.copy_handout_to_all_students(
70
handout.get("handout_id"),
71
scope === "remaining",
72
!!overwrite,
73
);
74
setOpenedRunAll(null);
75
}}
76
/>
77
}
78
ariaLabel={runAllAriaLabel(intl, "distribution")}
79
/>
80
);
81
}
82
83
return (
84
<StudentAssignmentInfoHeader
85
mode="handout"
86
actions={{
87
distribution: [renderDistributionRunAll()],
88
}}
89
progress={{
90
distribution: (
91
<Progress
92
key="progress-handout"
93
done={handoutStatus.handout}
94
not_done={handoutStatus.not_handout}
95
step="distributed"
96
/>
97
),
98
}}
99
filter={
100
<DebounceInput
101
debounceTimeout={500}
102
element={Input as any}
103
placeholder={filterPlaceholder(intl)}
104
value={studentSearch}
105
onChange={(e) => setStudentSearch(e.target.value)}
106
/>
107
}
108
/>
109
);
110
}
111
112