mirror of
https://github.com/balzack/databag.git
synced 2025-02-14 12:39:17 +00:00
adding debounce and validation to login update
This commit is contained in:
parent
18716162cc
commit
4591759c2c
@ -39,7 +39,7 @@ export function Create() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="database" size={18} color="#888888" />
|
||||
<TextInput style={styles.inputfield} value={state.server} onChangeText={actions.setServer}
|
||||
autoCapitalize="none" placeholder="server" />
|
||||
autoCorrect={false} autoCapitalize="none" placeholder="server" />
|
||||
<View style={styles.space}>
|
||||
{ (!state.server || !state.serverChecked) && (
|
||||
<Text style={styles.required}>✻</Text>
|
||||
@ -57,7 +57,7 @@ export function Create() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="key" size={18} color="#888888" />
|
||||
<TextInput style={styles.inputfield} value={state.token} onChangeText={actions.setToken}
|
||||
autoCapitalize="none" placeholder="token" />
|
||||
autoCorrect={false} autoCapitalize="none" placeholder="token" />
|
||||
<View style={styles.space}>
|
||||
{ (!validServer || !state.token || !state.tokenChecked) && (
|
||||
<Text style={styles.required}>✻</Text>
|
||||
@ -75,7 +75,7 @@ export function Create() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="user" size={18} color="#888888" />
|
||||
<TextInput style={styles.inputfield} value={state.username} onChangeText={actions.setUsername}
|
||||
autoCapitalize="none" placeholder="username" />
|
||||
autoCorrect={false} autoCapitalize="none" placeholder="username" />
|
||||
<View style={styles.space}>
|
||||
{ (!validServer || !validToken || !state.username || !state.usernameChecked) && (
|
||||
<Text style={styles.required}>✻</Text>
|
||||
@ -92,7 +92,7 @@ export function Create() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="lock" size={18} color="#888888" />
|
||||
<TextInput style={styles.inputfield} value={state.password} onChangeText={actions.setPassword}
|
||||
autoCapitalize="none" placeholder="password" />
|
||||
autoCorrect={false} autoCapitalize="none" placeholder="password" />
|
||||
<TouchableOpacity onPress={actions.hidePassword}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
@ -102,7 +102,7 @@ export function Create() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="lock" size={18} color="#888888" />
|
||||
<TextInput style={styles.inputfield} value={state.password} onChangeText={actions.setPassword}
|
||||
secureTextEntry={true} autoCapitalize="none" placeholder="password" />
|
||||
autoCorrect={false} secureTextEntry={true} autoCapitalize="none" placeholder="password" />
|
||||
<TouchableOpacity onPress={actions.showPassword}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
@ -112,7 +112,7 @@ export function Create() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="lock" size={18} color="#888888" />
|
||||
<TextInput style={styles.inputfield} value={state.confirm} onChangeText={actions.setConfirm}
|
||||
autoCapitalize="none" placeholder="confirm password" />
|
||||
autoCorrect={false} autoCapitalize="none" placeholder="confirm password" />
|
||||
<TouchableOpacity onPress={actions.hideConfirm}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
@ -122,7 +122,7 @@ export function Create() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="lock" size={18} color="#888888" />
|
||||
<TextInput style={styles.inputfield} value={state.confirm} onChangeText={actions.setConfirm}
|
||||
secureTextEntry={true} autoCapitalize="none" placeholder="confirm password" />
|
||||
autoCorrect={false} secureTextEntry={true} autoCapitalize="none" placeholder="confirm password" />
|
||||
<TouchableOpacity onPress={actions.showConfirm}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
|
@ -35,14 +35,14 @@ export function Login() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="user" size={18} color="#aaaaaa" />
|
||||
<TextInput style={styles.inputfield} value={state.login} onChangeText={actions.setLogin}
|
||||
autoCapitalize="none" placeholder="username@server" />
|
||||
autoCorrect={false} autoCapitalize="none" placeholder="username@server" />
|
||||
<View style={styles.space} />
|
||||
</View>
|
||||
{ state.showPassword && (
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="lock" size={18} color="#aaaaaa" />
|
||||
<TextInput style={styles.inputfield} value={state.password} onChangeText={actions.setPassword}
|
||||
autoCapitalize="none" placeholder="password"/>
|
||||
autoCorrect={false} autoCapitalize="none" placeholder="password"/>
|
||||
<TouchableOpacity onPress={actions.hidePassword}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#aaaaaa" />
|
||||
</TouchableOpacity>
|
||||
@ -52,7 +52,7 @@ export function Login() {
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="lock" size={18} color="#aaaaaa" />
|
||||
<TextInput style={styles.inputfield} value={state.password} onChangeText={actions.setPassword}
|
||||
secureTextEntry={true} autoCapitalize="none" placeholder="password" />
|
||||
autoCorrect={false} secureTextEntry={true} autoCapitalize="none" placeholder="password" />
|
||||
<TouchableOpacity onPress={actions.showPassword}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#aaaaaa" />
|
||||
</TouchableOpacity>
|
||||
|
8
app/mobile/src/api/getHandle.js
Normal file
8
app/mobile/src/api/getHandle.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
|
||||
export async function getHandle(server, token, name) {
|
||||
let available = await fetchWithTimeout(`https://${server}/account/username?agent=${token}&name=${encodeURIComponent(name)}`, { method: 'GET' })
|
||||
checkResponse(available)
|
||||
return await available.json()
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { getProfile } from 'api/getProfile';
|
||||
import { setProfileData } from 'api/setProfileData';
|
||||
import { setProfileImage } from 'api/setProfileImage';
|
||||
import { getProfileImageUrl } from 'api/getProfileImageUrl';
|
||||
import { getHandle } from 'api/getHandle';
|
||||
import { StoreContext } from 'context/StoreContext';
|
||||
|
||||
export function useProfileContext() {
|
||||
@ -71,6 +72,10 @@ export function useProfileContext() {
|
||||
const { server, appToken } = session.current;
|
||||
await setProfileImage(server, appToken, image);
|
||||
},
|
||||
getHandle: async (name) => {
|
||||
const { server, appToken } = session.current;
|
||||
return await getHandle(server, appToken, name);
|
||||
},
|
||||
}
|
||||
|
||||
return { state, actions }
|
||||
|
@ -39,6 +39,17 @@ export function Profile() {
|
||||
}
|
||||
|
||||
const saveLogin = async () => {
|
||||
try {
|
||||
await actions.saveLogin();
|
||||
actions.hideLoginEdit();
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
Alert.alert(
|
||||
'Failed to Change Login',
|
||||
'Please try again.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const onGallery = async () => {
|
||||
@ -63,6 +74,8 @@ export function Profile() {
|
||||
}
|
||||
}
|
||||
|
||||
const enabled = (state.checked && state.available && state.editConfirm === state.editPassword && state.editPassword);
|
||||
|
||||
return (
|
||||
<ScrollView>
|
||||
<View style={styles.container}>
|
||||
@ -113,15 +126,15 @@ export function Profile() {
|
||||
<Text style={styles.editHeader}>Edit Details:</Text>
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editName} onChangeText={actions.setEditName}
|
||||
autoCapitalize="word" placeholder="Name" />
|
||||
autoCapitalize="words" placeholder="Name" />
|
||||
</View>
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editLocation} onChangeText={actions.setEditLocation}
|
||||
autoCapitalize="sentence" placeholder="Location" />
|
||||
autoCapitalize="words" placeholder="Location" />
|
||||
</View>
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editDescription} onChangeText={actions.setEditDescription}
|
||||
autoCapitalize="none" placeholder="Description" multiline={true} />
|
||||
autoCapitalize="sentences" placeholder="Description" multiline={true} />
|
||||
</View>
|
||||
<View style={styles.editControls}>
|
||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideDetailEdit}>
|
||||
@ -146,23 +159,64 @@ export function Profile() {
|
||||
<Text style={styles.editHeader}>Change Login:</Text>
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editHandle} onChangeText={actions.setEditHandle}
|
||||
placeholder="Username" />
|
||||
</View>
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editPassword} onChangeText={actions.setEditPassword}
|
||||
secureTextEntry={true} placeholder="Password" />
|
||||
</View>
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editConfirm} onChangeText={actions.setEditConfirm}
|
||||
secureTextEntry={true} placeholder="Confirm Password" />
|
||||
autoCapitalize={'none'} placeholder="Username" />
|
||||
{ state.checked && state.available && (
|
||||
<Ionicons style={styles.icon} name="checkcircleo" size={18} color={Colors.background} />
|
||||
)}
|
||||
{ state.checked && !state.available && (
|
||||
<Ionicons style={styles.icon} name="exclamationcircleo" size={18} color={Colors.alert} />
|
||||
)}
|
||||
</View>
|
||||
{ !state.showPassword && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editPassword} onChangeText={actions.setEditPassword}
|
||||
autoCapitalize={'none'} secureTextEntry={true} placeholder="Password" />
|
||||
<TouchableOpacity onPress={actions.showPassword}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{ state.showPassword && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editPassword} onChangeText={actions.setEditPassword}
|
||||
autoCapitalize={'none'} secureTextEntry={false} placeholder="Password" />
|
||||
<TouchableOpacity onPress={actions.hidePassword}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{ !state.showConfirm && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editConfirm} onChangeText={actions.setEditConfirm}
|
||||
autoCapitalize={'none'} secureTextEntry={true} placeholder="Confirm" />
|
||||
<TouchableOpacity onPress={actions.showConfirm}>
|
||||
<Ionicons style={styles.icon} name="eyeo" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{ state.showConfirm && (
|
||||
<View style={styles.inputField}>
|
||||
<TextInput style={styles.input} value={state.editConfirm} onChangeText={actions.setEditConfirm}
|
||||
autoCapitalize={'none'} secureTextEntry={false} placeholder="Confirm" />
|
||||
<TouchableOpacity onPress={actions.hideConfirm}>
|
||||
<Ionicons style={styles.icon} name="eye" size={18} color="#888888" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.editControls}>
|
||||
<TouchableOpacity style={styles.cancel} onPress={actions.hideLoginEdit}>
|
||||
<Text>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.save} onPress={saveLogin}>
|
||||
<Text style={styles.saveText}>Save</Text>
|
||||
</TouchableOpacity>
|
||||
{ enabled && (
|
||||
<TouchableOpacity style={styles.save} onPress={saveLogin}>
|
||||
<Text style={styles.saveText}>Save</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ !enabled && (
|
||||
<View style={styles.disabled}>
|
||||
<Text style={styles.disabledText}>Save</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -128,10 +128,12 @@ export const styles = StyleSheet.create({
|
||||
padding: 8,
|
||||
marginBottom: 8,
|
||||
maxHeight: 92,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
input: {
|
||||
fontSize: 16,
|
||||
width: '100%',
|
||||
flexGrow: 1,
|
||||
},
|
||||
editControls: {
|
||||
display: 'flex',
|
||||
@ -148,6 +150,18 @@ export const styles = StyleSheet.create({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
disabled: {
|
||||
borderWidth: 1,
|
||||
borderColor: Colors.lightgrey,
|
||||
padding: 8,
|
||||
borderRadius: 4,
|
||||
width: 72,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
disabledText: {
|
||||
color: Colors.disabled,
|
||||
},
|
||||
save: {
|
||||
padding: 8,
|
||||
borderRadius: 4,
|
||||
|
@ -22,12 +22,17 @@ export function useProfile() {
|
||||
editHandle: null,
|
||||
editPassword: null,
|
||||
editConfirm: null,
|
||||
checked: true,
|
||||
available: true,
|
||||
showPassword: false,
|
||||
showConfirm: false,
|
||||
});
|
||||
|
||||
const app = useContext(AppContext);
|
||||
const account = useContext(AccountContext);
|
||||
const profile = useContext(ProfileContext);
|
||||
const navigate = useNavigate();
|
||||
const debounce = useRef(null);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
@ -76,8 +81,38 @@ export function useProfile() {
|
||||
setEditDescription: (editDescription) => {
|
||||
updateState({ editDescription });
|
||||
},
|
||||
showPassword: () => {
|
||||
updateState({ showPassword: true });
|
||||
},
|
||||
hidePassword: () => {
|
||||
updateState({ showPassword: false });
|
||||
},
|
||||
showConfirm: () => {
|
||||
updateState({ showConfirm: true });
|
||||
},
|
||||
hideConfirm: () => {
|
||||
updateState({ showConfirm: false });
|
||||
},
|
||||
setEditHandle: (editHandle) => {
|
||||
updateState({ editHandle });
|
||||
updateState({ editHandle, checked: false });
|
||||
|
||||
if (debounce.current != null) {
|
||||
clearTimeout(debounce.current);
|
||||
}
|
||||
debounce.current = setTimeout(async () => {
|
||||
try {
|
||||
if (editHandle === state.handle) {
|
||||
updateState({ available: true, checked: true });
|
||||
}
|
||||
else {
|
||||
const available = await profile.actions.getHandle(editHandle);
|
||||
updateState({ available, checked: true });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
setEditPassword: (editPassword) => {
|
||||
updateState({ editPassword });
|
||||
@ -85,8 +120,11 @@ export function useProfile() {
|
||||
setEditConfirm: (editConfirm) => {
|
||||
updateState({ editConfirm });
|
||||
},
|
||||
saveDetails: () => {
|
||||
profile.actions.setProfileData(state.editName, state.editLocation, state.editDescription);
|
||||
saveDetails: async () => {
|
||||
await profile.actions.setProfileData(state.editName, state.editLocation, state.editDescription);
|
||||
},
|
||||
saveLogin: async () => {
|
||||
await account.actions.setLogin(state.editHandle, state.editPassword);
|
||||
},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user