Commit 5f30f3f1 authored by tom's avatar tom

add fallback for user avatar

parent 407a3504
import { useColorModeValue, chakra, SkeletonCircle, Image } from '@chakra-ui/react'; import { useColorModeValue, useToken, SkeletonCircle, Image, Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import Identicon from 'react-identicons'; import Identicon from 'react-identicons';
...@@ -7,7 +7,28 @@ import type { UserInfo } from 'types/api/account'; ...@@ -7,7 +7,28 @@ import type { UserInfo } from 'types/api/account';
import { useAppContext } from 'lib/appContext'; import { useAppContext } from 'lib/appContext';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
const ProfileIcon = chakra(Identicon); // for those who haven't got profile
// or if we cannot download the profile picture for some reasons
const FallbackImage = ({ size, id }: { size: number; id: string }) => {
const bgColor = useToken('colors', useColorModeValue('blackAlpha.100', 'white'));
return (
<Box
flexShrink={ 0 }
maxWidth={ `${ size }px` }
maxHeight={ `${ size }px` }
>
<Box boxSize={ size * 2 } transformOrigin="left top" transform="scale(0.5)" borderRadius="full" overflow="hidden">
<Identicon
bg={ bgColor }
string={ id }
// the displayed size is doubled for retina displays and then scaled down
size={ size * 2 }
/>
</Box>
</Box>
);
};
interface Props { interface Props {
size: number; size: number;
...@@ -18,41 +39,31 @@ interface Props { ...@@ -18,41 +39,31 @@ interface Props {
const UserAvatar = ({ size, data, isFetched }: Props) => { const UserAvatar = ({ size, data, isFetched }: Props) => {
const appProps = useAppContext(); const appProps = useAppContext();
const hasAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN, appProps.cookies)); const hasAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN, appProps.cookies));
const [ isImageLoadError, setImageLoadError ] = React.useState(false);
const sizeString = `${ size }px`; const sizeString = `${ size }px`;
const bgColor = useColorModeValue('blackAlpha.100', 'white');
const handleImageLoadError = React.useCallback(() => {
setImageLoadError(true);
}, []);
if (hasAuth && !isFetched) { if (hasAuth && !isFetched) {
return <SkeletonCircle h={ sizeString } w={ sizeString }/>; return <SkeletonCircle h={ sizeString } w={ sizeString }/>;
} }
if (data?.avatar) {
return (
<Image
flexShrink={ 0 }
src={ data.avatar }
alt={ `Profile picture of ${ data?.name || data?.nickname || '' }` }
w={ sizeString }
minW={ sizeString }
h={ sizeString }
minH={ sizeString }
borderRadius="full"
overflow="hidden"
/>
);
}
return ( return (
<ProfileIcon <Image
flexShrink={ 0 } flexShrink={ 0 }
maxWidth={ sizeString } src={ data?.avatar }
maxHeight={ sizeString } alt={ `Profile picture of ${ data?.name || data?.nickname || '' }` }
string={ data?.email || 'randomness' } w={ sizeString }
// the displayed size is doubled for retina displays minW={ sizeString }
size={ size * 2 } h={ sizeString }
bg={ bgColor } minH={ sizeString }
borderRadius="full" borderRadius="full"
overflow="hidden" overflow="hidden"
fallback={ isImageLoadError || !data?.avatar ? <FallbackImage size={ size } id={ data?.email || 'randomness' }/> : undefined }
onError={ handleImageLoadError }
/> />
); );
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment