From 4591759c2cf79afed4a3414b399d61166121c9ef Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Thu, 22 Sep 2022 12:23:49 -0700 Subject: [PATCH] adding debounce and validation to login update --- app/mobile/src/access/create/Create.jsx | 14 ++-- app/mobile/src/access/login/Login.jsx | 6 +- app/mobile/src/api/getHandle.js | 8 ++ .../src/context/useProfileContext.hook.js | 5 ++ app/mobile/src/session/profile/Profile.jsx | 84 +++++++++++++++---- .../src/session/profile/Profile.styled.js | 16 +++- .../src/session/profile/useProfile.hook.js | 44 +++++++++- 7 files changed, 148 insertions(+), 29 deletions(-) create mode 100644 app/mobile/src/api/getHandle.js diff --git a/app/mobile/src/access/create/Create.jsx b/app/mobile/src/access/create/Create.jsx index f6a22ac6..854bfc24 100644 --- a/app/mobile/src/access/create/Create.jsx +++ b/app/mobile/src/access/create/Create.jsx @@ -39,7 +39,7 @@ export function Create() { + autoCorrect={false} autoCapitalize="none" placeholder="server" /> { (!state.server || !state.serverChecked) && ( @@ -57,7 +57,7 @@ export function Create() { + autoCorrect={false} autoCapitalize="none" placeholder="token" /> { (!validServer || !state.token || !state.tokenChecked) && ( @@ -75,7 +75,7 @@ export function Create() { + autoCorrect={false} autoCapitalize="none" placeholder="username" /> { (!validServer || !validToken || !state.username || !state.usernameChecked) && ( @@ -92,7 +92,7 @@ export function Create() { + autoCorrect={false} autoCapitalize="none" placeholder="password" /> @@ -102,7 +102,7 @@ export function Create() { + autoCorrect={false} secureTextEntry={true} autoCapitalize="none" placeholder="password" /> @@ -112,7 +112,7 @@ export function Create() { + autoCorrect={false} autoCapitalize="none" placeholder="confirm password" /> @@ -122,7 +122,7 @@ export function Create() { + autoCorrect={false} secureTextEntry={true} autoCapitalize="none" placeholder="confirm password" /> diff --git a/app/mobile/src/access/login/Login.jsx b/app/mobile/src/access/login/Login.jsx index 58623476..739649ae 100644 --- a/app/mobile/src/access/login/Login.jsx +++ b/app/mobile/src/access/login/Login.jsx @@ -35,14 +35,14 @@ export function Login() { + autoCorrect={false} autoCapitalize="none" placeholder="username@server" /> { state.showPassword && ( + autoCorrect={false} autoCapitalize="none" placeholder="password"/> @@ -52,7 +52,7 @@ export function Login() { + autoCorrect={false} secureTextEntry={true} autoCapitalize="none" placeholder="password" /> diff --git a/app/mobile/src/api/getHandle.js b/app/mobile/src/api/getHandle.js new file mode 100644 index 00000000..4006df55 --- /dev/null +++ b/app/mobile/src/api/getHandle.js @@ -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() +} + diff --git a/app/mobile/src/context/useProfileContext.hook.js b/app/mobile/src/context/useProfileContext.hook.js index 3fcd4764..8ac26b2c 100644 --- a/app/mobile/src/context/useProfileContext.hook.js +++ b/app/mobile/src/context/useProfileContext.hook.js @@ -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 } diff --git a/app/mobile/src/session/profile/Profile.jsx b/app/mobile/src/session/profile/Profile.jsx index c30a63e8..88db45fb 100644 --- a/app/mobile/src/session/profile/Profile.jsx +++ b/app/mobile/src/session/profile/Profile.jsx @@ -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 ( @@ -113,15 +126,15 @@ export function Profile() { Edit Details: + autoCapitalize="words" placeholder="Name" /> + autoCapitalize="words" placeholder="Location" /> + autoCapitalize="sentences" placeholder="Description" multiline={true} /> @@ -146,23 +159,64 @@ export function Profile() { Change Login: - - - - - - + autoCapitalize={'none'} placeholder="Username" /> + { state.checked && state.available && ( + + )} + { state.checked && !state.available && ( + + )} + { !state.showPassword && ( + + + + + + + )} + { state.showPassword && ( + + + + + + + )} + { !state.showConfirm && ( + + + + + + + )} + { state.showConfirm && ( + + + + + + + )} Cancel - - Save - + { enabled && ( + + Save + + )} + { !enabled && ( + + Save + + )} diff --git a/app/mobile/src/session/profile/Profile.styled.js b/app/mobile/src/session/profile/Profile.styled.js index c2e8dc70..634ca3d8 100644 --- a/app/mobile/src/session/profile/Profile.styled.js +++ b/app/mobile/src/session/profile/Profile.styled.js @@ -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, diff --git a/app/mobile/src/session/profile/useProfile.hook.js b/app/mobile/src/session/profile/useProfile.hook.js index 0c71699e..51842bd1 100644 --- a/app/mobile/src/session/profile/useProfile.hook.js +++ b/app/mobile/src/session/profile/useProfile.hook.js @@ -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); }, };