diff --git a/src/icons/logo-short.tsx b/src/icons/logo-short.tsx index 38baddf6df..aa5b441245 100644 --- a/src/icons/logo-short.tsx +++ b/src/icons/logo-short.tsx @@ -21,14 +21,14 @@ export const LogoShortIcon: React.FC<{ id?: string; width?: number; height?: num return (
Bonk
); diff --git a/src/views/dialogs/SharePNLAnalyticsDialog.tsx b/src/views/dialogs/SharePNLAnalyticsDialog.tsx index 0a139d56e0..654b7d1b46 100644 --- a/src/views/dialogs/SharePNLAnalyticsDialog.tsx +++ b/src/views/dialogs/SharePNLAnalyticsDialog.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { BonsaiHelpers } from '@/bonsai/ontology'; import { useToBlob } from '@hugocxl/react-to-image'; @@ -6,11 +6,13 @@ import styled from 'styled-components'; import tw from 'twin.macro'; import { AnalyticsEvents } from '@/constants/analytics'; +import { ASSET_ICON_MAP } from '@/constants/assets'; import { ButtonAction } from '@/constants/buttons'; import { DialogProps, SharePNLAnalyticsDialogProps } from '@/constants/dialogs'; import { STRING_KEYS } from '@/constants/localization'; import { IndexerPositionSide } from '@/types/indexer/indexerApiGen'; +import { useCustomNotification } from '@/hooks/useCustomNotification'; import { useAppSelectorWithArgs } from '@/hooks/useParameterizedSelector'; import { useStringGetter } from '@/hooks/useStringGetter'; @@ -38,8 +40,14 @@ const copyBlobToClipboard = async (blob: Blob | null) => { return; } - const item = new ClipboardItem({ 'image/png': blob }); - await navigator.clipboard.write([item]); + try { + const item = new ClipboardItem({ 'image/png': blob }); + await navigator.clipboard.write([item]); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to copy blob. ', error); + throw error; + } }; export const SharePNLAnalyticsDialog = ({ @@ -56,12 +64,27 @@ export const SharePNLAnalyticsDialog = ({ const stringGetter = useStringGetter(); const dispatch = useAppDispatch(); const logoUrl = useAppSelectorWithArgs(BonsaiHelpers.assets.selectAssetLogo, assetId); - const symbol = getDisplayableAssetFromBaseAsset(assetId); + const notify = useCustomNotification(); + const [isCopied, setIsCopied] = useState(false); const [{ isLoading: isCopying }, convert, ref] = useToBlob({ quality: 1.0, - onSuccess: copyBlobToClipboard, + onSuccess: async (blob) => { + await copyBlobToClipboard(blob); + setIsCopied(true); + setTimeout(() => setIsCopied(false), 2000); + }, + onError: (error) => { + // eslint-disable-next-line no-console + console.error('Failed to copy blob. ', error); + notify({ + title: stringGetter({ key: STRING_KEYS.ERROR }), + body: stringGetter({ key: STRING_KEYS.SOMETHING_WENT_WRONG }), + slotTitleLeft: , + toastDuration: 5000, + }); + }, }); const [{ isLoading: isSharing }, convertShare, refShare] = useToBlob({ @@ -98,6 +121,36 @@ export const SharePNLAnalyticsDialog = ({ const [assetLeft, assetRight] = marketId.split('-'); + const [logoBase64, setLogoBase64] = useState(null); + + const localLogoUrl = useMemo(() => { + if (assetId && Object.prototype.hasOwnProperty.call(ASSET_ICON_MAP, assetId)) { + return ASSET_ICON_MAP[assetId as keyof typeof ASSET_ICON_MAP]; + } + return logoUrl; + }, [logoUrl, assetId]); + + useEffect(() => { + if (!logoUrl) return; + + const img = new Image(); + img.crossOrigin = 'anonymous'; + img.src = logoUrl; + img.onload = () => { + const canvas = document.createElement('canvas'); + canvas.width = img.width || 26; + canvas.height = img.height || 26; + const ctx = canvas.getContext('2d'); + ctx?.drawImage(img, 0, 0, canvas.width, canvas.height); + setLogoBase64(canvas.toDataURL('image/png')); + }; + img.onerror = () => { + // eslint-disable-next-line no-console + console.error('Failed to load asset image. ', logoUrl); + setLogoBase64(null); + }; + }, [logoUrl]); + return ( <$ShareableCard @@ -110,7 +163,11 @@ export const SharePNLAnalyticsDialog = ({ >
- + {assetLeft}/{assetRight} @@ -126,7 +183,7 @@ export const SharePNLAnalyticsDialog = ({ showSign={ShowSign.Both} />
- +
@@ -176,7 +233,7 @@ export const SharePNLAnalyticsDialog = ({
<$Action action={ButtonAction.Secondary} - slotLeft={} + slotLeft={} onClick={() => { track(AnalyticsEvents.SharePnlCopied({ asset: assetId })); convert(); @@ -185,7 +242,7 @@ export const SharePNLAnalyticsDialog = ({ isLoading: isCopying, }} > - {stringGetter({ key: STRING_KEYS.COPY })} + {stringGetter({ key: isCopied ? STRING_KEYS.COPIED : STRING_KEYS.COPY })} <$Action action={ButtonAction.Primary}