rendering field states in create screen

This commit is contained in:
balzack 2022-09-10 02:12:49 -07:00
parent 0f6963afd6
commit d437d206d1
5 changed files with 153 additions and 32 deletions

View File

@ -19,6 +19,10 @@ export function Create() {
} }
} }
const validServer = (state.server && state.serverChecked && state.serverValid);
const validToken = (!state.tokenRequired || (state.token && state.tokenChecked && state.tokenValid));
const validUsername = (state.username && state.usernameChecked && state.usernameValid);
return ( return (
<View style={styles.wrapper}> <View style={styles.wrapper}>
<View style={styles.container}> <View style={styles.container}>
@ -37,23 +41,51 @@ export function Create() {
<TextInput style={styles.inputfield} value={state.server} onChangeText={actions.setServer} <TextInput style={styles.inputfield} value={state.server} onChangeText={actions.setServer}
autoCapitalize="none" placeholder="server" /> autoCapitalize="none" placeholder="server" />
<View style={styles.space}> <View style={styles.space}>
<Text style={styles.required}></Text> { (!state.server || !state.serverChecked) && (
<Text style={styles.required}></Text>
)}
{ state.server && state.serverChecked && !state.serverValid && (
<Ionicons style={styles.icon} name="exclamationcircleo" size={18} color="#ff8888" />
)}
{ state.server && state.serverChecked && state.serverValid && (
<Ionicons style={styles.icon} name="checkcircleo" size={18} color="#448866" />
)}
</View> </View>
</View> </View>
{ state.tokenRequired && ( <View style={styles.token}>
<View style={styles.inputwrapper}> { state.tokenRequired && (
<Ionicons style={styles.icon} name="key" size={18} color="#888888" /> <View style={styles.inputwrapper}>
<TextInput style={styles.inputfield} value={state.token} onChangeText={actions.setToken} <Ionicons style={styles.icon} name="key" size={18} color="#888888" />
autoCapitalize="none" placeholder="token" /> <TextInput style={styles.inputfield} value={state.token} onChangeText={actions.setToken}
<View style={styles.space} /> autoCapitalize="none" placeholder="token" />
</View> <View style={styles.space}>
)} { (!validServer || !state.token || !state.tokenChecked) && (
<View style={styles.inputwrapperpad}> <Text style={styles.required}></Text>
)}
{ validServer && state.token && state.tokenChecked && !state.tokenValid && (
<Ionicons style={styles.icon} name="exclamationcircleo" size={18} color="#ff8888" />
)}
{ validServer && state.token && state.tokenChecked && state.tokenValid && (
<Ionicons style={styles.icon} name="checkcircleo" size={18} color="#448866" />
)}
</View>
</View>
)}
</View>
<View style={styles.inputwrapper}>
<Ionicons style={styles.icon} name="user" size={18} color="#888888" /> <Ionicons style={styles.icon} name="user" size={18} color="#888888" />
<TextInput style={styles.inputfield} value={state.username} onChangeText={actions.setUsername} <TextInput style={styles.inputfield} value={state.username} onChangeText={actions.setUsername}
autoCapitalize="none" placeholder="username" /> autoCapitalize="none" placeholder="username" />
<View style={styles.space}> <View style={styles.space}>
<Text style={styles.required}></Text> { (!validServer || !validToken || !state.username || !state.usernameChecked) && (
<Text style={styles.required}></Text>
)}
{ validServer && validToken && state.username && state.usernameChecked && !state.usernameValid && (
<Ionicons style={styles.icon} name="exclamationcircleo" size={18} color="#ff8888" />
)}
{ validServer && validToken && state.username && state.usernameChecked && state.usernameValid && (
<Ionicons style={styles.icon} name="checkcircleo" size={18} color="#448866" />
)}
</View> </View>
</View> </View>
{ state.showPassword && ( { state.showPassword && (

View File

@ -20,7 +20,7 @@ export const styles = StyleSheet.create({
}, },
required: { required: {
fontSize: 12, fontSize: 12,
color: Colors.alert, color: Colors.grey,
textAlignVertical: 'center', textAlignVertical: 'center',
}, },
container: { container: {
@ -31,6 +31,9 @@ export const styles = StyleSheet.create({
height: '100%', height: '100%',
display: 'flex', display: 'flex',
}, },
token: {
height: 52,
},
control: { control: {
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
@ -103,6 +106,7 @@ export const styles = StyleSheet.create({
height: 28, height: 28,
backgroundColor: Colors.primary, backgroundColor: Colors.primary,
borderRadius: 4, borderRadius: 4,
marginBottom: 16,
}, },
createtext: { createtext: {
color: Colors.formFocus, color: Colors.formFocus,
@ -122,14 +126,14 @@ export const styles = StyleSheet.create({
nocreatetext: { nocreatetext: {
color: Colors.disabled, color: Colors.disabled,
}, },
create: { login: {
marginTop: 16, marginTop: 16,
marginBottom: 16, marginBottom: 16,
}, },
createtext: { logintext: {
fontColor: 'yellow', fontColor: 'yellow',
}, },
nocreatetext: { nologintext: {
color: Colors.disabled, color: Colors.disabled,
}, },

View File

@ -2,6 +2,8 @@ import { useState, useEffect, useContext, useRef } from 'react';
import { useWindowDimensions } from 'react-native'; import { useWindowDimensions } from 'react-native';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { AppContext } from 'context/AppContext'; import { AppContext } from 'context/AppContext';
import { getAvailable } from 'api/getAvailable';
import { getUsername } from 'api/getUsername';
export function useCreate() { export function useCreate() {
@ -18,23 +20,26 @@ export function useCreate() {
confirm: null, confirm: null,
showPassword: false, showPassword: false,
showConfirm: false, showConfirm: false,
serverCheck: true, serverChecked: true,
serverValid: false, serverValid: false,
tokenRequired: false, tokenRequired: false,
usernameCheck: true, tokenChecked: true,
tokenValid: false,
usernameChecked: true,
usernameValid: false, usernameValid: false,
}); });
const debounceUsername = useRef(null); const debounce = useRef(null);
const debounceServer = useRef(null);
const updateState = (value) => { const updateState = (value) => {
setState((s) => ({ ...s, ...value })); setState((s) => ({ ...s, ...value }));
} }
useEffect(() => { useEffect(() => {
if (state.password && state.username && state.server && state.confirm && state.password === state.confirm) { if (state.usernameChecked && state.serverChecked && state.tokenChecked &&
state.password && state.username && state.server && state.confirm &&
(!state.tokenRequired || state.tokenValid) &&
state.serverValid && state.usernameValid && state.password === state.confirm) {
if (!state.enabled) { if (!state.enabled) {
updateState({ enabled: true }); updateState({ enabled: true });
} }
@ -44,20 +49,93 @@ export function useCreate() {
updateState({ enabled: false }); updateState({ enabled: false });
} }
} }
}, [state.login, state.password]); }, [state]);
const check = (server, token, username) => {
if (debounce.current) {
clearTimeout(debounce.current);
}
debounce.current = setTimeout(async () => {
debounce.current = null;
if (server) {
try {
const available = await getAvailable(server);
if (available) {
if (username) {
try {
const claimable = await getUsername(username, server, null);
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: false,
usernameValid: claimable, serverValid: true });
}
catch (err) {
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: false,
usernameValid: false, serverValid: true });
}
}
else {
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: false,
serverValid: true });
}
}
else {
if (token) {
try {
const accessible = await getUsername(null, server, token);
if (accessible) {
if (username) {
try {
const claimable = await getUsername(username, server, token);
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: true,
usernameValid: claimable, tokenValid: true, serverValid: true });
}
catch (err) {
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: true,
usernameValid: false, tokenValid: true, serverValid: true });
}
}
else {
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: true,
tokenValid: true, serverValid: true });
}
}
else {
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: true,
tokenValid: false, serverValid: true });
}
}
catch (err) {
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: true,
tokenValid: false, serverValid: true });
}
}
else {
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, tokenRequired: true,
serverValid: true });
}
}
}
catch (err) {
updateState({ usernameChecked: true, tokenChecked: true, serverChecked: true, serverValid: false });
}
}
}, 1000);
}
const actions = { const actions = {
config: () => { config: () => {
navigate('/admin'); navigate('/admin');
}, },
setServer: (server) => { setServer: (server) => {
updateState({ server }); updateState({ server, serverChecked: false });
check(server, state.token, state.username);
}, },
setToken: (token) => { setToken: (token) => {
updateState({ token }); updateState({ token, tokenChecked: false });
check(state.server, token, state.username);
}, },
setUsername: (username) => { setUsername: (username) => {
updateState({ username }); updateState({ username, usernameChecked: false });
check(state.server, state.token, username);
}, },
setPassword: (password) => { setPassword: (password) => {
updateState({ password }); updateState({ password });

View File

@ -1,7 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getAvailable() { export async function getAvailable(server) {
let available = await fetchWithTimeout("/account/available", { method: 'GET' }) let available = await fetchWithTimeout(`https://${server}/account/available`, { method: 'GET' })
checkResponse(available) checkResponse(available)
return await available.json() return await available.json()
} }

View File

@ -1,11 +1,18 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getUsername(name, token) { export async function getUsername(name, server, token) {
let access = ""; let query = "";
if (token) { if (token && name) {
access = `&token=${token}` query = `?name=${encodeURIComponent(name)}&token=${token}`;
} }
let available = await fetchWithTimeout('/account/username?name=' + encodeURIComponent(name) + access, { method: 'GET' }) else if (!token && name) {
query = `?name=${encodeURIComponent(name)}`
}
else if (token && !name) {
query = `?token=${token}`;
}
let available = await fetchWithTimeout(`https://${server}/account/username${query}`, { method: 'GET' })
checkResponse(available) checkResponse(available)
return await available.json() return await available.json()
} }