React -> Upgrade forms & simple fixes
parent
d7bc10f938
commit
9e5fe8790b
|
|
@ -13,15 +13,15 @@ export const FormGenerator = ({
|
||||||
|
|
||||||
const handler = async (event) => {
|
const handler = async (event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
for ( let i = 0; i < refList.length; i++ ) {
|
for (let i = 0; i < refList.length; i++) {
|
||||||
if (
|
if (refList[i].current.value === ''
|
||||||
refList[i].current.value === ''
|
|
||||||
&& inputList[0].action !== 'Update'
|
&& inputList[0].action !== 'Update'
|
||||||
|| i === 0 && refList.length !== 1
|
|| i === 0
|
||||||
|
&& refList.length !== 1
|
||||||
) {
|
) {
|
||||||
refList[i].current.focus()
|
refList[i].current.focus()
|
||||||
} else if ( i === refList.length - 1 ) {
|
} else if (i === refList.length - 1) {
|
||||||
await action( refList )
|
await action(refList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,32 +29,42 @@ export const FormGenerator = ({
|
||||||
let info
|
let info
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={ event => handler( event ) }>
|
<form onSubmit={event => handler(event)}>
|
||||||
{
|
{
|
||||||
inputList.map( (input, key) => {
|
inputList.map((input, key) => {
|
||||||
|
|
||||||
if ( input.type === 'info' ) {
|
if (input.type === 'info') {
|
||||||
info = input
|
info = input
|
||||||
} else if ( input.type === 'text' ) {
|
} else if (input.type === 'text') {
|
||||||
return (
|
return (
|
||||||
<TextInputGenerator
|
<TextInputGenerator
|
||||||
input={ input }
|
input={input}
|
||||||
info={ info }
|
info={info}
|
||||||
key={ key }
|
key={key}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
} else if ( input.type === 'file' ) {
|
} else if (input.type === 'password') {
|
||||||
|
return (
|
||||||
|
<PasswordInputGenerator
|
||||||
|
input={input}
|
||||||
|
info={info}
|
||||||
|
key={key}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
} else if (input.type === 'file') {
|
||||||
return (
|
return (
|
||||||
<UploadInputGenerator
|
<UploadInputGenerator
|
||||||
input={ input }
|
input={input}
|
||||||
info={ info }
|
info={info}
|
||||||
key={ key }
|
key={key}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
<button type='submit' />
|
<button type='submit'>
|
||||||
|
{ info.button_value }
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -79,11 +89,42 @@ const TextInputGenerator = ({
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{ input.name + ':' }
|
{input.name + ':'}
|
||||||
<input
|
<input
|
||||||
id={ input.name + info.action + info.endpoint + 'Input' }
|
id={input.name + info.action + info.endpoint + 'Input'}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
ref={ input.ref }
|
ref={input.ref}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text input generator, example:
|
||||||
|
* @param {
|
||||||
|
* {
|
||||||
|
* type: 'password',
|
||||||
|
* name: 'name',
|
||||||
|
* ref: React.createRef()
|
||||||
|
* } } input - basic text input
|
||||||
|
* @param {
|
||||||
|
* {
|
||||||
|
* type: 'info',
|
||||||
|
* action: 'Update'
|
||||||
|
* endpoint: 'Album'
|
||||||
|
* } } info - information about form
|
||||||
|
*/
|
||||||
|
const PasswordInputGenerator = ({
|
||||||
|
input, info
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{input.name + ':'}
|
||||||
|
<input
|
||||||
|
id={input.name + info.action + info.endpoint + 'Input'}
|
||||||
|
autoComplete='off'
|
||||||
|
ref={input.ref}
|
||||||
|
type='password'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
@ -105,26 +146,26 @@ const UploadInputGenerator = ({
|
||||||
input, info
|
input, info
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const onLoadFile = async ( event ) => {
|
const onLoadFile = async (event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
let data = event.target.files[0]
|
let data = event.target.files[0]
|
||||||
input.setFile( await toBase64( data ) )
|
input.setFile(await toBase64(data))
|
||||||
setDropInfos(data.name, data.size)
|
setDropInfos(data.name, data.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onLoadFileDrop = async ( event ) => {
|
const onLoadFileDrop = async (event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.persist()
|
event.persist()
|
||||||
let data = event.dataTransfer.files[0]
|
let data = event.dataTransfer.files[0]
|
||||||
input.setFile( await toBase64( data ) )
|
input.setFile(await toBase64(data))
|
||||||
setDropInfos(data.name, data.size)
|
setDropInfos(data.name, data.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
const toBase64 = ( file ) => new Promise( (resolve, reject) => {
|
const toBase64 = (file) => new Promise((resolve, reject) => {
|
||||||
let fileReader = new FileReader()
|
let fileReader = new FileReader()
|
||||||
fileReader.readAsDataURL( file )
|
fileReader.readAsDataURL(file)
|
||||||
fileReader.onload = () => resolve( fileReader.result )
|
fileReader.onload = () => resolve(fileReader.result)
|
||||||
fileReader.onerror = error => reject( error )
|
fileReader.onerror = error => reject(error)
|
||||||
})
|
})
|
||||||
|
|
||||||
const setDropInfos = (name, size) => {
|
const setDropInfos = (name, size) => {
|
||||||
|
|
@ -132,24 +173,24 @@ const UploadInputGenerator = ({
|
||||||
'name: "'
|
'name: "'
|
||||||
+ name
|
+ name
|
||||||
+ '"\nsize: '
|
+ '"\nsize: '
|
||||||
+ (Math.round(size / 100 + 'e-2') / 100 )
|
+ (Math.round(size / 100 + 'e-2') / 100)
|
||||||
+ ' MB'
|
+ ' MB'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div onDrop={ event => onLoadFileDrop( event ) } >
|
<div onDrop={event => onLoadFileDrop(event)} >
|
||||||
<pre style={ {marginTop: '25px', marginLeft: '40px'} }>
|
<pre style={{ marginTop: '25px', marginLeft: '40px' }}>
|
||||||
{ input.dropInfo }
|
{input.dropInfo}
|
||||||
</pre>
|
</pre>
|
||||||
<input
|
<input
|
||||||
style={ { marginTop: '-55px' } }
|
style={{ marginTop: '-55px' }}
|
||||||
id={ input.name + info.action + info.endpoint + 'Input' }
|
id={input.name + info.action + info.endpoint + 'Input'}
|
||||||
className='uploadInput'
|
className='uploadInput'
|
||||||
type='file'
|
type='file'
|
||||||
accept={ input.fileType + '/*' }
|
accept={input.fileType + '/*'}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
onChange={ event => onLoadFile( event ) }
|
onChange={event => onLoadFile(event)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
import { useSelector, useDispatch } from 'react-redux'
|
||||||
|
|
||||||
|
import { userAuthSelector } from '../../../redux/slices/userAuthSlice'
|
||||||
|
import userAuthAsyncThunk from '../../../redux/asyncThunks/userAuthAsyncThunk'
|
||||||
|
|
||||||
|
import FormGenerator from '../formGenerator'
|
||||||
|
|
||||||
|
|
||||||
|
const UserLoginForm = () => {
|
||||||
|
|
||||||
|
const usernameInput = React.createRef()
|
||||||
|
const passwordInput = React.createRef()
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
let refList = [
|
||||||
|
usernameInput,
|
||||||
|
passwordInput
|
||||||
|
]
|
||||||
|
|
||||||
|
let inputList = [
|
||||||
|
{
|
||||||
|
type: 'info',
|
||||||
|
action: 'Create',
|
||||||
|
endpint: 'user/auth/login',
|
||||||
|
button_value: 'Sign In'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'Username',
|
||||||
|
ref: usernameInput
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'password',
|
||||||
|
name: 'Password',
|
||||||
|
ref: passwordInput
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const login = async ( refs ) => {
|
||||||
|
let pass = {
|
||||||
|
username: refs[0].current.value,
|
||||||
|
password: refs[1].current.value
|
||||||
|
}
|
||||||
|
dispatch(
|
||||||
|
userAuthAsyncThunk.fetchLogin(
|
||||||
|
pass
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FormGenerator
|
||||||
|
inputList={ inputList }
|
||||||
|
refList={ refList }
|
||||||
|
action={ login }
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserLoginForm
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
import { useSelector, useDispatch } from 'react-redux'
|
||||||
|
|
||||||
|
import { userCrudSelector } from '../../../redux/slices/userCrudSlice'
|
||||||
|
import userCrudAsyncThunk from '../../../redux/asyncThunks/userCrudAsyncThunk'
|
||||||
|
|
||||||
|
import FormGenerator from '../formGenerator'
|
||||||
|
|
||||||
|
|
||||||
|
const UserRegisterForm = () => {
|
||||||
|
|
||||||
|
const usernameInput = React.createRef()
|
||||||
|
const passwordInput = React.createRef()
|
||||||
|
const emailInput = React.createRef()
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
let refList = [
|
||||||
|
usernameInput,
|
||||||
|
passwordInput,
|
||||||
|
emailInput
|
||||||
|
]
|
||||||
|
|
||||||
|
let inputList = [
|
||||||
|
{
|
||||||
|
type: 'info',
|
||||||
|
action: 'Create',
|
||||||
|
endpint: 'user/auth/login',
|
||||||
|
button_value: 'Sign In'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'Username',
|
||||||
|
ref: usernameInput
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'password',
|
||||||
|
name: 'Password',
|
||||||
|
ref: passwordInput
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'Email',
|
||||||
|
ref: emailInput
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const register = async ( refs ) => {
|
||||||
|
let pass = {
|
||||||
|
username: refs[0].current.value,
|
||||||
|
password: refs[1].current.value,
|
||||||
|
email: refs[2].current.value,
|
||||||
|
}
|
||||||
|
dispatch(
|
||||||
|
userCrudAsyncThunk.fetchRegister(
|
||||||
|
pass
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FormGenerator
|
||||||
|
inputList={ inputList }
|
||||||
|
refList={ refList }
|
||||||
|
action={ register }
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserRegisterForm
|
||||||
|
|
@ -80,7 +80,7 @@ const __verifyUserSession = (token, user) => {
|
||||||
if ( user.id !== 0 && user.username !== '' && user.email !== '' && token !== '' )
|
if ( user.id !== 0 && user.username !== '' && user.email !== '' && token !== '' )
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return true
|
return false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
import UserLoginForm from '../../../components/forms/user_auth/userLogin'
|
||||||
|
|
||||||
|
|
||||||
const UserAuthIndex = () => {
|
const UserAuthIndex = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<UserLoginForm />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,31 +74,53 @@ const responseAbstract = async (endpoint, method, token, body) => {
|
||||||
|
|
||||||
const headerBuilder = (url, method, token, body) => {
|
const headerBuilder = (url, method, token, body) => {
|
||||||
let headers_r = {
|
let headers_r = {
|
||||||
'Authorization': token,
|
'authorization': token,
|
||||||
|
'x-csrftoken': getCookie('csrftoken'),
|
||||||
'accept': 'application/json',
|
'accept': 'application/json',
|
||||||
'Content-Type': 'application/json',
|
'content-type': 'application/json',
|
||||||
}
|
}
|
||||||
if ('file' in body) {
|
if ('file' in body) {
|
||||||
headers_r = {
|
headers_r = {
|
||||||
'Authorization': token,
|
'authorization': token,
|
||||||
|
'x-csrftoken': getCookie('csrftoken'),
|
||||||
'accept': 'multipart/form-data',
|
'accept': 'multipart/form-data',
|
||||||
'Content-Type': 'multipart/form-data',
|
'content-type': 'multipart/form-data',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let headers = {
|
let headers = {
|
||||||
url: url,
|
url: url,
|
||||||
method: method,
|
method: method,
|
||||||
headers: headers_r
|
headers: headers_r,
|
||||||
|
credentials: 'same-origin'
|
||||||
}
|
}
|
||||||
if (method === 'PUT' || method === 'POST' || method === 'PATCH') {
|
if (method === 'PUT' || method === 'POST' || method === 'PATCH') {
|
||||||
headers = Object.assign({}, headers, {
|
headers = Object.assign({}, headers, {
|
||||||
data: JSON.stringify(body),
|
data: JSON.stringify(body),
|
||||||
withCredentials: true,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
console.log(headers)
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get cookie method for CSRF verification
|
||||||
|
* @param {string} name - name of handled cookie
|
||||||
|
*/
|
||||||
|
const getCookie = (name) => {
|
||||||
|
if (!document.cookie) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const token = document.cookie.split(';')
|
||||||
|
.map(c => c.trim())
|
||||||
|
.filter(c => c.startsWith(name + '='));
|
||||||
|
|
||||||
|
if (token.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return decodeURIComponent(token[0].split('=')[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
APIAddress,
|
APIAddress,
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,15 @@ const userAuthSlice = createSlice(
|
||||||
reducers: {},
|
reducers: {},
|
||||||
extraReducers: {
|
extraReducers: {
|
||||||
[userAuthAsyncThunk.fetchLogin.fulfilled.type]: (state, action) => {
|
[userAuthAsyncThunk.fetchLogin.fulfilled.type]: (state, action) => {
|
||||||
|
try {
|
||||||
state.token = action.payload.data.Authorization
|
state.token = action.payload.data.Authorization
|
||||||
state.user.id = action.payload.data.user.id
|
state.user.id = action.payload.data.user.id
|
||||||
state.user.username = action.payload.data.user.username
|
state.user.username = action.payload.data.user.username
|
||||||
state.user.email = action.payload.data.user.email
|
state.user.email = action.payload.data.user.email
|
||||||
state.info = 'login success'
|
state.info = 'login success'
|
||||||
|
} catch {
|
||||||
|
state.info = 'login failed'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[userAuthAsyncThunk.fetchLogout.fulfilled.type]: (state, action) => {
|
[userAuthAsyncThunk.fetchLogout.fulfilled.type]: (state, action) => {
|
||||||
state.token = ''
|
state.token = ''
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue