Skip to content

Commit

Permalink
Merge pull request #3351 from tloncorp/james/revert-group-avatar
Browse files Browse the repository at this point in the history
groups: revert avatar src-checking
  • Loading branch information
patosullivan authored Mar 19, 2024
2 parents baa5df7 + eb7348f commit 060d82d
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 63 deletions.
49 changes: 29 additions & 20 deletions apps/tlon-web/src/components/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import classNames from 'classnames';
import { darken, lighten, parseToHsla } from 'color2k';
import _ from 'lodash';
import React, { CSSProperties, useMemo } from 'react';
import { isValidPatp, clan as shipType } from 'urbit-ob';
import { isValidPatp } from 'urbit-ob';

import { isValidUrl, normalizeUrbitColor } from '@/logic/utils';
import { useAvatar } from '@/state/avatar';
Expand Down Expand Up @@ -106,15 +106,15 @@ function Avatar({
const calm = useCalm();
const { previewColor, previewAvatar } = previewData ?? {};
const previewAvatarIsValid = useMemo(
() => previewAvatar && isValidUrl(previewAvatar),
() => previewAvatar && previewAvatar !== null && isValidUrl(previewAvatar),
[previewAvatar]
);
const { color, avatar } = contact || emptyContact;
const { hasLoaded, load } = useAvatar(
(previewAvatarIsValid ? previewAvatar : avatar) || ''
);
const showImage = useMemo(
() => loadImage && hasLoaded,
() => loadImage || hasLoaded,
[loadImage, hasLoaded]
);
const { classes, size: sigilSize } = useMemo(() => sizeMap[size], [size]);
Expand All @@ -132,34 +132,33 @@ function Avatar({
);
const citedShip = useMemo(() => cite(ship), [ship]);
const props: SigilProps = {
point: citedShip,
point: citedShip || '~zod',
size: sigilSize,
detail: icon ? 'none' : 'default',
space: 'none',
background: adjustedColor,
foreground: foregroundColor,
};
const invalidShip = useMemo(
() => !isValidPatp(ship) || ['comet', 'moon'].includes(shipType(ship)),
[ship]
() =>
!ship ||
ship === 'undefined' ||
!isValidPatp(ship) ||
citedShip.match(/[_^]/) ||
citedShip.length > 14,
[ship, citedShip]
);

const shouldShowImage = useMemo(
() =>
showImage &&
previewAvatarIsValid &&
!calm.disableRemoteContent &&
!calm.disableAvatars &&
((previewAvatarIsValid && showImage) ||
(!previewAvatarIsValid && avatar && showImage)),
[
previewAvatarIsValid,
showImage,
calm.disableRemoteContent,
calm.disableAvatars,
avatar,
]
!calm.disableAvatars,
[showImage, previewAvatarIsValid, calm]
);

if (shouldShowImage && previewAvatarIsValid) {
if (shouldShowImage) {
return (
<img
className={classNames(className, classes, 'object-cover')}
Expand All @@ -171,24 +170,34 @@ function Avatar({
);
}

if (shouldShowImage && !previewAvatarIsValid) {
if (
avatar &&
showImage &&
!calm.disableRemoteContent &&
!calm.disableAvatars
) {
return (
<img
className={classNames(className, classes, 'object-cover')}
src={avatar ?? ''} // Defensively avoid null src
src={avatar}
alt=""
style={style}
onLoad={load}
/>
);
}

// Fallback to sigil or other representation if the conditions for showing the image are not met
return (
<div
className={classNames(
'relative flex flex-none items-center justify-center rounded bg-black',
classes,
size === 'sidebar' && 'p-1.5',
size === 'xs' && 'p-1.5',
size === 'small' && 'p-2',
size === 'default' && 'p-3',
size === 'big' && 'p-4',
size === 'huge' && 'p-3',
className
)}
style={{ backgroundColor: adjustedColor, ...style }}
Expand Down
3 changes: 1 addition & 2 deletions apps/tlon-web/src/dms/MultiDmAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function MultiDmAvatar({
loadImage = true,
}: MultiDmAvatarProps) {
const { hasLoaded, load } = useAvatar(image || '');
const showImage = loadImage && hasLoaded;
const showImage = hasLoaded || loadImage;

if (image && isColor(image)) {
return (
Expand All @@ -69,7 +69,6 @@ export default function MultiDmAvatar({
);
}

// Fallback if the image isn't available or showImage is false
return (
<div
className={cn(
Expand Down
3 changes: 1 addition & 2 deletions apps/tlon-web/src/groups/GroupAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,10 @@ export default function GroupAvatar({
const calm = useCalm();
const showImage = useMemo(
() =>
loadImage &&
image &&
!calm.disableRemoteContent &&
!imageIsColor &&
hasLoaded,
(hasLoaded || loadImage),
[image, calm.disableRemoteContent, imageIsColor, hasLoaded, loadImage]
);
const dark = useIsDark();
Expand Down
67 changes: 28 additions & 39 deletions apps/tlon-web/src/state/avatar.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,33 @@
import { useCallback, useEffect, useState } from 'react';
import produce from 'immer';
import { useCallback } from 'react';
import create from 'zustand';

export function useAvatar(src: string) {
// This hook is used to load an image and determine if it has loaded
const [hasLoaded, setHasLoaded] = useState(false);

const load = useCallback(() => {
// Create a new image object
const img = new Image();

// Set the hasLoaded state based on the image load
img.onload = () => {
setHasLoaded(true);
};

// Set the hasLoaded state to false if the image fails to load
img.onerror = () => {
setHasLoaded(false);
};

// Set the src of the image to the src passed to the hook
img.src = src;

// If the src is not defined, set hasLoaded to false
if (!src) {
setHasLoaded(false);
}
}, [src]);

// Load the image when the component mounts
useEffect(() => {
load();
}, [load]);
interface AvatarStore {
status: Record<string, boolean>;
loaded: (src: string) => void;
}

// Reset the hasLoaded state when the src changes
useEffect(() => {
setHasLoaded(false);
}, [src]);
const useAvatarStore = create<AvatarStore>((set, get) => ({
status: {},
loaded: (src) => {
set(
produce((draft) => {
draft.status[src] = true;
})
);
},
}));

// Return the hasLoaded state and the load function
return { hasLoaded, load };
export function useAvatar(src: string) {
return useAvatarStore(
useCallback(
(store: AvatarStore) => ({
hasLoaded: store.status[src] || false,
load: () => store.loaded(src),
}),
[src]
)
);
}

export default useAvatar;
export default useAvatarStore;

0 comments on commit 060d82d

Please sign in to comment.