Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/editors/stopwatch/editor.tsx
1691 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
/*
7
Time
8
9
Right now this is the simplest possible imaginable stopwatch, with state synchronized properly.
10
11
This is also probably a good relatively simple example of a React-based editor that
12
uses persistent shared state.
13
14
Later, maybe:
15
16
- [ ] Make the editor title tab display the current time
17
- [ ] Make TimeTravel rendering work (so easy undo in case accidentally hit stop)
18
- [x] Labels/description, which is full markdown, hence can have links
19
- [ ] Ability to set a specific time
20
- [ ] Initialize this will just be a simple stopwatch, synchronized between viewers.
21
- [ ] Maybe a bunch of stopwatches and countdown timers, with labels, markdown links, etc.; draggable.
22
- [ ] Later yet, it may hook into what other activities are going on in a project, to auto stop/start, etc.
23
- [ ] Time tracking
24
*/
25
26
import { Alert, Button } from "antd";
27
import { PlusCircleTwoTone } from "@ant-design/icons";
28
import { Loading } from "@cocalc/frontend/components/loading";
29
import { ReactNode } from "react";
30
import Stopwatch from "./stopwatch";
31
import { ButtonBar } from "./button-bar";
32
import type { TimeActions } from "./actions";
33
import { List } from "immutable";
34
import { useRedux } from "@cocalc/frontend/app-framework";
35
import { useFrameContext } from "@cocalc/frontend/frame-editors/frame-tree/frame-context";
36
37
export default function EditorTime() {
38
// TODO: sort of abusive...
39
const { project_id, path, actions } = useFrameContext() as unknown as {
40
project_id: string;
41
path: string;
42
actions?: TimeActions;
43
};
44
const timers: List<any> | undefined = useRedux(["timers"], project_id, path);
45
const error: string | undefined = useRedux(["error"], project_id, path);
46
47
if (timers == null || actions == null) {
48
return <Loading />;
49
}
50
51
function renderStopwatches(): ReactNode[] {
52
if (timers == null) {
53
return [];
54
}
55
return timers
56
.sortBy((x) => x.get("id"))
57
.toJS()
58
.map((data) => (
59
<Stopwatch
60
key={data.id}
61
label={data.label}
62
total={data.total}
63
state={data.state}
64
time={data.time}
65
countdown={data.countdown}
66
clickButton={(button) => clickButton(data.id, button)}
67
setLabel={(label) => setLabel(data.id, label)}
68
setCountdown={
69
data.countdown != null
70
? (countdown) => {
71
actions?.setCountdown(data.id, countdown);
72
}
73
: undefined
74
}
75
/>
76
));
77
}
78
79
function clickButton(id: number, button: string): void {
80
if (actions == null) {
81
return;
82
}
83
switch (button) {
84
case "reset":
85
actions.resetStopwatch(id);
86
return;
87
case "start":
88
actions.startStopwatch(id);
89
return;
90
case "pause":
91
actions.pauseStopwatch(id);
92
return;
93
case "delete":
94
actions.deleteStopwatch(id);
95
return;
96
default:
97
console.warn(`unknown button '${button}'`);
98
return;
99
}
100
}
101
102
function setLabel(id: number, label: string): void {
103
actions?.setLabel(id, label);
104
}
105
106
function renderButtonBar(): ReactNode {
107
if (actions == null) return null;
108
return <ButtonBar actions={actions} />;
109
}
110
111
return (
112
<div className="smc-vfill">
113
{error && <Alert type="error" message={`Error: ${error}`} />}
114
{renderButtonBar()}
115
<div className="smc-vfill" style={{ overflowY: "auto" }}>
116
{renderStopwatches()}
117
<div style={{ display: "flex" }}>
118
<Button
119
size="large"
120
icon={<PlusCircleTwoTone />}
121
style={{ maxWidth: "200px", margin: "15px" }}
122
key={"add-stopwatch"}
123
onClick={() => actions.addStopwatch()}
124
>
125
New Stopwatch
126
</Button>
127
<Button
128
size="large"
129
icon={<PlusCircleTwoTone />}
130
style={{ maxWidth: "200px", margin: "15px" }}
131
key={"add-timer"}
132
onClick={() => actions.addTimer()}
133
>
134
New Timer
135
</Button>
136
</div>
137
</div>
138
</div>
139
);
140
}
141
142