Path: blob/master/src/packages/frontend/account/settings/password-setting.tsx
5973 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { Form, Input } from "antd";6import { join } from "path";7import { useIntl } from "react-intl";89import { Button, ButtonToolbar, Well } from "@cocalc/frontend/antd-bootstrap";10import {11Rendered,12useIsMountedRef,13useState,14} from "@cocalc/frontend/app-framework";15import {16A,17ErrorDisplay,18LabeledRow,19Saving,20} from "@cocalc/frontend/components";21import { appBasePath } from "@cocalc/frontend/customize/app-base-path";22import { labels } from "@cocalc/frontend/i18n";23import { webapp_client } from "@cocalc/frontend/webapp-client";24import { MIN_PASSWORD_LENGTH } from "@cocalc/util/auth";2526interface State {27state: "view" | "edit" | "saving"; // view --> edit --> saving --> view28old_password: string;29new_password: string;30error: string;31}3233export const PasswordSetting: React.FC = () => {34const intl = useIntl();35const is_mounted = useIsMountedRef();3637const [state, set_state] = useState<State["state"]>("view");38const [old_password, set_old_password] = useState("");39const [new_password, set_new_password] = useState("");40const [error, set_error] = useState("");4142function reset(): void {43set_state("view");44set_error("");45set_old_password("");46set_new_password("");47}4849function change_password(): void {50reset();51set_state("edit");52}5354function cancel_editing(): void {55set_state("view");56set_old_password("");57set_new_password("");58}5960async function save_new_password(): Promise<void> {61set_state("saving");62try {63await webapp_client.account_client.change_password(64old_password,65new_password,66);67if (!is_mounted.current) return;68} catch (err) {69if (!is_mounted.current) return;70set_state("edit");71set_error(`Error changing password -- ${err}`);72return;73}74reset();75}7677function is_submittable(): boolean {78return !!(79new_password.length >= MIN_PASSWORD_LENGTH &&80new_password &&81new_password !== old_password82);83}8485function render_change_button(): Rendered {86if (is_submittable()) {87return (88<Button onClick={save_new_password} bsStyle="success">89{intl.formatMessage(labels.account_password_change)}90</Button>91);92} else {93return (94<Button disabled bsStyle="success">95{intl.formatMessage(labels.account_password_change)}96</Button>97);98}99}100101function render_error(): Rendered {102if (error) {103return (104<>105<ErrorDisplay106error={error}107onClose={() => set_error("")}108style={{ marginTop: "15px" }}109/>110<A href={join(appBasePath, "auth/password-reset")}>111{intl.formatMessage(labels.account_password_forgot)}112</A>113</>114);115}116}117118function onFinish(): void {119if (is_submittable()) {120save_new_password();121}122}123124function render_edit(): Rendered {125return (126<Well style={{ marginTop: "3ex" }}>127<Form onFinish={onFinish}>128<Form.Item>129Current password{" "}130<span color="#888">131(leave blank if you have not set a password)132</span>133<Input.Password134autoFocus135type="password"136value={old_password}137placeholder="Current password"138onChange={(e) => set_old_password(e.target.value)}139/>140</Form.Item>141New password142{new_password.length < MIN_PASSWORD_LENGTH143? ` (at least ${MIN_PASSWORD_LENGTH} characters)`144: undefined}145{new_password.length >= 6 && new_password == old_password146? " (different than old password)"147: undefined}148<Form.Item>149<Input.Password150type="password"151value={new_password}152placeholder="New password"153onChange={(e) => {154set_new_password(e.target.value);155}}156/>157</Form.Item>158</Form>159<ButtonToolbar>160{render_change_button()}161<Button onClick={cancel_editing}>Cancel</Button>162</ButtonToolbar>163{render_error()}164{render_saving()}165</Well>166);167}168169function render_saving(): Rendered {170if (state === "saving") {171return <Saving />;172}173}174175return (176<LabeledRow177label={intl.formatMessage(labels.account_password)}178style={{ marginBottom: "15px" }}179>180<div style={{ height: "30px" }}>181<Button182className="pull-right"183disabled={state !== "view"}184onClick={change_password}185>186{intl.formatMessage(labels.account_password_change)}...187</Button>188</div>189{state !== "view" ? render_edit() : undefined}190</LabeledRow>191);192};193194195