import React, { useState, useCallback } from 'react' import PropTypes from 'prop-types' import { Field, Form } from 'react-final-form' import { useDispatch } from 'react-redux' import Button from '@material-ui/core/Button' import Card from '@material-ui/core/Card' import CardActions from '@material-ui/core/CardActions' import CircularProgress from '@material-ui/core/CircularProgress' import TextField from '@material-ui/core/TextField' import { createMuiTheme, makeStyles } from '@material-ui/core/styles' import { ThemeProvider } from '@material-ui/styles' import Logo from '../icons/android-icon-72x72.png' import { useLogin, useNotify, useTranslate } from 'react-admin' import Notification from './Notification' import LightTheme from '../themes/light' import config from '../config' import { clearQueue } from '../actions' const useStyles = makeStyles((theme) => ({ main: { display: 'flex', flexDirection: 'column', minHeight: '100vh', alignItems: 'center', justifyContent: 'flex-start', background: `url(${config.loginBackgroundURL})`, backgroundRepeat: 'no-repeat', backgroundSize: 'cover', backgroundPosition: 'center', }, card: { minWidth: 300, marginTop: '6em', }, avatar: { margin: '1em', display: 'flex', justifyContent: 'center', }, icon: { backgroundColor: 'white', width: '40px', }, systemName: { marginTop: '1em', display: 'flex', justifyContent: 'center', color: '#3f51b5', //theme.palette.grey[500] }, welcome: { marginTop: '1em', padding: '0 1em 1em 1em', display: 'flex', justifyContent: 'center', color: '#3f51b5', //theme.palette.grey[500] }, form: { padding: '0 1em 1em 1em', }, input: { marginTop: '1em', }, actions: { padding: '0 1em 1em 1em', }, })) const renderInput = ({ meta: { touched, error } = {}, input: { ...inputProps }, ...props }) => ( ) const FormLogin = ({ loading, handleSubmit, validate }) => { const translate = useTranslate() const classes = useStyles() return (
(
{'logo'}
Navidrome
{config.welcomeMessage && (
)}
)} /> ) } const FormSignUp = ({ loading, handleSubmit, validate }) => { const translate = useTranslate() const classes = useStyles() return (
(
{'logo'}
{translate('ra.auth.welcome1')}
{translate('ra.auth.welcome2')}
)} /> ) } const Login = ({ location }) => { const [loading, setLoading] = useState(false) const translate = useTranslate() const notify = useNotify() const login = useLogin() const dispatch = useDispatch() const handleSubmit = useCallback( (auth) => { setLoading(true) dispatch(clearQueue()) login(auth, location.state ? location.state.nextPathname : '/').catch( (error) => { setLoading(false) notify( typeof error === 'string' ? error : typeof error === 'undefined' || !error.message ? 'ra.auth.sign_in_error' : error.message, 'warning' ) } ) }, [dispatch, login, notify, setLoading, location] ) const validateLogin = useCallback( (values) => { const errors = {} if (!values.username) { errors.username = translate('ra.validation.required') } if (!values.password) { errors.password = translate('ra.validation.required') } return errors }, [translate] ) const validateSignup = useCallback( (values) => { const errors = validateLogin(values) const regex = /^\w+$/g if (values.username && !values.username.match(regex)) { errors.username = translate('ra.validation.invalidChars') } if (!values.confirmPassword) { errors.confirmPassword = translate('ra.validation.required') } if (values.confirmPassword !== values.password) { errors.confirmPassword = translate('ra.validation.passwordDoesNotMatch') } return errors }, [translate, validateLogin] ) if (config.firstTime) { return ( ) } return ( ) } Login.propTypes = { authProvider: PropTypes.func, previousRoute: PropTypes.string, } // We need to put the ThemeProvider decoration in another component // Because otherwise the useStyles() hook used in Login won't get // the right theme const LoginWithTheme = (props) => ( ) export default LoginWithTheme