import React, { useEffect, useState } from 'react'; import { getInitials } from '../../util/getInitials'; type Props = { diameter: number; name: string; pubkey: string; }; const sha512FromPubkey = async (pubkey: string): Promise => { const buf = await crypto.subtle.digest('SHA-512', new TextEncoder().encode(pubkey)); // tslint:disable: prefer-template restrict-plus-operands return Array.prototype.map .call(new Uint8Array(buf), (x: any) => ('00' + x.toString(16)).slice(-2)) .join(''); }; // do not do this on every avatar, just cache the values so we can reuse them accross the app // key is the pubkey, value is the hash const cachedHashes = new Map(); const avatarPlaceholderColors = ['#5ff8b0', '#26cdb9', '#f3c615', '#fcac5a']; const avatarBorderColor = '#00000059'; function useHashBasedOnPubkey(pubkey: string) { const [hash, setHash] = useState(undefined); const [loading, setIsLoading] = useState(true); useEffect(() => { const cachedHash = cachedHashes.get(pubkey); if (cachedHash) { setHash(cachedHash); setIsLoading(false); return; } setIsLoading(true); let isInProgress = true; if (!pubkey) { if (isInProgress) { setIsLoading(false); setHash(undefined); } return; } void sha512FromPubkey(pubkey).then(sha => { if (isInProgress) { setIsLoading(false); // Generate the seed simulate the .hashCode as Java if (sha) { const hashed = parseInt(sha.substring(0, 12), 16) || 0; setHash(hashed); cachedHashes.set(pubkey, hashed); return; } setHash(undefined); } }); return () => { isInProgress = false; }; }, [pubkey]); return { loading, hash }; } export const AvatarPlaceHolder = (props: Props) => { const { pubkey, diameter, name } = props; const { hash, loading } = useHashBasedOnPubkey(pubkey); const diameterWithoutBorder = diameter - 2; const viewBox = `0 0 ${diameter} ${diameter}`; const r = diameter / 2; const rWithoutBorder = diameterWithoutBorder / 2; if (loading || !hash) { // return grey circle return ( ); } const initial = getInitials(name)?.toLocaleUpperCase() || '0'; const fontSize = diameter * 0.5; const bgColorIndex = hash % avatarPlaceholderColors.length; const bgColor = avatarPlaceholderColors[bgColorIndex]; return ( {initial} ); };