Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/course/handouts/handouts-info-panel.tsx
1503 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
// CoCalc libraries
7
// React Libraries
8
import { Button, Col, Row, Space } from "antd";
9
import { useState } from "react";
10
import { useIntl } from "react-intl";
11
12
import { Icon, Tip } from "@cocalc/frontend/components";
13
import ShowError from "@cocalc/frontend/components/error";
14
import { COPY_TIMEOUT_MS } from "@cocalc/frontend/course/consts";
15
import { labels } from "@cocalc/frontend/i18n";
16
import { webapp_client } from "@cocalc/frontend/webapp-client";
17
import { CourseActions } from "../actions";
18
import { BigTime } from "../common";
19
import { LastCopyInfo } from "../store";
20
21
interface StudentHandoutInfoProps {
22
actions: CourseActions;
23
info: { handout_id: string; student_id: string; status?: LastCopyInfo };
24
title: string;
25
}
26
27
export function StudentHandoutInfo({
28
actions,
29
info,
30
title,
31
}: StudentHandoutInfoProps) {
32
const intl = useIntl();
33
34
const [recopy, setRecopy] = useState<boolean>(false);
35
36
function open(handout_id: string, student_id: string): void {
37
actions.handouts.open_handout(handout_id, student_id);
38
}
39
40
function copy(handout_id: string, student_id: string): void {
41
actions.handouts.copy_handout_to_student(handout_id, student_id, false);
42
}
43
44
function stop(handout_id: string, student_id: string): void {
45
actions.handouts.stop_copying_handout(handout_id, student_id);
46
}
47
48
function render_last_time(time) {
49
return (
50
<div key="time" style={{ color: "#666" }}>
51
(<BigTime date={time} />)
52
</div>
53
);
54
}
55
56
function render_open_recopy_confirm(name, copy, copy_tip) {
57
if (recopy) {
58
const v: any[] = [];
59
v.push(
60
<Button key="copy_cancel" onClick={() => setRecopy(false)}>
61
{intl.formatMessage(labels.cancel)}
62
</Button>,
63
);
64
v.push(
65
<Button
66
key="copy_confirm"
67
danger
68
onClick={() => {
69
setRecopy(false);
70
return copy();
71
}}
72
>
73
<Icon name="share-square" /> Yes, {name.toLowerCase()} again
74
</Button>,
75
);
76
return <Space wrap>{v}</Space>;
77
} else {
78
return (
79
<Button type="dashed" key="copy" onClick={() => setRecopy(true)}>
80
<Tip title={name} tip={<span>{copy_tip}</span>}>
81
<Icon name="share-square" /> {name}...
82
</Tip>
83
</Button>
84
);
85
}
86
}
87
88
function render_open_recopy(name, open, copy, copy_tip, open_tip) {
89
return (
90
<Space key="open_recopy">
91
{render_open_recopy_confirm(name, copy, copy_tip)}
92
<Button key="open" onClick={open}>
93
<Tip title="Open Folder" tip={open_tip}>
94
<Icon name="folder-open" /> Open directory...
95
</Tip>
96
</Button>
97
</Space>
98
);
99
}
100
101
function render_open_copying(open, stop) {
102
return (
103
<Space key="open_copying">
104
<Button key="copy" type="primary" disabled={true}>
105
<Icon name="cocalc-ring" spin /> Working...
106
</Button>
107
<Button key="stop" danger onClick={stop}>
108
<Icon name="times" />
109
</Button>
110
<Button key="open" onClick={open}>
111
<Icon name="folder-open" /> Open
112
</Button>
113
</Space>
114
);
115
}
116
117
function render_copy(name, copy, copy_tip) {
118
return (
119
<Tip key="copy" title={name} tip={copy_tip}>
120
<Button onClick={copy} type="primary">
121
<Icon name="share-square" /> {name}
122
</Button>
123
</Tip>
124
);
125
}
126
127
function render_error(name, error) {
128
if (typeof error !== "string") {
129
error = `${error}`;
130
}
131
if (error.includes("[object Object]")) {
132
// already too late to know the actual error -- it got mangled/reported incorrectly
133
error = "";
134
}
135
if (error.indexOf("No such file or directory") !== -1) {
136
error = `Somebody may have moved the folder that should have contained the handout -- \n${error}`;
137
} else {
138
error = `Try to ${name.toLowerCase()} again -- \n${error}`;
139
}
140
return (
141
<ShowError
142
key="error"
143
error={error}
144
style={{ marginTop: "5px", maxHeight: "140px", overflow: "auto" }}
145
/>
146
);
147
}
148
149
function render_last(name, obj, info, enable_copy, copy_tip, open_tip) {
150
const do_open = () => open(info.handout_id, info.student_id);
151
const do_copy = () => copy(info.handout_id, info.student_id);
152
const do_stop = () => stop(info.handout_id, info.student_id);
153
if (obj == null) {
154
obj = {};
155
}
156
const v: any[] = [];
157
if (enable_copy) {
158
if (webapp_client.server_time() - (obj.start ?? 0) < COPY_TIMEOUT_MS) {
159
v.push(render_open_copying(do_open, do_stop));
160
} else if (obj.time) {
161
v.push(render_open_recopy(name, do_open, do_copy, copy_tip, open_tip));
162
} else {
163
v.push(render_copy(name, do_copy, copy_tip));
164
}
165
}
166
if (obj.time) {
167
v.push(render_last_time(obj.time));
168
}
169
if (obj.error) {
170
v.push(render_error(name, obj.error));
171
}
172
return v;
173
}
174
175
return (
176
<div>
177
<Row
178
style={{
179
borderTop: "1px solid #aaa",
180
paddingTop: "5px",
181
paddingBottom: "5px",
182
}}
183
>
184
<Col md={4} key="title">
185
{title}
186
</Col>
187
<Col md={20} key="rest">
188
<Row>
189
<Col md={24} key="last_handout">
190
{render_last(
191
"Distribute",
192
info.status,
193
info,
194
true,
195
"Copy the handout from your project to this student's project.",
196
"Open the student's copy of this handout directly in their project. You will be able to see them type, chat with them, answer questions, etc.",
197
)}
198
</Col>
199
</Row>
200
</Col>
201
</Row>
202
</div>
203
);
204
}
205
206