Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/pages/ephemeral.tsx
2442 views
1
/*
2
* This file is part of CoCalc: Copyright © 2024 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { useEffect, useState } from "react";
7
import { Alert, Button, Card, Input, Layout, Space, Typography } from "antd";
8
import Footer from "components/landing/footer";
9
import Header from "components/landing/header";
10
import Head from "components/landing/head";
11
import { Icon } from "@cocalc/frontend/components/icon";
12
import apiPost from "lib/api/post";
13
import { Customize } from "lib/customize";
14
import withCustomize from "lib/with-customize";
15
import { useRouter } from "next/router";
16
17
const { Paragraph, Text, Title } = Typography;
18
19
type Status = "idle" | "verifying" | "redirecting";
20
21
interface Props {
22
customize;
23
token?: string;
24
}
25
26
export default function EphemeralPage({ customize, token }: Props) {
27
const router = useRouter();
28
const [registrationToken, setRegistrationToken] = useState<string>(
29
token ?? "",
30
);
31
const [status, setStatus] = useState<Status>("idle");
32
const [info, setInfo] = useState<string>("");
33
const [error, setError] = useState<string>("");
34
35
useEffect(() => {
36
if (token) {
37
setRegistrationToken(token);
38
}
39
}, [token]);
40
41
const trimmedToken = registrationToken.trim();
42
const working = status !== "idle";
43
const disabled = trimmedToken.length === 0 || working;
44
45
async function handleConfirm(): Promise<void> {
46
if (disabled) return;
47
setStatus("verifying");
48
setInfo("");
49
setError("");
50
try {
51
const result = await apiPost("/auth/ephemeral", {
52
registrationToken: trimmedToken,
53
});
54
setStatus("redirecting");
55
setInfo("Success! Redirecting you to your workspace…");
56
if (result?.project_id) {
57
await router.push(
58
`/static/app.html?target=projects/${result.project_id}/files/`,
59
);
60
} else {
61
await router.push("/static/app.html?target=projects");
62
}
63
} catch (err) {
64
setError(err?.message ?? `${err}`);
65
setStatus("idle");
66
}
67
}
68
69
return (
70
<Customize value={customize}>
71
<Head title="Create Ephemeral Account" />
72
<Layout>
73
<Header />
74
<Layout.Content style={{ backgroundColor: "white", minHeight: "60vh" }}>
75
<div
76
style={{
77
maxWidth: "640px",
78
margin: "8vh auto 10vh auto",
79
padding: "0 15px",
80
}}
81
>
82
<Card>
83
<Space
84
direction="vertical"
85
style={{ width: "100%" }}
86
size="large"
87
>
88
<Space
89
align="center"
90
direction="vertical"
91
style={{ width: "100%" }}
92
>
93
<Icon name="user" style={{ fontSize: "60px" }} />
94
<Title level={2} style={{ marginBottom: 0 }}>
95
Enter Registration Token
96
</Title>
97
<Paragraph style={{ textAlign: "center", marginBottom: 0 }}>
98
Provide the registration token supplied for your exam or
99
event. You can land directly on this page using{" "}
100
<code>/ephemeral?token=YOUR_TOKEN</code>, or paste the code
101
below.
102
</Paragraph>
103
</Space>
104
105
<div>
106
<Text strong>Registration Token</Text>
107
<Input
108
allowClear
109
autoFocus
110
size="large"
111
placeholder="abc123..."
112
value={registrationToken}
113
onChange={(e) => {
114
setRegistrationToken(e.target.value);
115
if (info) setInfo("");
116
if (error) setError("");
117
}}
118
onPressEnter={disabled ? undefined : handleConfirm}
119
/>
120
</div>
121
122
{error && (
123
<Alert
124
type="error"
125
message="Unable to create account"
126
description={error}
127
showIcon
128
closable
129
onClose={() => setError("")}
130
/>
131
)}
132
133
{info && (
134
<Alert
135
type="info"
136
message={info}
137
showIcon
138
closable
139
onClose={() => setInfo("")}
140
/>
141
)}
142
143
<Button
144
type="primary"
145
size="large"
146
disabled={disabled}
147
loading={working}
148
onClick={handleConfirm}
149
block
150
>
151
{status === "redirecting" ? "Redirecting…" : "Continue"}
152
</Button>
153
154
<Alert
155
type="warning"
156
showIcon
157
message="Ephemeral accounts"
158
description={
159
<Paragraph style={{ marginBottom: 0 }}>
160
Ephemeral accounts automatically expire after the duration
161
configured with their registration token. When the token
162
is valid you'll be signed in automatically and redirected
163
to your workspace with a cookie that expires at the same
164
time.
165
</Paragraph>
166
}
167
/>
168
</Space>
169
</Card>
170
</div>
171
</Layout.Content>
172
<Footer />
173
</Layout>
174
</Customize>
175
);
176
}
177
178
export async function getServerSideProps(context) {
179
const token =
180
typeof context?.query?.token === "string" ? context.query.token : "";
181
return await withCustomize({
182
context,
183
props: { token },
184
});
185
}
186
187