import { useMemo, useState } from 'react'; import { Link } from 'react-router-dom'; import { setAccount, useAccount, useAuthorAvatar } from '@plebbit/plebbit-react-hooks'; import styles from './avatar-settings.module.css'; import { Trans, useTranslation } from 'react-i18next'; import LoadingEllipsis from '../../loading-ellipsis'; const AvatarPreview = ({ avatar }: any) => { const { t } = useTranslation(); const account = useAccount(); let author = useMemo(() => ({ ...account?.author, avatar }), [account, avatar]); const { imageUrl, state, error } = useAuthorAvatar({ author }); // if avatar already set, and user hasn't typed anything yet, preview already set author if (account?.author?.avatar && !avatar?.chainTicker && !avatar?.address && !avatar?.id && !avatar?.signature) { author = account.author; } // not enough data to preview yet if (!author?.avatar?.address && !author?.avatar?.signature) { return; } const stateText = state !== 'succeeded' ? : undefined; return ( <>
{imageUrl && state !== 'initializing' ? : {t('none')}}
{state !== 'succeeded' && account?.author?.avatar && (
{!error && stateText} {error && error?.message}
)} ); }; const AvatarSettings = () => { const { t } = useTranslation(); const account = useAccount(); const authorAddress = account?.author?.address; const [chainTicker, setChainTicker] = useState(account?.author?.avatar?.chainTicker); const [tokenAddress, setTokenAddress] = useState(account?.author?.avatar?.address); const [tokenId, setTokenId] = useState(account?.author?.avatar?.id); const [timestamp, setTimestamp] = useState(account?.author?.avatar?.timestamp); const [signature, setSignature] = useState(account?.author?.avatar?.signature?.signature); const getNftMessageToSign = (authorAddress: string, timestamp: number, tokenAddress: string, tokenId: string) => { let messageToSign: any = {}; // the property names must be in this order for the signature to match // insert props one at a time otherwise babel/webpack will reorder messageToSign.domainSeparator = 'plebbit-author-avatar'; messageToSign.authorAddress = authorAddress; messageToSign.timestamp = timestamp; messageToSign.tokenAddress = tokenAddress; messageToSign.tokenId = String(tokenId); // must be a type string, not number // use plain JSON so the user can read what he's signing messageToSign = JSON.stringify(messageToSign); return messageToSign; }; const [hasCopied, setHasCopied] = useState(false); const copyMessageToSign = () => { if (!chainTicker) { return alert(t('missing_chain_ticker')); } if (!tokenAddress) { return alert(t('missing_token_address')); } if (!tokenId) { return alert(t('missing_token_id')); } const newTimestamp = Math.floor(Date.now() / 1000); const messageToSign = getNftMessageToSign(authorAddress, newTimestamp, tokenAddress, tokenId); // update timestamp every time the user gets a new message to sign setTimestamp(newTimestamp); navigator.clipboard.writeText(messageToSign); setHasCopied(true); setTimeout(() => { setHasCopied(false); }, 2000); }; // how to resolve and verify NFT signatures https://github.com/plebbit/plebbit-js/blob/master/docs/nft.md const avatar = { chainTicker: chainTicker?.toLowerCase() || account?.author?.avatar?.chainTicker, timestamp, address: tokenAddress || account?.author?.avatar?.address, id: tokenId || account?.author?.avatar?.id, signature: { signature: signature || account?.author?.avatar?.signature?.signature, type: 'eip191', }, }; const save = () => { if (!chainTicker) { return alert(t('missing_chain_ticker')); } if (!tokenAddress) { return alert(t('missing_token_address')); } if (!tokenId) { return alert(t('missing_token_id')); } if (!signature) { return alert(t('missing_signature')); } setAccount({ ...account, author: { ...account?.author, avatar } }); alert(`saved`); }; return (
{t('chain_ticker')} setChainTicker(e.target.value)} />
), }} /> setTokenAddress(e.target.value)} />
{t('token_id')} setTokenId(e.target.value)} />
, // eslint-disable-next-line 2: , }} />
{t('paste_signature')} setSignature(e.target.value)} />
); }; export default AvatarSettings;