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/profile-image.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 gravatarUrl from "./gravatar-url";
7
import { Button, Well } from "@cocalc/frontend/antd-bootstrap";
8
import { Component, Rendered } from "@cocalc/frontend/app-framework";
9
import { ErrorDisplay, Loading } from "@cocalc/frontend/components";
10
import { webapp_client } from "@cocalc/frontend/webapp-client";
11
import type { AccountState } from "./types";
12
import UploadProfileImage from "./upload-profile-image";
13
14
interface ProfileImageSelectorProps {
15
profile: AccountState["profile"];
16
account_id: string;
17
email_address: string | undefined;
18
}
19
20
interface ProfileImageSelectorState {
21
crop;
22
is_loading?: boolean;
23
error?: any;
24
show_default_explanation?: boolean;
25
show_gravatar_explanation?: boolean;
26
}
27
28
export async function setProfile({ account_id, profile }) {
29
await webapp_client.async_query({
30
query: {
31
accounts: { account_id, profile },
32
},
33
});
34
}
35
36
export class ProfileImageSelector extends Component<
37
ProfileImageSelectorProps,
38
ProfileImageSelectorState
39
> {
40
private is_mounted: boolean = true;
41
42
constructor(props: ProfileImageSelectorProps, context: any) {
43
super(props, context);
44
this.state = {
45
crop: {
46
unit: "%",
47
width: 100,
48
aspect: 1,
49
},
50
};
51
}
52
53
componentWillUnmount() {
54
this.is_mounted = false;
55
}
56
57
set_image = async (src: string) => {
58
this.setState({ is_loading: true });
59
try {
60
await setProfile({
61
account_id: this.props.account_id,
62
profile: { image: src },
63
});
64
} catch (err) {
65
if (this.is_mounted) {
66
this.setState({ error: `${err}` });
67
}
68
} finally {
69
if (this.is_mounted) {
70
this.setState({ is_loading: false });
71
}
72
}
73
};
74
75
handle_gravatar_click = () => {
76
if (!this.props.email_address) {
77
// Should not be necessary, but to make typescript happy.
78
return;
79
}
80
this.set_image(gravatarUrl(this.props.email_address));
81
};
82
83
handle_default_click = () => this.set_image("");
84
85
render_options_gravatar() {
86
if (!this.props.email_address) {
87
return;
88
}
89
return (
90
<>
91
<Button
92
style={{ marginTop: "5px" }}
93
onClick={this.handle_gravatar_click}
94
>
95
Gravatar
96
</Button>{" "}
97
<a
98
href="#"
99
onClick={(e) => {
100
e.preventDefault();
101
this.setState({ show_gravatar_explanation: true });
102
}}
103
>
104
What is this?
105
</a>
106
{this.state.show_gravatar_explanation ? (
107
<Well style={{ marginTop: "10px", marginBottom: "10px" }}>
108
Gravatar is a service for using a common avatar across websites. Go
109
to the{" "}
110
<a href="https://en.gravatar.com" target="_blank" rel="noopener">
111
Wordpress Gravatar site
112
</a>{" "}
113
and sign in (or create an account) using {this.props.email_address}.
114
<br />
115
<br />
116
<Button
117
onClick={() =>
118
this.setState({ show_gravatar_explanation: false })
119
}
120
>
121
Close
122
</Button>
123
</Well>
124
) : (
125
<br />
126
)}
127
</>
128
);
129
}
130
131
render_options() {
132
return (
133
<>
134
<Button
135
style={{ marginTop: "5px" }}
136
onClick={this.handle_default_click}
137
>
138
Default
139
</Button>{" "}
140
<a
141
href="#"
142
onClick={(e) => {
143
e.preventDefault();
144
this.setState({ show_default_explanation: true });
145
}}
146
>
147
What is this?
148
</a>
149
{this.state.show_default_explanation ? (
150
<Well style={{ marginTop: "10px", marginBottom: "10px" }}>
151
The default avatar is a circle with the first letter of your name.
152
<br />
153
<br />
154
<Button
155
onClick={() => this.setState({ show_default_explanation: false })}
156
>
157
Close
158
</Button>
159
</Well>
160
) : (
161
<br />
162
)}
163
<div style={{ margin: "15px 0" }}>
164
<UploadProfileImage
165
account_id={this.props.account_id}
166
onChange={(data) => {
167
this.set_image(data);
168
}}
169
/>
170
</div>
171
{this.render_options_gravatar()}
172
</>
173
);
174
}
175
176
render_loading() {
177
return (
178
<div>
179
Saving... <Loading />
180
</div>
181
);
182
}
183
184
render_error(): Rendered {
185
if (this.state.error == null) {
186
return;
187
}
188
return (
189
<ErrorDisplay
190
error={this.state.error}
191
onClose={() => this.setState({ error: undefined })}
192
/>
193
);
194
}
195
196
render() {
197
if (this.state.is_loading) {
198
return this.render_loading();
199
}
200
return (
201
<>
202
{this.render_error()}
203
<br />
204
{this.render_options()}
205
</>
206
);
207
}
208
}
209
210