From eb7348fec1b1fedb36e4a2e44bbefbcd1063df83 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Mon, 18 Mar 2024 22:37:46 -0400 Subject: [PATCH] groups: revert avatar src-checking --- apps/tlon-web/src/components/Avatar.tsx | 49 ++++++++++------- apps/tlon-web/src/dms/MultiDmAvatar.tsx | 3 +- apps/tlon-web/src/groups/GroupAvatar.tsx | 3 +- apps/tlon-web/src/state/avatar.ts | 67 ++++++++++-------------- 4 files changed, 59 insertions(+), 63 deletions(-) diff --git a/apps/tlon-web/src/components/Avatar.tsx b/apps/tlon-web/src/components/Avatar.tsx index 7a7dfeb68e..91cece39f5 100644 --- a/apps/tlon-web/src/components/Avatar.tsx +++ b/apps/tlon-web/src/components/Avatar.tsx @@ -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'; @@ -106,7 +106,7 @@ 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; @@ -114,7 +114,7 @@ function Avatar({ (previewAvatarIsValid ? previewAvatar : avatar) || '' ); const showImage = useMemo( - () => loadImage && hasLoaded, + () => loadImage || hasLoaded, [loadImage, hasLoaded] ); const { classes, size: sigilSize } = useMemo(() => sizeMap[size], [size]); @@ -132,7 +132,7 @@ function Avatar({ ); const citedShip = useMemo(() => cite(ship), [ship]); const props: SigilProps = { - point: citedShip, + point: citedShip || '~zod', size: sigilSize, detail: icon ? 'none' : 'default', space: 'none', @@ -140,26 +140,25 @@ function Avatar({ 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 ( - loadImage && image && !calm.disableRemoteContent && !imageIsColor && - hasLoaded, + (hasLoaded || loadImage), [image, calm.disableRemoteContent, imageIsColor, hasLoaded, loadImage] ); const dark = useIsDark(); diff --git a/apps/tlon-web/src/state/avatar.ts b/apps/tlon-web/src/state/avatar.ts index a18c0c8283..a48ed3d14b 100644 --- a/apps/tlon-web/src/state/avatar.ts +++ b/apps/tlon-web/src/state/avatar.ts @@ -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; + loaded: (src: string) => void; +} - // Reset the hasLoaded state when the src changes - useEffect(() => { - setHasLoaded(false); - }, [src]); +const useAvatarStore = create((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;