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 Identicon from 'react-identicons';
......@@ -7,7 +7,28 @@ import type { UserInfo } from 'types/api/account';
import { useAppContext } from 'lib/appContext';
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 {
size: number;
......@@ -18,19 +39,22 @@ interface Props {
const UserAvatar = ({ size, data, isFetched }: Props) => {
const appProps = useAppContext();
const hasAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN, appProps.cookies));
const [ isImageLoadError, setImageLoadError ] = React.useState(false);
const sizeString = `${ size }px`;
const bgColor = useColorModeValue('blackAlpha.100', 'white');
const handleImageLoadError = React.useCallback(() => {
setImageLoadError(true);
}, []);
if (hasAuth && !isFetched) {
return <SkeletonCircle h={ sizeString } w={ sizeString }/>;
}
if (data?.avatar) {
return (
<Image
flexShrink={ 0 }
src={ data.avatar }
src={ data?.avatar }
alt={ `Profile picture of ${ data?.name || data?.nickname || '' }` }
w={ sizeString }
minW={ sizeString }
......@@ -38,21 +62,8 @@ const UserAvatar = ({ size, data, isFetched }: Props) => {
minH={ sizeString }
borderRadius="full"
overflow="hidden"
/>
);
}
return (
<ProfileIcon
flexShrink={ 0 }
maxWidth={ sizeString }
maxHeight={ sizeString }
string={ data?.email || 'randomness' }
// the displayed size is doubled for retina displays
size={ size * 2 }
bg={ bgColor }
borderRadius="full"
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