// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 import React from 'react'; import { useState, useEffect, useRef } from 'react'; import { CustomStyleRulesCallback } from 'common/custom-theme'; import { WithStyles } from '@mui/styles'; import withStyles from '@mui/styles/withStyles'; import CircularProgress from '@mui/material/CircularProgress'; import { Button, Card, CardContent, TextField, CardActions } from '@mui/material'; import { green } from '@mui/material/colors'; import { AxiosPromise } from 'axios'; import { DispatchProp } from 'react-redux'; import { saveApiToken } from 'store/auth/auth-action'; import { navigateToRootProject } from 'store/navigation/navigation-action'; import { replace } from 'react-router-redux'; import { PasswordLoginResponse } from 'views/login-panel/login-panel'; type CssRules = 'root' | 'loginBtn' | 'card' | 'wrapper' | 'progress'; const styles: CustomStyleRulesCallback = theme => ({ root: { display: 'flex', flexWrap: 'wrap', width: '100%', margin: `${theme.spacing(1)} auto` }, loginBtn: { marginTop: theme.spacing(1), flexGrow: 1 }, card: { marginTop: theme.spacing(1), width: '100%' }, wrapper: { margin: theme.spacing(1), position: 'relative', }, progress: { color: green[500], position: 'absolute', top: '50%', left: '50%', marginTop: -12, marginLeft: -12, }, }); type LoginFormProps = DispatchProp & WithStyles & { handleSubmit: (username: string, password: string) => AxiosPromise; loginLabel?: string, }; export const LoginForm = withStyles(styles)( ({ handleSubmit, loginLabel, dispatch, classes }: LoginFormProps) => { const userInput = useRef(null); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [isButtonDisabled, setIsButtonDisabled] = useState(true); const [isSubmitting, setSubmitting] = useState(false); const [helperText, setHelperText] = useState(''); const [error, setError] = useState(false); useEffect(() => { setError(false); setHelperText(''); if (username.trim() && password.trim()) { setIsButtonDisabled(false); } else { setIsButtonDisabled(true); } }, [username, password]); // This only runs once after render. useEffect(() => { setFocus(); }, []); const setFocus = () => { userInput.current!.focus(); }; const handleLogin = () => { setError(false); setHelperText(''); setSubmitting(true); handleSubmit(username, password) .then((response) => { setSubmitting(false); if (response.data.uuid && response.data.api_token) { const apiToken = `v2/${response.data.uuid}/${response.data.api_token}`; const rd = new URL(window.location.href); const rdUrl = rd.pathname + rd.search; dispatch(saveApiToken(apiToken)).finally( () => { if ((new URL(window.location.href).pathname) !== '/my-account') { rdUrl === '/' ? dispatch(navigateToRootProject) : dispatch(replace(rdUrl)) } } ); } else { setError(true); setHelperText(response.data.message || 'Please try again'); setFocus(); } }) .catch((err) => { setError(true); setSubmitting(false); setHelperText(`${(err.response && err.response.data && err.response.data.errors[0]) || 'Error logging in: ' + err}`); setFocus(); }); }; const handleKeyPress = (e: any) => { if (e.keyCode === 13 || e.which === 13) { if (!isButtonDisabled) { handleLogin(); } } }; return (
setUsername(e.target.value)} onKeyPress={(e) => handleKeyPress(e)} /> setPassword(e.target.value)} onKeyPress={(e) => handleKeyPress(e)} /> {isSubmitting && }
); });