mirror of
https://git.vectorsigma.ru/public/photoview.git
synced 2026-08-03 21:09:05 +00:00
Redesign for initial setup wizard
This commit is contained in:
@@ -1,13 +1,15 @@
|
|||||||
import React, { useState } from 'react'
|
import React from 'react'
|
||||||
import { gql, useQuery, useMutation } from '@apollo/client'
|
import { gql, useQuery, useMutation } from '@apollo/client'
|
||||||
import { Redirect } from 'react-router-dom'
|
import { Redirect } from 'react-router-dom'
|
||||||
import { Button, Form, Message, Header } from 'semantic-ui-react'
|
|
||||||
import { Container } from './loginUtilities'
|
import { Container } from './loginUtilities'
|
||||||
|
|
||||||
import { checkInitialSetupQuery, login } from './loginUtilities'
|
import { checkInitialSetupQuery, login } from './loginUtilities'
|
||||||
import { authToken } from '../../helpers/authentication'
|
import { authToken } from '../../helpers/authentication'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { CheckInitialSetup } from './__generated__/CheckInitialSetup'
|
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`
|
const initialSetupMutation = gql`
|
||||||
mutation InitialSetup(
|
mutation InitialSetup(
|
||||||
@@ -27,14 +29,26 @@ const initialSetupMutation = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
type InitialSetupFormData = {
|
||||||
|
username: string
|
||||||
|
password: string
|
||||||
|
rootPath: string
|
||||||
|
}
|
||||||
|
|
||||||
const InitialSetupPage = () => {
|
const InitialSetupPage = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const {
|
||||||
username: '',
|
register,
|
||||||
password: '',
|
handleSubmit,
|
||||||
rootPath: '',
|
formState: { errors: formErrors },
|
||||||
})
|
} = useForm<InitialSetupFormData>()
|
||||||
|
|
||||||
|
// const [state, setState] = useState({
|
||||||
|
// username: '',
|
||||||
|
// password: '',
|
||||||
|
// rootPath: '',
|
||||||
|
// })
|
||||||
|
|
||||||
if (authToken()) {
|
if (authToken()) {
|
||||||
return <Redirect to="/" />
|
return <Redirect to="/" />
|
||||||
@@ -48,41 +62,37 @@ const InitialSetupPage = () => {
|
|||||||
<Redirect to="/" />
|
<Redirect to="/" />
|
||||||
)
|
)
|
||||||
|
|
||||||
const [
|
const [authorize, { loading: authorizeLoading, data: authorizationData }] =
|
||||||
authorize,
|
useMutation(initialSetupMutation, {
|
||||||
{ loading: authorizeLoading, data: authorizationData },
|
onCompleted: data => {
|
||||||
] = useMutation(initialSetupMutation, {
|
const { success, token } = data.initialSetupWizard
|
||||||
onCompleted: data => {
|
|
||||||
const { success, token } = data.initialSetupWizard
|
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
login(token)
|
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,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
// 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
|
let errorMessage = null
|
||||||
if (authorizationData && !authorizationData.initialSetupWizard.success) {
|
if (authorizationData && !authorizationData.initialSetupWizard.success) {
|
||||||
@@ -93,49 +103,59 @@ const InitialSetupPage = () => {
|
|||||||
<div>
|
<div>
|
||||||
{initialSetupRedirect}
|
{initialSetupRedirect}
|
||||||
<Container>
|
<Container>
|
||||||
<Header as="h1" textAlign="center">
|
<h1 className="text-center text-xl">
|
||||||
{t('login_page.initial_setup.title', 'Initial Setup')}
|
{t('login_page.initial_setup.title', 'Initial Setup')}
|
||||||
</Header>
|
</h1>
|
||||||
<Form
|
<form onSubmit={signIn} className="max-w-[500px] mx-auto">
|
||||||
style={{ width: 500, margin: 'auto' }}
|
<TextField
|
||||||
error={!!errorMessage}
|
wrapperClassName="my-4"
|
||||||
onSubmit={signIn}
|
fullWidth
|
||||||
loading={
|
{...register('username', { required: true })}
|
||||||
authorizeLoading || authorizationData?.initialSetupWizard?.success
|
label={t('login_page.field.username', 'Username')}
|
||||||
}
|
error={
|
||||||
>
|
formErrors.username?.type == 'required'
|
||||||
<Form.Field>
|
? 'Please enter a username'
|
||||||
<label>{t('login_page.field.username', 'Username')}</label>
|
: undefined
|
||||||
<input onChange={e => handleChange(e, 'username')} />
|
}
|
||||||
</Form.Field>
|
/>
|
||||||
<Form.Field>
|
<TextField
|
||||||
<label>{t('login_page.field.password', 'Password')}</label>
|
wrapperClassName="my-4"
|
||||||
<input
|
fullWidth
|
||||||
type="password"
|
{...register('password', { required: true })}
|
||||||
onChange={e => handleChange(e, 'password')}
|
label={t('login_page.field.password', 'Password')}
|
||||||
/>
|
error={
|
||||||
</Form.Field>
|
formErrors.password?.type == 'required'
|
||||||
<Form.Field>
|
? 'Please enter a password'
|
||||||
<label>
|
: undefined
|
||||||
{t(
|
}
|
||||||
'login_page.initial_setup.field.photo_path.label',
|
/>
|
||||||
'Photo path'
|
<TextField
|
||||||
)}
|
wrapperClassName="my-4"
|
||||||
</label>
|
fullWidth
|
||||||
<input
|
{...register('rootPath', { required: true })}
|
||||||
placeholder={t(
|
label={t(
|
||||||
'login_page.initial_setup.field.photo_path.placeholder',
|
'login_page.initial_setup.field.photo_path.label',
|
||||||
'/path/to/photos'
|
'Photo path'
|
||||||
)}
|
)}
|
||||||
type="text"
|
placeholder={t(
|
||||||
onChange={e => handleChange(e, 'rootPath')}
|
'login_page.initial_setup.field.photo_path.placeholder',
|
||||||
/>
|
'/path/to/photos'
|
||||||
</Form.Field>
|
)}
|
||||||
<Message error content={errorMessage} />
|
error={
|
||||||
<Button type="submit">
|
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')}
|
{t('login_page.initial_setup.field.submit', 'Setup Photoview')}
|
||||||
</Button>
|
</Submit>
|
||||||
</Form>
|
</form>
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const LogoHeader = () => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
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" />
|
<img className="h-24" src={logoPath} alt="photoview logo" />
|
||||||
<h1 className="text-3xl text-center mt-4">
|
<h1 className="text-3xl text-center mt-4">
|
||||||
{t('login_page.welcome', 'Welcome to Photoview')}
|
{t('login_page.welcome', 'Welcome to Photoview')}
|
||||||
@@ -73,13 +73,13 @@ const LoginForm = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
className="mx-auto max-w-[450px] px-4"
|
className="mx-auto max-w-[500px] px-4"
|
||||||
onSubmit={handleSubmit(onSubmit)}
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
// loading={loading || (data && data.authorizeUser.success)}
|
// loading={loading || (data && data.authorizeUser.success)}
|
||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
sizeVariant="big"
|
sizeVariant="big"
|
||||||
wrapperClassName="my-4"
|
wrapperClassName="my-6"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
label={t('login_page.field.username', 'Username')}
|
label={t('login_page.field.username', 'Username')}
|
||||||
{...register('username', { required: true })}
|
{...register('username', { required: true })}
|
||||||
@@ -91,7 +91,7 @@ const LoginForm = () => {
|
|||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
sizeVariant="big"
|
sizeVariant="big"
|
||||||
wrapperClassName="my-4"
|
wrapperClassName="my-6"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
type="password"
|
type="password"
|
||||||
label={t('login_page.field.password', 'Password')}
|
label={t('login_page.field.password', 'Password')}
|
||||||
@@ -106,7 +106,7 @@ const LoginForm = () => {
|
|||||||
type="submit"
|
type="submit"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
value={t('login_page.field.submit', 'Sign in') as string}
|
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
|
<MessageBox
|
||||||
message={errorMessage}
|
message={errorMessage}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { gql } from '@apollo/client'
|
import { gql } from '@apollo/client'
|
||||||
import { saveTokenCookie } from '../../helpers/authentication'
|
import { saveTokenCookie } from '../../helpers/authentication'
|
||||||
import styled from 'styled-components'
|
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`
|
export const checkInitialSetupQuery = gql`
|
||||||
query CheckInitialSetup {
|
query CheckInitialSetup {
|
||||||
@@ -16,6 +16,4 @@ export function login(token: string) {
|
|||||||
window.location.href = '/'
|
window.location.href = '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Container = styled(SemanticContainer)`
|
export const Container = styled.div.attrs({ className: 'mt-20' })``
|
||||||
margin-top: 80px;
|
|
||||||
`
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const TextField = forwardRef(
|
|||||||
let variant = 'bg-white border-gray-200 focus:border-blue-400'
|
let variant = 'bg-white border-gray-200 focus:border-blue-400'
|
||||||
if (error)
|
if (error)
|
||||||
variant =
|
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'
|
if (disabled) variant = 'bg-gray-100'
|
||||||
|
|
||||||
@@ -148,15 +148,21 @@ const buttonStyles = ({ variant, background }: ButtonProps) =>
|
|||||||
background == 'white' ? 'bg-white' : 'bg-gray-50'
|
background == 'white' ? 'bg-white' : 'bg-gray-50'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SubmitProps = ButtonProps & {
|
||||||
|
children: string
|
||||||
|
}
|
||||||
|
|
||||||
export const Submit = ({
|
export const Submit = ({
|
||||||
className,
|
className,
|
||||||
variant,
|
variant,
|
||||||
background,
|
background,
|
||||||
|
children,
|
||||||
...props
|
...props
|
||||||
}: ButtonProps & React.ButtonHTMLAttributes<HTMLInputElement>) => (
|
}: SubmitProps & React.ButtonHTMLAttributes<HTMLInputElement>) => (
|
||||||
<input
|
<input
|
||||||
className={classNames(buttonStyles({ variant, background }), className)}
|
className={classNames(buttonStyles({ variant, background }), className)}
|
||||||
type="submit"
|
type="submit"
|
||||||
|
value={children}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user