diff --git a/src/api/general.ts b/src/api/general.ts index 59e4c15e..63393fd2 100644 --- a/src/api/general.ts +++ b/src/api/general.ts @@ -69,7 +69,7 @@ const apiGeneral = async ({ error.response.status, error.response.data.error ) - return Promise.reject(error.response) + return Promise.reject(error.response.data.error) } else if (error.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of diff --git a/src/api/instance.ts b/src/api/instance.ts index 57736082..af1d7bef 100644 --- a/src/api/instance.ts +++ b/src/api/instance.ts @@ -98,7 +98,7 @@ const apiInstance = async ({ error.response.status, error.response.data.error ) - return Promise.reject(error.response) + return Promise.reject(error.response.data.error) } else if (error.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of diff --git a/src/components/Menu/Row.tsx b/src/components/Menu/Row.tsx index e7dde35b..ffb62118 100644 --- a/src/components/Menu/Row.tsx +++ b/src/components/Menu/Row.tsx @@ -76,84 +76,86 @@ const MenuRow: React.FC = ({ } }} > - - - {iconFront && ( - - )} - {badge ? ( - - ) : null} - - - {title} - - - - - {content || switchValue !== undefined || iconBack ? ( - - {content ? ( - typeof content === 'string' ? ( - - {content} - - ) : ( - content - ) - ) : null} - {switchValue !== undefined ? ( - - ) : null} - {iconBack ? ( + + + + {iconFront && ( + )} + {badge ? ( + ) : null} - {loading && loadingSpinkit} + + + {title} + + + + {content || switchValue !== undefined || iconBack ? ( + + {content ? ( + typeof content === 'string' ? ( + + {content} + + ) : ( + content + ) + ) : null} + {switchValue !== undefined ? ( + + ) : null} + {iconBack ? ( + + ) : null} + {loading && loadingSpinkit} + + ) : null} + + {description ? ( + + {description} + ) : null} - {description ? ( - - {description} - - ) : null} ) } diff --git a/src/i18n/en/screens/tabs.json b/src/i18n/en/screens/tabs.json index 18ae1a72..c87a7904 100644 --- a/src/i18n/en/screens/tabs.json +++ b/src/i18n/en/screens/tabs.json @@ -102,11 +102,11 @@ }, "avatar": { "title": "Avatar", - "description": "Available in next version" + "description": "Will be downscaled to 400x400px" }, - "banner": { + "header": { "title": "Banner", - "description": "Available in next version" + "description": "Will be downscaled to 1500x500px" }, "note": { "title": "Description" diff --git a/src/screens/Tabs/Me/Profile.tsx b/src/screens/Tabs/Me/Profile.tsx index 54decf2b..608232a7 100644 --- a/src/screens/Tabs/Me/Profile.tsx +++ b/src/screens/Tabs/Me/Profile.tsx @@ -30,7 +30,6 @@ const TabMeProfile: React.FC ) }} - /> + > + {({ route, navigation }) => ( + + )} + { + .catch(err => { displayMessage({ ref: messageRef, message: t('me.profile.feedback.failed', { type: t('me.profile.root.note.title') }), + ...(err && { description: err }), mode, type: 'error' }) diff --git a/src/screens/Tabs/Me/Profile/Name.tsx b/src/screens/Tabs/Me/Profile/Name.tsx index cb915af7..c0b96765 100644 --- a/src/screens/Tabs/Me/Profile/Name.tsx +++ b/src/screens/Tabs/Me/Profile/Name.tsx @@ -77,12 +77,13 @@ const TabMeProfileName: React.FC { + .catch(err => { displayMessage({ ref: messageRef, message: t('me.profile.feedback.failed', { type: t('me.profile.root.name.title') }), + ...(err && { description: err }), mode, type: 'error' }) diff --git a/src/screens/Tabs/Me/Profile/Note.tsx b/src/screens/Tabs/Me/Profile/Note.tsx index 98da197d..9ae06086 100644 --- a/src/screens/Tabs/Me/Profile/Note.tsx +++ b/src/screens/Tabs/Me/Profile/Note.tsx @@ -77,12 +77,13 @@ const TabMeProfileNote: React.FC { + .catch(err => { displayMessage({ ref: messageRef, message: t('me.profile.feedback.failed', { type: t('me.profile.root.note.title') }), + ...(err && { description: err }), mode, type: 'error' }) diff --git a/src/screens/Tabs/Me/Profile/Root.tsx b/src/screens/Tabs/Me/Profile/Root.tsx index ae735671..38cf2547 100644 --- a/src/screens/Tabs/Me/Profile/Root.tsx +++ b/src/screens/Tabs/Me/Profile/Root.tsx @@ -1,24 +1,26 @@ -import GracefullyImage from '@components/GracefullyImage' -import mediaSelector from '@components/mediaSelector' import { MenuContainer, MenuRow } from '@components/Menu' +import { displayMessage } from '@components/Message' import { useActionSheet } from '@expo/react-native-action-sheet' import { StackScreenProps } from '@react-navigation/stack' import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile' -import * as ImagePicker from 'expo-image-picker' -import React, { useCallback } from 'react' +import { useTheme } from '@utils/styles/ThemeManager' +import React, { RefObject, useCallback } from 'react' import { useTranslation } from 'react-i18next' +import FlashMessage from 'react-native-flash-message' import { ScrollView } from 'react-native-gesture-handler' +import ProfileAvatarHeader from './Root/AvatarHeader' const TabMeProfileRoot: React.FC> = ({ navigation }) => { +> & { messageRef: RefObject }> = ({ messageRef, navigation }) => { + const { mode } = useTheme() const { t } = useTranslation('screenTabs') const { showActionSheetWithOptions } = useActionSheet() const { data, isLoading } = useProfileQuery({}) - const { mutate } = useProfileMutation() + const { mutateAsync } = useProfileMutation() const onPressVisibility = useCallback(() => { showActionSheetWithOptions( @@ -35,13 +37,46 @@ const TabMeProfileRoot: React.FC { switch (buttonIndex) { case 0: - mutate({ type: 'source[privacy]', data: 'public' }) + mutateAsync({ type: 'source[privacy]', data: 'public' }).catch( + err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.visibility.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) break case 1: - mutate({ type: 'source[privacy]', data: 'unlisted' }) + mutateAsync({ type: 'source[privacy]', data: 'unlisted' }).catch( + err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.visibility.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) break case 2: - mutate({ type: 'source[privacy]', data: 'private' }) + mutateAsync({ type: 'source[privacy]', data: 'private' }).catch( + err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.visibility.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) break } } @@ -50,25 +85,88 @@ const TabMeProfileRoot: React.FC { if (data?.source.sensitive === undefined) { - mutate({ type: 'source[sensitive]', data: true }) + mutateAsync({ type: 'source[sensitive]', data: true }).catch(err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.sensitive.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) } else { - mutate({ type: 'source[sensitive]', data: !data.source.sensitive }) + mutateAsync({ + type: 'source[sensitive]', + data: !data.source.sensitive + }).catch(err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.sensitive.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) } }, [data?.source.sensitive]) const onPressLock = useCallback(() => { if (data?.locked === undefined) { - mutate({ type: 'locked', data: true }) + mutateAsync({ type: 'locked', data: true }).catch(err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.lock.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) } else { - mutate({ type: 'locked', data: !data.locked }) + mutateAsync({ type: 'locked', data: !data.locked }).catch(err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.lock.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) } }, [data?.locked]) const onPressBot = useCallback(() => { if (data?.bot === undefined) { - mutate({ type: 'bot', data: true }) + mutateAsync({ type: 'bot', data: true }).catch(err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.bot.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) } else { - mutate({ type: 'bot', data: !data?.bot }) + mutateAsync({ type: 'bot', data: !data?.bot }).catch(err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t('me.profile.root.bot.title') + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) } }, [data?.bot]) @@ -87,52 +185,8 @@ const TabMeProfileRoot: React.FC - - } - loading={isLoading} - iconBack='ChevronRight' - onPress={async () => { - const image = await mediaSelector({ - showActionSheetWithOptions, - mediaTypes: ImagePicker.MediaTypeOptions.Images, - resize: { width: 400, height: 400 } - }) - mutate({ type: 'avatar', data: image.uri }) - }} - /> - - } - loading={isLoading} - iconBack='ChevronRight' - onPress={async () => { - const image = await mediaSelector({ - showActionSheetWithOptions, - mediaTypes: ImagePicker.MediaTypeOptions.Images, - resize: { width: 1500, height: 500 } - }) - mutate({ type: 'header', data: image.uri }) - }} - /> + + +} + +const ProfileAvatarHeader: React.FC = ({ type, messageRef }) => { + const { mode } = useTheme() + const { t } = useTranslation('screenTabs') + + const { showActionSheetWithOptions } = useActionSheet() + + const query = useProfileQuery({}) + const mutation = useProfileMutation() + + return ( + { + const image = await mediaSelector({ + showActionSheetWithOptions, + mediaTypes: ImagePicker.MediaTypeOptions.Images, + resize: { width: 400, height: 400 } + }) + mutation + .mutateAsync({ type, data: image.uri }) + .then(() => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.succeed', { + type: t(`me.profile.root.${type}.title`) + }), + mode, + type: 'success' + }) + ) + .catch(err => + displayMessage({ + ref: messageRef, + message: t('me.profile.feedback.failed', { + type: t(`me.profile.root.${type}.title`) + }), + ...(err && { description: err }), + mode, + type: 'error' + }) + ) + }} + /> + ) +} + +export default ProfileAvatarHeader