Front: Update User Avatar (#250)
* Front: Update User Avatar * Front: Fix expo-image-picker version
This commit is contained in:
+25
-4
@@ -21,6 +21,8 @@ import { PlageHandler } from './models/Plage';
|
||||
import { ListHandler } from './models/List';
|
||||
import { AccessTokenResponseHandler } from './models/AccessTokenResponse';
|
||||
import * as yup from 'yup';
|
||||
import { base64ToBlob } from 'file64';
|
||||
import { ImagePickerAsset } from 'expo-image-picker';
|
||||
|
||||
type AuthenticationInput = { username: string; password: string };
|
||||
type RegistrationInput = AuthenticationInput & { email: string };
|
||||
@@ -30,6 +32,7 @@ export type AccessToken = string;
|
||||
type FetchParams = {
|
||||
route: string;
|
||||
body?: object;
|
||||
formData?: FormData;
|
||||
method?: 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT';
|
||||
};
|
||||
|
||||
@@ -81,17 +84,22 @@ export default class API {
|
||||
public static async fetch(params: FetchParams): Promise<void>;
|
||||
public static async fetch(params: FetchParams, handle?: HandleParams) {
|
||||
const jwtToken = store.getState().user.accessToken;
|
||||
const header = {
|
||||
'Content-Type': 'application/json',
|
||||
const headers = {
|
||||
...(params.formData == undefined && { 'Content-Type': 'application/json' }),
|
||||
...(jwtToken && { Authorization: `Bearer ${jwtToken}` }),
|
||||
};
|
||||
const response = await fetch(`${API.baseUrl}${params.route}`, {
|
||||
headers: (jwtToken && { ...header, Authorization: `Bearer ${jwtToken}` }) || header,
|
||||
body: JSON.stringify(params.body),
|
||||
headers: headers,
|
||||
body: params.formData ?? JSON.stringify(params.body),
|
||||
method: params.method ?? 'GET',
|
||||
}).catch(() => {
|
||||
throw new Error('Error while fetching API: ' + API.baseUrl);
|
||||
});
|
||||
if (!handle || handle.emptyResponse) {
|
||||
if (!response.ok) {
|
||||
console.log(await response.json());
|
||||
throw new APIError(response.statusText, response.status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (handle.raw) {
|
||||
@@ -164,6 +172,7 @@ export default class API {
|
||||
{
|
||||
route: '/auth/guest',
|
||||
method: 'POST',
|
||||
body: undefined,
|
||||
},
|
||||
{ handler: AccessTokenResponseHandler }
|
||||
)
|
||||
@@ -587,4 +596,16 @@ export default class API {
|
||||
{ handler: UserHandler }
|
||||
);
|
||||
}
|
||||
|
||||
public static async updateProfileAvatar(image: ImagePickerAsset): Promise<void> {
|
||||
const data = await base64ToBlob(image.uri);
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('file', data);
|
||||
return API.fetch({
|
||||
route: '/auth/me/picture',
|
||||
method: 'POST',
|
||||
formData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -32,6 +32,14 @@
|
||||
"eas": {
|
||||
"projectId": "dade8e5e-3e2c-49f7-98c5-cf8834c7ebb2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugins": [
|
||||
[
|
||||
"expo-image-picker",
|
||||
{
|
||||
"photosPermission": "The app accesses your photos to let you set your personal avatar."
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Avatar } from 'native-base';
|
||||
import API from '../API';
|
||||
import { useQuery } from '../Queries';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const getInitials = (name: string) => {
|
||||
return name
|
||||
@@ -13,9 +14,22 @@ type UserAvatarProps = Pick<Parameters<typeof Avatar>[0], 'size'>;
|
||||
|
||||
const UserAvatar = ({ size }: UserAvatarProps) => {
|
||||
const user = useQuery(API.getUserInfo);
|
||||
const avatarUrl = useMemo(() => {
|
||||
if (!user.data) {
|
||||
return null;
|
||||
}
|
||||
const url = new URL(user.data.data.avatar);
|
||||
|
||||
url.searchParams.append('updatedAt', user.dataUpdatedAt.toString());
|
||||
return url;
|
||||
}, [user.data]);
|
||||
|
||||
return (
|
||||
<Avatar size={size} source={{ uri: user.data?.data.avatar }} style={{ zIndex: 0 }}>
|
||||
<Avatar
|
||||
size={size}
|
||||
source={avatarUrl ? { uri: avatarUrl.toString() } : undefined}
|
||||
style={{ zIndex: 0 }}
|
||||
>
|
||||
{user.data !== undefined && getInitials(user.data.name)}
|
||||
</Avatar>
|
||||
);
|
||||
|
||||
@@ -180,6 +180,8 @@ export const en = {
|
||||
|
||||
recentSearches: 'Recent searches',
|
||||
noRecentSearches: 'No recent searches',
|
||||
avatar: 'Avatar',
|
||||
changeIt: 'Change It',
|
||||
};
|
||||
|
||||
export const fr: typeof en = {
|
||||
@@ -362,6 +364,8 @@ export const fr: typeof en = {
|
||||
|
||||
recentSearches: 'Recherches récentes',
|
||||
noRecentSearches: 'Aucune recherche récente',
|
||||
avatar: 'Avatar',
|
||||
changeIt: 'Modifier',
|
||||
};
|
||||
|
||||
export const sp: typeof en = {
|
||||
@@ -548,4 +552,7 @@ export const sp: typeof en = {
|
||||
recentSearches: 'Búsquedas recientes',
|
||||
noRecentSearches: 'No hay búsquedas recientes',
|
||||
continuewithgoogle: 'Continuar con Google',
|
||||
|
||||
avatar: 'Avatar',
|
||||
changeIt: 'Cambialo',
|
||||
};
|
||||
|
||||
@@ -34,11 +34,13 @@
|
||||
"expo": "^47.0.8",
|
||||
"expo-asset": "~8.7.0",
|
||||
"expo-dev-client": "~2.0.1",
|
||||
"expo-image-picker": "~14.0.2",
|
||||
"expo-linking": "~3.3.1",
|
||||
"expo-screen-orientation": "~5.0.1",
|
||||
"expo-secure-store": "~12.0.0",
|
||||
"expo-splash-screen": "~0.17.5",
|
||||
"expo-status-bar": "~1.4.2",
|
||||
"file64": "^1.0.2",
|
||||
"format-duration": "^2.0.0",
|
||||
"i18next": "^21.8.16",
|
||||
"install": "^0.13.0",
|
||||
|
||||
@@ -2,13 +2,14 @@ import API from '../../API';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { unsetAccessToken } from '../../state/UserSlice';
|
||||
import React from 'react';
|
||||
import { Column, Text, Button, Box, Flex, Center, Heading, Popover } from 'native-base';
|
||||
import { Column, Text, Button, Box, Flex, Center, Heading, Popover, Toast } from 'native-base';
|
||||
import TextButton from '../../components/TextButton';
|
||||
import { LoadingView } from '../../components/Loading';
|
||||
import ElementList from '../../components/GtkUI/ElementList';
|
||||
import { translate } from '../../i18n/i18n';
|
||||
import { useQuery } from '../../Queries';
|
||||
import UserAvatar from '../../components/UserAvatar';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
|
||||
// Too painful to infer the settings-only, typed navigator. Gave up
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -50,7 +51,39 @@ const ProfileSettings = ({ navigation }: { navigation: any }) => {
|
||||
data: {
|
||||
text: user.email || translate('NoAssociatedEmail'),
|
||||
onPress: () => {
|
||||
navigation.navigate('ChangeEmail');
|
||||
navigation.navigate('changeEmail');
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
title: translate('avatar'),
|
||||
data: {
|
||||
text: translate('changeIt'),
|
||||
onPress: () => {
|
||||
ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
aspect: [1, 1],
|
||||
quality: 1,
|
||||
base64: true,
|
||||
}).then((result) => {
|
||||
console.log(result);
|
||||
const image = result.assets?.at(0);
|
||||
|
||||
if (!result.canceled && image) {
|
||||
API.updateProfileAvatar(image)
|
||||
.then(() => {
|
||||
userQuery.refetch();
|
||||
Toast.show({
|
||||
description: 'Update successful',
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
Toast.show({ description: 'Update failed' });
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -9116,6 +9116,18 @@ expo-font@~11.0.1:
|
||||
dependencies:
|
||||
fontfaceobserver "^2.1.0"
|
||||
|
||||
expo-image-loader@~4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-image-loader/-/expo-image-loader-4.0.0.tgz#a17e5f95a4c1671791168dd5dfc221bf2f88480c"
|
||||
integrity sha512-hVMhXagsO1cSng5s70IEjuJAuHy2hX/inu5MM3T0ecJMf7L/7detKf22molQBRymerbk6Tzu+20h11eU0n/3jQ==
|
||||
|
||||
expo-image-picker@~14.0.2:
|
||||
version "14.0.3"
|
||||
resolved "https://registry.yarnpkg.com/expo-image-picker/-/expo-image-picker-14.0.3.tgz#ea0bbe796ccc3bd5e58fc00487be22bac317afeb"
|
||||
integrity sha512-VN5wMWzhYhIRhFq8I1pjMbn/ivjlhWfxzJpz5jUOf3mQ8vxrI5GcR8cJO9kyYwuCrI9W3GUzh/aDt7QRSTQDDA==
|
||||
dependencies:
|
||||
expo-image-loader "~4.0.0"
|
||||
|
||||
expo-json-utils@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/expo-json-utils/-/expo-json-utils-0.4.0.tgz#47ae83a1cc973101d62371f94790e9ad39491751"
|
||||
@@ -9459,6 +9471,11 @@ file-uri-to-path@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
||||
|
||||
file64@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/file64/-/file64-1.0.2.tgz#d3dde9bab142ccf0049e0bd407a2576e94894825"
|
||||
integrity sha512-cDQefGBdb8OO7Pb2nXiRcZlVjwgzoG0uuJ/H2fxNdz3vbOZctp0iPJoHDQ4VZrirqGYc9n/p9+ZqptLZrcSGRA==
|
||||
|
||||
filesize@6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00"
|
||||
|
||||
Reference in New Issue
Block a user