CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/account/settings/email-address-setting.tsx
Views: 687
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 { FormattedMessage, useIntl } from "react-intl";
7
import { alert_message } from "@cocalc/frontend/alerts";
8
import { Button, Card, Input, Space } from "antd";
9
import { useState } from "react";
10
import { ErrorDisplay, LabeledRow, Saving } from "@cocalc/frontend/components";
11
import { labels } from "@cocalc/frontend/i18n";
12
import { log } from "@cocalc/frontend/user-tracking";
13
import { webapp_client } from "@cocalc/frontend/webapp-client";
14
import { COLORS } from "@cocalc/util/theme";
15
16
interface Props {
17
email_address?: string;
18
disabled?: boolean;
19
is_anonymous?: boolean;
20
verify_emails?: boolean;
21
}
22
23
export const EmailAddressSetting = ({
24
email_address: email_address0,
25
disabled,
26
is_anonymous,
27
verify_emails,
28
}: Props) => {
29
const intl = useIntl();
30
const [state, setState] = useState<"view" | "edit" | "saving">("view");
31
const [password, setPassword] = useState<string>("");
32
const [email_address, set_email_address] = useState<string>(
33
email_address0 ?? "",
34
);
35
const [error, setError] = useState<string>("");
36
37
function start_editing() {
38
setState("edit");
39
set_email_address(email_address0 ?? "");
40
setError("");
41
setPassword("");
42
}
43
44
function cancel_editing() {
45
setState("view");
46
setPassword("");
47
}
48
49
async function save_editing(): Promise<void> {
50
if (password.length < 6) {
51
setState("edit");
52
setError("Password must be at least 6 characters long.");
53
return;
54
}
55
setState("saving");
56
try {
57
await webapp_client.account_client.change_email(email_address, password);
58
} catch (error) {
59
setState("edit");
60
setError(`Error -- ${error}`);
61
return;
62
}
63
if (is_anonymous) {
64
log("email_sign_up", { source: "anonymous_account" });
65
}
66
setState("view");
67
setError("");
68
setPassword("");
69
// if email verification is enabled, send out a token
70
// in any case, send a welcome email to an anonymous user, possibly
71
// including an email verification link
72
if (!(verify_emails || is_anonymous)) {
73
return;
74
}
75
try {
76
// anonymouse users will get the "welcome" email
77
await webapp_client.account_client.send_verification_email(!is_anonymous);
78
} catch (error) {
79
const err_msg = `Problem sending welcome email: ${error}`;
80
console.log(err_msg);
81
alert_message({ type: "error", message: err_msg });
82
}
83
}
84
85
function is_submittable(): boolean {
86
return !!(password !== "" && email_address !== email_address0);
87
}
88
89
function render_error() {
90
if (error) {
91
return (
92
<ErrorDisplay
93
error={error}
94
onClose={() => setError("")}
95
style={{ marginTop: "15px" }}
96
/>
97
);
98
}
99
}
100
101
function render_edit() {
102
const password_label = intl.formatMessage(
103
{
104
id: "account.settings.email_address.password_label",
105
defaultMessage:
106
"{have_email, select, true {Current password} other {Choose a password}}",
107
},
108
{
109
have_email: !!email_address,
110
},
111
);
112
return (
113
<Card style={{ marginTop: "3ex" }}>
114
<div style={{ marginBottom: "15px" }}>
115
<FormattedMessage
116
id="account.settings.email_address.new_email_address_label"
117
defaultMessage="New email address"
118
/>
119
<Input
120
autoFocus
121
placeholder="[email protected]"
122
onChange={(e) => {
123
set_email_address(e.target.value);
124
}}
125
maxLength={254}
126
/>
127
</div>
128
{password_label}
129
<Input.Password
130
value={password}
131
placeholder={password_label}
132
onChange={(e) => {
133
const pw = e.target.value;
134
if (pw != null) {
135
setPassword(pw);
136
}
137
}}
138
onPressEnter={() => {
139
if (is_submittable()) {
140
return save_editing();
141
}
142
}}
143
/>
144
<Space style={{ marginTop: "15px" }}>
145
<Button onClick={cancel_editing}>Cancel</Button>
146
<Button
147
disabled={!is_submittable()}
148
onClick={save_editing}
149
type="primary"
150
>
151
{button_label()}
152
</Button>
153
</Space>
154
{render_error()}
155
{render_saving()}
156
</Card>
157
);
158
}
159
160
function render_saving() {
161
if (state === "saving") {
162
return <Saving />;
163
}
164
}
165
166
function button_label(): string {
167
return intl.formatMessage(
168
{
169
id: "account.settings.email_address.button_label",
170
defaultMessage: `{type, select,
171
anonymous {Sign up using an email address and password}
172
have_email {Change email address}
173
other {Set email address and password}}`,
174
},
175
{
176
type: is_anonymous ? "anonymous" : email_address ? "have_email" : "",
177
},
178
);
179
}
180
181
const label = is_anonymous ? (
182
<h5 style={{ color: COLORS.GRAY_M }}>
183
Sign up using an email address and password
184
</h5>
185
) : (
186
intl.formatMessage(labels.email_address)
187
);
188
189
return (
190
<LabeledRow
191
label={label}
192
style={disabled ? { color: COLORS.GRAY_M } : undefined}
193
>
194
<div>
195
{email_address}
196
{state === "view" ? (
197
<Button
198
disabled={disabled}
199
className="pull-right"
200
onClick={start_editing}
201
>
202
{button_label()}...
203
</Button>
204
) : undefined}
205
</div>
206
{state !== "view" ? render_edit() : undefined}
207
</LabeledRow>
208
);
209
};
210
211