|
|
|
@ -10,11 +10,13 @@ import { ChainToChain } from '../../components/icons/ChainToChain'; |
|
|
|
|
import { HelpIcon } from '../../components/icons/HelpIcon'; |
|
|
|
|
import { useBackgroundBanner } from '../../components/layout/BackgroundBanner'; |
|
|
|
|
import { Card } from '../../components/layout/Card'; |
|
|
|
|
import { chainToDomain } from '../../consts/domains'; |
|
|
|
|
import CheckmarkIcon from '../../images/icons/checkmark-circle.svg'; |
|
|
|
|
import ErrorCircleIcon from '../../images/icons/error-circle.svg'; |
|
|
|
|
import { MessageStatus } from '../../types'; |
|
|
|
|
import { MessageStatus, PartialTransactionReceipt } from '../../types'; |
|
|
|
|
import { getChainName } from '../../utils/chains'; |
|
|
|
|
import { logger } from '../../utils/logger'; |
|
|
|
|
import { getHumanReadableTimeString } from '../../utils/time'; |
|
|
|
|
import { getDateTimeString } from '../../utils/time'; |
|
|
|
|
import { useInterval } from '../../utils/timeout'; |
|
|
|
|
|
|
|
|
|
import { PLACEHOLDER_MESSAGES } from './placeholderMessages'; |
|
|
|
@ -45,14 +47,6 @@ export function MessageDetails({ messageId }: { messageId: string }) { |
|
|
|
|
originTransaction, |
|
|
|
|
destinationTransaction, |
|
|
|
|
} = message; |
|
|
|
|
const originTxExplorerLink = getTxExplorerLink( |
|
|
|
|
originChainId, |
|
|
|
|
originTransaction?.transactionHash, |
|
|
|
|
); |
|
|
|
|
const destinationTxExplorerLink = getTxExplorerLink( |
|
|
|
|
destinationChainId, |
|
|
|
|
destinationTransaction?.transactionHash, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const { bannerClassName, setBannerClassName } = useBackgroundBanner(); |
|
|
|
|
useEffect(() => { |
|
|
|
@ -113,22 +107,103 @@ export function MessageDetails({ messageId }: { messageId: string }) { |
|
|
|
|
)} |
|
|
|
|
</div> |
|
|
|
|
<div className="flex flex-wrap items-center justify-between mt-5 gap-4"> |
|
|
|
|
<Card classes="flex-1 min-w-fit space-y-4"> |
|
|
|
|
<div className="flex items-center justify-between"> |
|
|
|
|
<div className="relative -top-px -left-0.5"> |
|
|
|
|
<ChainIcon chainId={originChainId} /> |
|
|
|
|
</div> |
|
|
|
|
<div className="flex items-center pb-1"> |
|
|
|
|
<h3 className="text-gray-500 font-medium text-md mr-2"> |
|
|
|
|
Origin Transaction |
|
|
|
|
</h3> |
|
|
|
|
<HelpIcon size={16} text={helpText.origin} /> |
|
|
|
|
</div> |
|
|
|
|
<TransactionCard |
|
|
|
|
title="Origin Transaction" |
|
|
|
|
chainId={originChainId} |
|
|
|
|
status={status} |
|
|
|
|
transaction={originTransaction} |
|
|
|
|
help={helpText.origin} |
|
|
|
|
shouldBlur={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<TransactionCard |
|
|
|
|
title="Destination Transaction" |
|
|
|
|
chainId={destinationChainId} |
|
|
|
|
status={status} |
|
|
|
|
transaction={destinationTransaction} |
|
|
|
|
help={helpText.destination} |
|
|
|
|
shouldBlur={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<DetailsCard |
|
|
|
|
originChainId={originChainId} |
|
|
|
|
destinationChainId={destinationChainId} |
|
|
|
|
sender={sender} |
|
|
|
|
recipient={recipient} |
|
|
|
|
body={body} |
|
|
|
|
shouldBlur={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
</> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function StatusHeader({ |
|
|
|
|
text, |
|
|
|
|
fetching, |
|
|
|
|
children, |
|
|
|
|
}: PropsWithChildren<{ text: string; fetching: boolean }>) { |
|
|
|
|
return ( |
|
|
|
|
<div className="flex items-center"> |
|
|
|
|
<h3 className="text-white text-lg mr-3">{text}</h3> |
|
|
|
|
{fetching || !children ? ( |
|
|
|
|
<div className="w-7 h-7 overflow-hidden flex items-center justify-center"> |
|
|
|
|
<div className="scale-[35%]"> |
|
|
|
|
<Spinner white={true} /> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
) : ( |
|
|
|
|
children |
|
|
|
|
)} |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
interface TransactionCardProps { |
|
|
|
|
title: string; |
|
|
|
|
chainId: number; |
|
|
|
|
status: MessageStatus; |
|
|
|
|
transaction?: PartialTransactionReceipt; |
|
|
|
|
help: string; |
|
|
|
|
shouldBlur: boolean; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function TransactionCard({ |
|
|
|
|
title, |
|
|
|
|
chainId, |
|
|
|
|
status, |
|
|
|
|
transaction, |
|
|
|
|
help, |
|
|
|
|
shouldBlur, |
|
|
|
|
}: TransactionCardProps) { |
|
|
|
|
const txExplorerLink = getTxExplorerLink( |
|
|
|
|
chainId, |
|
|
|
|
transaction?.transactionHash, |
|
|
|
|
); |
|
|
|
|
return ( |
|
|
|
|
<Card classes="flex-1 min-w-fit space-y-4"> |
|
|
|
|
<div className="flex items-center justify-between"> |
|
|
|
|
<div className="relative -top-px -left-0.5"> |
|
|
|
|
<ChainIcon chainId={chainId} /> |
|
|
|
|
</div> |
|
|
|
|
<div className="flex items-center pb-1"> |
|
|
|
|
<h3 className="text-gray-500 font-medium text-md mr-2">{title}</h3> |
|
|
|
|
<HelpIcon size={16} text={help} /> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
{transaction ? ( |
|
|
|
|
<> |
|
|
|
|
<ValueRow |
|
|
|
|
label="Chain:" |
|
|
|
|
labelWidth="w-16" |
|
|
|
|
display={`${getChainName(chainId)} (${chainId} / ${ |
|
|
|
|
chainToDomain[chainId] |
|
|
|
|
})`}
|
|
|
|
|
displayWidth="w-44 sm:w-56" |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<ValueRow |
|
|
|
|
label="Tx hash:" |
|
|
|
|
labelWidth="w-16" |
|
|
|
|
display={originTransaction.transactionHash} |
|
|
|
|
display={transaction.transactionHash} |
|
|
|
|
displayWidth="w-44 sm:w-56" |
|
|
|
|
showCopy={true} |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
@ -136,7 +211,7 @@ export function MessageDetails({ messageId }: { messageId: string }) { |
|
|
|
|
<ValueRow |
|
|
|
|
label="From:" |
|
|
|
|
labelWidth="w-16" |
|
|
|
|
display={originTransaction.from} |
|
|
|
|
display={transaction.from} |
|
|
|
|
displayWidth="w-44 sm:w-56" |
|
|
|
|
showCopy={true} |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
@ -144,153 +219,99 @@ export function MessageDetails({ messageId }: { messageId: string }) { |
|
|
|
|
<ValueRow |
|
|
|
|
label="Block:" |
|
|
|
|
labelWidth="w-16" |
|
|
|
|
display={`${ |
|
|
|
|
originTransaction.blockNumber |
|
|
|
|
} (${getHumanReadableTimeString(originTransaction.timestamp)})`}
|
|
|
|
|
display={`${transaction.blockNumber} (${getDateTimeString( |
|
|
|
|
transaction.timestamp, |
|
|
|
|
)})`}
|
|
|
|
|
displayWidth="w-44 sm:w-56" |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
{originTxExplorerLink && ( |
|
|
|
|
{txExplorerLink && ( |
|
|
|
|
<a |
|
|
|
|
className="block text-sm text-gray-500 pl-px underline" |
|
|
|
|
href={originTxExplorerLink} |
|
|
|
|
href={txExplorerLink} |
|
|
|
|
target="_blank" |
|
|
|
|
rel="noopener noreferrer" |
|
|
|
|
> |
|
|
|
|
View in block explorer |
|
|
|
|
</a> |
|
|
|
|
)} |
|
|
|
|
</Card> |
|
|
|
|
<Card classes="flex-1 min-w-fit space-y-4"> |
|
|
|
|
<div className="flex items-center justify-between"> |
|
|
|
|
<div className="relative -top-px -left-0.5"> |
|
|
|
|
<ChainIcon chainId={destinationChainId} /> |
|
|
|
|
</div> |
|
|
|
|
<div className="flex items-center pb-1"> |
|
|
|
|
<h3 className="text-gray-500 font-medium text-md mr-2"> |
|
|
|
|
Destination Transaction |
|
|
|
|
</h3> |
|
|
|
|
<HelpIcon size={16} text={helpText.destination} /> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
{destinationTransaction ? ( |
|
|
|
|
<> |
|
|
|
|
<ValueRow |
|
|
|
|
label="Tx hash:" |
|
|
|
|
labelWidth="w-16" |
|
|
|
|
display={destinationTransaction.transactionHash} |
|
|
|
|
displayWidth="w-44 sm:w-56" |
|
|
|
|
showCopy={true} |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<ValueRow |
|
|
|
|
label="From:" |
|
|
|
|
labelWidth="w-16" |
|
|
|
|
display={destinationTransaction.from} |
|
|
|
|
displayWidth="w-44 sm:w-56" |
|
|
|
|
showCopy={true} |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<ValueRow |
|
|
|
|
label="Block:" |
|
|
|
|
labelWidth="w-16" |
|
|
|
|
display={`${ |
|
|
|
|
destinationTransaction.blockNumber |
|
|
|
|
} (${getHumanReadableTimeString( |
|
|
|
|
destinationTransaction.timestamp, |
|
|
|
|
)})`}
|
|
|
|
|
displayWidth="w-44 sm:w-56" |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
{destinationTxExplorerLink && ( |
|
|
|
|
<a |
|
|
|
|
className="block text-sm text-gray-500 pl-px underline" |
|
|
|
|
href={destinationTxExplorerLink} |
|
|
|
|
target="_blank" |
|
|
|
|
rel="noopener noreferrer" |
|
|
|
|
> |
|
|
|
|
View in block explorer |
|
|
|
|
</a> |
|
|
|
|
)} |
|
|
|
|
</> |
|
|
|
|
) : ( |
|
|
|
|
<div className="flex flex-col items-center py-6"> |
|
|
|
|
<div className="text-gray-500"> |
|
|
|
|
{status === MessageStatus.Failing |
|
|
|
|
? 'Destination chain transaction currently failing' |
|
|
|
|
: 'Destination chain transaction still in progress'} |
|
|
|
|
</div> |
|
|
|
|
<Spinner classes="mt-4" /> |
|
|
|
|
</div> |
|
|
|
|
)} |
|
|
|
|
</Card> |
|
|
|
|
</div> |
|
|
|
|
<Card classes="mt-4 space-y-4"> |
|
|
|
|
<div className="flex items-center justify-between"> |
|
|
|
|
<div className="relative -top-px -left-0.5"> |
|
|
|
|
<ChainToChain |
|
|
|
|
originChainId={originChainId} |
|
|
|
|
destinationChainId={destinationChainId} |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
<div className="flex items-center pb-1"> |
|
|
|
|
<h3 className="text-gray-500 font-medium text-md mr-2"> |
|
|
|
|
Message Details |
|
|
|
|
</h3> |
|
|
|
|
<HelpIcon size={16} text={helpText.details} /> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
<ValueRow |
|
|
|
|
label="Sender to outbox:" |
|
|
|
|
labelWidth="w-24 sm:w-36" |
|
|
|
|
display={sender} |
|
|
|
|
displayWidth="w-48 sm:w-80" |
|
|
|
|
showCopy={true} |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<ValueRow |
|
|
|
|
label="Recipient from outbox:" |
|
|
|
|
labelWidth="w-24 sm:w-36" |
|
|
|
|
display={recipient} |
|
|
|
|
displayWidth="w-48 sm:w-80" |
|
|
|
|
showCopy={true} |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<div> |
|
|
|
|
<label className="text-sm text-gray-500">Message content:</label> |
|
|
|
|
<div className="relative max-w-full break-words py-2 pl-2 pr-9 mt-2 bg-gray-100 text-sm font-mono rounded"> |
|
|
|
|
{body} |
|
|
|
|
<CopyButton |
|
|
|
|
copyValue={body} |
|
|
|
|
width={15} |
|
|
|
|
height={15} |
|
|
|
|
classes="absolute top-2 right-2 opacity-70" |
|
|
|
|
/> |
|
|
|
|
</> |
|
|
|
|
) : ( |
|
|
|
|
<div className="flex flex-col items-center py-6"> |
|
|
|
|
<div className="text-gray-500"> |
|
|
|
|
{status === MessageStatus.Failing |
|
|
|
|
? 'Destination chain transaction currently failing' |
|
|
|
|
: 'Destination chain transaction still in progress'} |
|
|
|
|
</div> |
|
|
|
|
<Spinner classes="mt-4" /> |
|
|
|
|
</div> |
|
|
|
|
</Card> |
|
|
|
|
</> |
|
|
|
|
)} |
|
|
|
|
</Card> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function StatusHeader({ |
|
|
|
|
text, |
|
|
|
|
fetching, |
|
|
|
|
children, |
|
|
|
|
}: PropsWithChildren<{ text: string; fetching: boolean }>) { |
|
|
|
|
interface DetailsCardProps { |
|
|
|
|
originChainId: number; |
|
|
|
|
destinationChainId: number; |
|
|
|
|
sender: string; |
|
|
|
|
recipient: string; |
|
|
|
|
body: string; |
|
|
|
|
shouldBlur: boolean; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function DetailsCard({ |
|
|
|
|
originChainId, |
|
|
|
|
destinationChainId, |
|
|
|
|
sender, |
|
|
|
|
recipient, |
|
|
|
|
body, |
|
|
|
|
shouldBlur, |
|
|
|
|
}: DetailsCardProps) { |
|
|
|
|
return ( |
|
|
|
|
<div className="flex items-center"> |
|
|
|
|
<h3 className="text-white text-lg mr-3">{text}</h3> |
|
|
|
|
{fetching || !children ? ( |
|
|
|
|
<div className="w-7 h-7 overflow-hidden flex items-center justify-center"> |
|
|
|
|
<div className="scale-[35%]"> |
|
|
|
|
<Spinner white={true} /> |
|
|
|
|
</div> |
|
|
|
|
<Card classes="mt-4 space-y-4"> |
|
|
|
|
<div className="flex items-center justify-between"> |
|
|
|
|
<div className="relative -top-px -left-0.5"> |
|
|
|
|
<ChainToChain |
|
|
|
|
originChainId={originChainId} |
|
|
|
|
destinationChainId={destinationChainId} |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
) : ( |
|
|
|
|
children |
|
|
|
|
)} |
|
|
|
|
</div> |
|
|
|
|
<div className="flex items-center pb-1"> |
|
|
|
|
<h3 className="text-gray-500 font-medium text-md mr-2"> |
|
|
|
|
Message Details |
|
|
|
|
</h3> |
|
|
|
|
<HelpIcon size={16} text={helpText.details} /> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
<ValueRow |
|
|
|
|
label="Sender:" |
|
|
|
|
labelWidth="w-20" |
|
|
|
|
display={sender} |
|
|
|
|
displayWidth="w-48 sm:w-80" |
|
|
|
|
showCopy={true} |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<ValueRow |
|
|
|
|
label="Recipient:" |
|
|
|
|
labelWidth="w-20" |
|
|
|
|
display={recipient} |
|
|
|
|
displayWidth="w-48 sm:w-80" |
|
|
|
|
showCopy={true} |
|
|
|
|
blurValue={shouldBlur} |
|
|
|
|
/> |
|
|
|
|
<div> |
|
|
|
|
<label className="text-sm text-gray-500">Message content:</label> |
|
|
|
|
<div className="relative max-w-full break-words py-2 pl-2 pr-9 mt-2 bg-gray-100 text-sm font-mono rounded"> |
|
|
|
|
{body} |
|
|
|
|
<CopyButton |
|
|
|
|
copyValue={body} |
|
|
|
|
width={15} |
|
|
|
|
height={15} |
|
|
|
|
classes="absolute top-2 right-2 opacity-70" |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</Card> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|