Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/frontend/account/profile-image.tsx
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import gravatarUrl from "./gravatar-url";6import { Button, Well } from "@cocalc/frontend/antd-bootstrap";7import { Component, Rendered } from "@cocalc/frontend/app-framework";8import { ErrorDisplay, Loading } from "@cocalc/frontend/components";9import { webapp_client } from "@cocalc/frontend/webapp-client";10import type { AccountState } from "./types";11import UploadProfileImage from "./upload-profile-image";1213interface ProfileImageSelectorProps {14profile: AccountState["profile"];15account_id: string;16email_address: string | undefined;17}1819interface ProfileImageSelectorState {20crop;21is_loading?: boolean;22error?: any;23show_default_explanation?: boolean;24show_gravatar_explanation?: boolean;25}2627export async function setProfile({ account_id, profile }) {28await webapp_client.async_query({29query: {30accounts: { account_id, profile },31},32});33}3435export class ProfileImageSelector extends Component<36ProfileImageSelectorProps,37ProfileImageSelectorState38> {39private is_mounted: boolean = true;4041constructor(props: ProfileImageSelectorProps, context: any) {42super(props, context);43this.state = {44crop: {45unit: "%",46width: 100,47aspect: 1,48},49};50}5152componentWillUnmount() {53this.is_mounted = false;54}5556set_image = async (src: string) => {57this.setState({ is_loading: true });58try {59await setProfile({60account_id: this.props.account_id,61profile: { image: src },62});63} catch (err) {64if (this.is_mounted) {65this.setState({ error: `${err}` });66}67} finally {68if (this.is_mounted) {69this.setState({ is_loading: false });70}71}72};7374handle_gravatar_click = () => {75if (!this.props.email_address) {76// Should not be necessary, but to make typescript happy.77return;78}79this.set_image(gravatarUrl(this.props.email_address));80};8182handle_default_click = () => this.set_image("");8384render_options_gravatar() {85if (!this.props.email_address) {86return;87}88return (89<>90<Button91style={{ marginTop: "5px" }}92onClick={this.handle_gravatar_click}93>94Gravatar95</Button>{" "}96<a97href="#"98onClick={(e) => {99e.preventDefault();100this.setState({ show_gravatar_explanation: true });101}}102>103What is this?104</a>105{this.state.show_gravatar_explanation ? (106<Well style={{ marginTop: "10px", marginBottom: "10px" }}>107Gravatar is a service for using a common avatar across websites. Go108to the{" "}109<a href="https://en.gravatar.com" target="_blank" rel="noopener">110Wordpress Gravatar site111</a>{" "}112and sign in (or create an account) using {this.props.email_address}.113<br />114<br />115<Button116onClick={() =>117this.setState({ show_gravatar_explanation: false })118}119>120Close121</Button>122</Well>123) : (124<br />125)}126</>127);128}129130render_options() {131return (132<>133<Button134style={{ marginTop: "5px" }}135onClick={this.handle_default_click}136>137Default138</Button>{" "}139<a140href="#"141onClick={(e) => {142e.preventDefault();143this.setState({ show_default_explanation: true });144}}145>146What is this?147</a>148{this.state.show_default_explanation ? (149<Well style={{ marginTop: "10px", marginBottom: "10px" }}>150The default avatar is a circle with the first letter of your name.151<br />152<br />153<Button154onClick={() => this.setState({ show_default_explanation: false })}155>156Close157</Button>158</Well>159) : (160<br />161)}162<div style={{ margin: "15px 0" }}>163<UploadProfileImage164account_id={this.props.account_id}165onChange={(data) => {166this.set_image(data);167}}168/>169</div>170{this.render_options_gravatar()}171</>172);173}174175render_loading() {176return (177<div>178Saving... <Loading />179</div>180);181}182183render_error(): Rendered {184if (this.state.error == null) {185return;186}187return (188<ErrorDisplay189error={this.state.error}190onClose={() => this.setState({ error: undefined })}191/>192);193}194195render() {196if (this.state.is_loading) {197return this.render_loading();198}199return (200<>201{this.render_error()}202<br />203{this.render_options()}204</>205);206}207}208209210