1
Fork 0

Redesign for initial setup wizard

This commit is contained in:
viktorstrate 2021-07-17 17:14:35 +02:00
parent 029a5678a6
commit de685f28f5
No known key found for this signature in database
GPG Key ID: 3F855605109C1E8A
4 changed files with 115 additions and 91 deletions

View File

@ -1,13 +1,15 @@
import React, { useState } from 'react'
import React from 'react'
import { gql, useQuery, useMutation } from '@apollo/client'
import { Redirect } from 'react-router-dom'
import { Button, Form, Message, Header } from 'semantic-ui-react'
import { Container } from './loginUtilities'
import { checkInitialSetupQuery, login } from './loginUtilities'
import { authToken } from '../../helpers/authentication'
import { useTranslation } from 'react-i18next'
import { CheckInitialSetup } from './__generated__/CheckInitialSetup'
import { useForm } from 'react-hook-form'
import { Submit, TextField } from '../../primitives/form/Input'
import MessageBox from '../../primitives/form/MessageBox'
const initialSetupMutation = gql`
mutation InitialSetup(
@ -27,14 +29,26 @@ const initialSetupMutation = gql`
}
`
type InitialSetupFormData = {
username: string
password: string
rootPath: string
}
const InitialSetupPage = () => {
const { t } = useTranslation()
const [state, setState] = useState({
username: '',
password: '',
rootPath: '',
})
const {
register,
handleSubmit,
formState: { errors: formErrors },
} = useForm<InitialSetupFormData>()
// const [state, setState] = useState({
// username: '',
// password: '',
// rootPath: '',
// })
if (authToken()) {
return <Redirect to="/" />
@ -48,41 +62,37 @@ const InitialSetupPage = () => {
<Redirect to="/" />
)
const [
authorize,
{ loading: authorizeLoading, data: authorizationData },
] = useMutation(initialSetupMutation, {
onCompleted: data => {
const { success, token } = data.initialSetupWizard
const [authorize, { loading: authorizeLoading, data: authorizationData }] =
useMutation(initialSetupMutation, {
onCompleted: data => {
const { success, token } = data.initialSetupWizard
if (success) {
login(token)
}
},
})
const handleChange = (
event: React.ChangeEvent<HTMLInputElement>,
key: string
) => {
const value = event.target.value
setState(prevState => ({
...prevState,
[key]: value,
}))
}
const signIn = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault()
authorize({
variables: {
username: state.username,
password: state.password,
rootPath: state.rootPath,
if (success) {
login(token)
}
},
})
}
// const handleChange = (
// event: React.ChangeEvent<HTMLInputElement>,
// key: string
// ) => {
// const value = event.target.value
// setState(prevState => ({
// ...prevState,
// [key]: value,
// }))
// }
const signIn = handleSubmit(data => {
authorize({
variables: {
username: data.username,
password: data.password,
rootPath: data.rootPath,
},
})
})
let errorMessage = null
if (authorizationData && !authorizationData.initialSetupWizard.success) {
@ -93,49 +103,59 @@ const InitialSetupPage = () => {
<div>
{initialSetupRedirect}
<Container>
<Header as="h1" textAlign="center">
<h1 className="text-center text-xl">
{t('login_page.initial_setup.title', 'Initial Setup')}
</Header>
<Form
style={{ width: 500, margin: 'auto' }}
error={!!errorMessage}
onSubmit={signIn}
loading={
authorizeLoading || authorizationData?.initialSetupWizard?.success
}
>
<Form.Field>
<label>{t('login_page.field.username', 'Username')}</label>
<input onChange={e => handleChange(e, 'username')} />
</Form.Field>
<Form.Field>
<label>{t('login_page.field.password', 'Password')}</label>
<input
type="password"
onChange={e => handleChange(e, 'password')}
/>
</Form.Field>
<Form.Field>
<label>
{t(
'login_page.initial_setup.field.photo_path.label',
'Photo path'
)}
</label>
<input
placeholder={t(
'login_page.initial_setup.field.photo_path.placeholder',
'/path/to/photos'
)}
type="text"
onChange={e => handleChange(e, 'rootPath')}
/>
</Form.Field>
<Message error content={errorMessage} />
<Button type="submit">
</h1>
<form onSubmit={signIn} className="max-w-[500px] mx-auto">
<TextField
wrapperClassName="my-4"
fullWidth
{...register('username', { required: true })}
label={t('login_page.field.username', 'Username')}
error={
formErrors.username?.type == 'required'
? 'Please enter a username'
: undefined
}
/>
<TextField
wrapperClassName="my-4"
fullWidth
{...register('password', { required: true })}
label={t('login_page.field.password', 'Password')}
error={
formErrors.password?.type == 'required'
? 'Please enter a password'
: undefined
}
/>
<TextField
wrapperClassName="my-4"
fullWidth
{...register('rootPath', { required: true })}
label={t(
'login_page.initial_setup.field.photo_path.label',
'Photo path'
)}
placeholder={t(
'login_page.initial_setup.field.photo_path.placeholder',
'/path/to/photos'
)}
error={
formErrors.password?.type == 'required'
? 'Please enter a photo path'
: undefined
}
/>
<MessageBox
type="negative"
message={errorMessage}
show={errorMessage}
/>
<Submit className="mt-2" disabled={authorizeLoading}>
{t('login_page.initial_setup.field.submit', 'Setup Photoview')}
</Button>
</Form>
</Submit>
</form>
</Container>
</div>
)

View File

@ -27,7 +27,7 @@ const LogoHeader = () => {
const { t } = useTranslation()
return (
<div className="flex justify-center flex-col pb-20 pt-12">
<div className="flex justify-center flex-col mb-14 mt-20">
<img className="h-24" src={logoPath} alt="photoview logo" />
<h1 className="text-3xl text-center mt-4">
{t('login_page.welcome', 'Welcome to Photoview')}
@ -73,13 +73,13 @@ const LoginForm = () => {
return (
<form
className="mx-auto max-w-[450px] px-4"
className="mx-auto max-w-[500px] px-4"
onSubmit={handleSubmit(onSubmit)}
// loading={loading || (data && data.authorizeUser.success)}
>
<TextField
sizeVariant="big"
wrapperClassName="my-4"
wrapperClassName="my-6"
className="w-full"
label={t('login_page.field.username', 'Username')}
{...register('username', { required: true })}
@ -91,7 +91,7 @@ const LoginForm = () => {
/>
<TextField
sizeVariant="big"
wrapperClassName="my-4"
wrapperClassName="my-6"
className="w-full"
type="password"
label={t('login_page.field.password', 'Password')}
@ -106,7 +106,7 @@ const LoginForm = () => {
type="submit"
disabled={loading}
value={t('login_page.field.submit', 'Sign in') as string}
className="rounded-md px-8 py-2 mt-1 focus:outline-none cursor-pointer bg-gradient-to-bl from-[#FF8246] to-[#D6264D] text-white font-semibold focus:ring-2 focus:ring-red-200 disabled:cursor-default disabled:opacity-80"
className="rounded-md px-8 py-2 mt-2 focus:outline-none cursor-pointer bg-gradient-to-bl from-[#FF8246] to-[#D6264D] text-white font-semibold focus:ring-2 focus:ring-red-200 disabled:cursor-default disabled:opacity-80"
/>
<MessageBox
message={errorMessage}

View File

@ -1,7 +1,7 @@
import { gql } from '@apollo/client'
import { saveTokenCookie } from '../../helpers/authentication'
import styled from 'styled-components'
import { Container as SemanticContainer } from 'semantic-ui-react'
// import { Container as SemanticContainer } from 'semantic-ui-react'
export const checkInitialSetupQuery = gql`
query CheckInitialSetup {
@ -16,6 +16,4 @@ export function login(token: string) {
window.location.href = '/'
}
export const Container = styled(SemanticContainer)`
margin-top: 80px;
`
export const Container = styled.div.attrs({ className: 'mt-20' })``

View File

@ -37,7 +37,7 @@ export const TextField = forwardRef(
let variant = 'bg-white border-gray-200 focus:border-blue-400'
if (error)
variant =
'bg-red-50 border-red-200 focus:border-red-400 focus:ring-red-100'
'bg-red-50 border-red-200 focus:border-red-400 focus:ring-red-100 placeholder-red-300'
if (disabled) variant = 'bg-gray-100'
@ -148,15 +148,21 @@ const buttonStyles = ({ variant, background }: ButtonProps) =>
background == 'white' ? 'bg-white' : 'bg-gray-50'
)
type SubmitProps = ButtonProps & {
children: string
}
export const Submit = ({
className,
variant,
background,
children,
...props
}: ButtonProps & React.ButtonHTMLAttributes<HTMLInputElement>) => (
}: SubmitProps & React.ButtonHTMLAttributes<HTMLInputElement>) => (
<input
className={classNames(buttonStyles({ variant, background }), className)}
type="submit"
value={children}
{...props}
/>
)