Changeset View
Changeset View
Standalone View
Standalone View
native/avatars/edit-user-avatar-provider.react.js
Show All 13 Lines | |||||
import { | import { | ||||
useDispatchActionPromise, | useDispatchActionPromise, | ||||
useServerCall, | useServerCall, | ||||
} from 'lib/utils/action-utils.js'; | } from 'lib/utils/action-utils.js'; | ||||
import { selectFromGallery, useUploadSelectedMedia } from './avatar-hooks.js'; | import { selectFromGallery, useUploadSelectedMedia } from './avatar-hooks.js'; | ||||
import { useSelector } from '../redux/redux-utils.js'; | import { useSelector } from '../redux/redux-utils.js'; | ||||
export type UserAvatarSelection = | |||||
| { +needsUpload: true, +mediaSelection: NativeMediaSelection } | |||||
| { +needsUpload: false, +updateUserAvatarRequest: UpdateUserAvatarRequest }; | |||||
type RegistrationMode = | |||||
| { +registrationMode: 'off' } | |||||
| { | |||||
+registrationMode: 'on', | |||||
+successCallback: UserAvatarSelection => mixed, | |||||
}; | |||||
const registrationModeOff = { registrationMode: 'off' }; | |||||
export type EditUserAvatarContextType = { | export type EditUserAvatarContextType = { | ||||
+userAvatarSaveInProgress: boolean, | +userAvatarSaveInProgress: boolean, | ||||
+selectFromGalleryAndUpdateUserAvatar: () => Promise<void>, | +selectFromGalleryAndUpdateUserAvatar: () => Promise<void>, | ||||
+updateImageUserAvatar: (selection: NativeMediaSelection) => Promise<void>, | +updateImageUserAvatar: (selection: NativeMediaSelection) => Promise<void>, | ||||
+setUserAvatar: (avatarRequest: UpdateUserAvatarRequest) => Promise<void>, | +setUserAvatar: (avatarRequest: UpdateUserAvatarRequest) => Promise<void>, | ||||
+setRegistrationMode: (registrationMode: RegistrationMode) => void, | |||||
}; | }; | ||||
const EditUserAvatarContext: React.Context<?EditUserAvatarContextType> = | const EditUserAvatarContext: React.Context<?EditUserAvatarContextType> = | ||||
React.createContext<?EditUserAvatarContextType>(); | React.createContext<?EditUserAvatarContextType>(); | ||||
const updateUserAvatarLoadingStatusSelector = createLoadingStatusSelector( | const updateUserAvatarLoadingStatusSelector = createLoadingStatusSelector( | ||||
updateUserAvatarActionTypes, | updateUserAvatarActionTypes, | ||||
); | ); | ||||
const displayFailureAlert = () => | const displayFailureAlert = () => | ||||
Alert.alert( | Alert.alert( | ||||
'Couldn’t save avatar', | 'Couldn’t save avatar', | ||||
'Please try again later', | 'Please try again later', | ||||
[{ text: 'OK' }], | [{ text: 'OK' }], | ||||
{ cancelable: true }, | { cancelable: true }, | ||||
); | ); | ||||
type Props = { | type Props = { | ||||
+children: React.Node, | +children: React.Node, | ||||
}; | }; | ||||
function EditUserAvatarProvider(props: Props): React.Node { | function EditUserAvatarProvider(props: Props): React.Node { | ||||
const { children } = props; | const { children } = props; | ||||
const [registrationMode, setRegistrationMode] = | |||||
React.useState<RegistrationMode>(registrationModeOff); | |||||
const dispatchActionPromise = useDispatchActionPromise(); | const dispatchActionPromise = useDispatchActionPromise(); | ||||
const updateUserAvatarCall = useServerCall(updateUserAvatar); | const updateUserAvatarCall = useServerCall(updateUserAvatar); | ||||
const [userAvatarMediaUploadInProgress, setUserAvatarMediaUploadInProgress] = | const [userAvatarMediaUploadInProgress, setUserAvatarMediaUploadInProgress] = | ||||
React.useState(false); | React.useState(false); | ||||
const updateUserAvatarLoadingStatus: LoadingStatus = useSelector( | const updateUserAvatarLoadingStatus: LoadingStatus = useSelector( | ||||
updateUserAvatarLoadingStatusSelector, | updateUserAvatarLoadingStatusSelector, | ||||
); | ); | ||||
const userAvatarSaveInProgress = | const userAvatarSaveInProgress = | ||||
userAvatarMediaUploadInProgress || | userAvatarMediaUploadInProgress || | ||||
updateUserAvatarLoadingStatus === 'loading'; | updateUserAvatarLoadingStatus === 'loading'; | ||||
const uploadSelectedMedia = useUploadSelectedMedia( | const uploadSelectedMedia = useUploadSelectedMedia( | ||||
setUserAvatarMediaUploadInProgress, | setUserAvatarMediaUploadInProgress, | ||||
); | ); | ||||
const updateImageUserAvatar = React.useCallback( | const updateImageUserAvatar = React.useCallback( | ||||
async (selection: NativeMediaSelection) => { | async (selection: NativeMediaSelection) => { | ||||
const imageAvatarUpdateRequest = await uploadSelectedMedia(selection); | if (registrationMode.registrationMode === 'on') { | ||||
registrationMode.successCallback({ | |||||
needsUpload: true, | |||||
mediaSelection: selection, | |||||
}); | |||||
return; | |||||
} | |||||
const imageAvatarUpdateRequest = await uploadSelectedMedia(selection); | |||||
if (!imageAvatarUpdateRequest) { | if (!imageAvatarUpdateRequest) { | ||||
return; | return; | ||||
} | } | ||||
dispatchActionPromise( | const promise = (async () => { | ||||
updateUserAvatarActionTypes, | |||||
(async () => { | |||||
setUserAvatarMediaUploadInProgress(false); | setUserAvatarMediaUploadInProgress(false); | ||||
try { | try { | ||||
return await updateUserAvatarCall(imageAvatarUpdateRequest); | return await updateUserAvatarCall(imageAvatarUpdateRequest); | ||||
} catch (e) { | } catch (e) { | ||||
displayFailureAlert(); | displayFailureAlert(); | ||||
throw e; | throw e; | ||||
} | } | ||||
})(), | })(); | ||||
); | dispatchActionPromise(updateUserAvatarActionTypes, promise); | ||||
await promise; | |||||
}, | }, | ||||
[dispatchActionPromise, updateUserAvatarCall, uploadSelectedMedia], | [ | ||||
registrationMode, | |||||
uploadSelectedMedia, | |||||
updateUserAvatarCall, | |||||
dispatchActionPromise, | |||||
], | |||||
); | ); | ||||
const selectFromGalleryAndUpdateUserAvatar = React.useCallback(async () => { | const selectFromGalleryAndUpdateUserAvatar = React.useCallback(async () => { | ||||
const selection = await selectFromGallery(); | const selection = await selectFromGallery(); | ||||
if (!selection) { | if (!selection) { | ||||
return; | return; | ||||
} | } | ||||
await updateImageUserAvatar(selection); | await updateImageUserAvatar(selection); | ||||
}, [updateImageUserAvatar]); | }, [updateImageUserAvatar]); | ||||
const setUserAvatar = React.useCallback( | const setUserAvatar = React.useCallback( | ||||
async (avatarRequest: UpdateUserAvatarRequest) => { | async (request: UpdateUserAvatarRequest) => { | ||||
if (registrationMode.registrationMode === 'on') { | |||||
registrationMode.successCallback({ | |||||
needsUpload: false, | |||||
updateUserAvatarRequest: request, | |||||
}); | |||||
return; | |||||
} | |||||
const promise = (async () => { | const promise = (async () => { | ||||
try { | try { | ||||
return await updateUserAvatarCall(avatarRequest); | return await updateUserAvatarCall(request); | ||||
} catch (e) { | } catch (e) { | ||||
displayFailureAlert(); | displayFailureAlert(); | ||||
throw e; | throw e; | ||||
} | } | ||||
})(); | })(); | ||||
dispatchActionPromise(updateUserAvatarActionTypes, promise); | dispatchActionPromise(updateUserAvatarActionTypes, promise); | ||||
await promise; | await promise; | ||||
}, | }, | ||||
[dispatchActionPromise, updateUserAvatarCall], | [registrationMode, updateUserAvatarCall, dispatchActionPromise], | ||||
); | ); | ||||
const context = React.useMemo( | const context = React.useMemo( | ||||
() => ({ | () => ({ | ||||
userAvatarSaveInProgress, | userAvatarSaveInProgress, | ||||
selectFromGalleryAndUpdateUserAvatar, | selectFromGalleryAndUpdateUserAvatar, | ||||
updateImageUserAvatar, | updateImageUserAvatar, | ||||
setUserAvatar, | setUserAvatar, | ||||
setRegistrationMode, | |||||
}), | }), | ||||
[ | [ | ||||
userAvatarSaveInProgress, | userAvatarSaveInProgress, | ||||
selectFromGalleryAndUpdateUserAvatar, | selectFromGalleryAndUpdateUserAvatar, | ||||
updateImageUserAvatar, | updateImageUserAvatar, | ||||
setUserAvatar, | setUserAvatar, | ||||
setRegistrationMode, | |||||
], | ], | ||||
); | ); | ||||
return ( | return ( | ||||
<EditUserAvatarContext.Provider value={context}> | <EditUserAvatarContext.Provider value={context}> | ||||
{children} | {children} | ||||
</EditUserAvatarContext.Provider> | </EditUserAvatarContext.Provider> | ||||
); | ); | ||||
} | } | ||||
export { EditUserAvatarContext, EditUserAvatarProvider }; | export { EditUserAvatarContext, EditUserAvatarProvider }; |