// Copyright 2017-2021 @polkadot/react-components authors & contributors // SPDX-License-Identifier: Apache-2.0 import type { IconName } from '@fortawesome/fontawesome-svg-core'; import type { QueueStatus, QueueTx, QueueTxStatus } from './types'; import React, { useCallback, useContext, useEffect, useState } from 'react'; import styled from 'styled-components'; import AddressMini from '../AddressMini'; import Button from '../Button'; import Icon from '../Icon'; import Spinner from '../Spinner'; import { useTranslation } from '../translate'; import { STATUS_COMPLETE } from './constants'; import StatusContext from './Context'; export { StatusContext }; interface Props { className?: string; } function iconName (status: string): IconName { switch (status) { case 'error': return 'ban'; case 'event': return 'assistive-listening-systems'; case 'received': return 'telegram-plane'; default: return 'check'; } } function signerIconName (status: QueueTxStatus): IconName { switch (status) { case 'cancelled': return 'ban'; case 'completed': case 'inblock': case 'finalized': case 'sent': return 'check'; case 'dropped': case 'invalid': case 'usurped': return 'arrow-down'; case 'error': case 'finalitytimeout': return 'exclamation-triangle'; case 'queued': // case 'retracted': return 'random'; default: return 'spinner'; } } function renderStatus ({ account, action, id, message, removeItem, status }: QueueStatus): React.ReactNode { return (
{Array.isArray(action) ? action.map((action, index) =>
{action}
) : action}
{account && ( )}
{message}
); } function renderItem ({ error, extrinsic, id, removeItem, rpc, status }: QueueTx): React.ReactNode { let { method, section } = rpc; if (extrinsic) { const found = extrinsic.registry.findMetaCall(extrinsic.callIndex); if (found.section !== 'unknown') { method = found.method; section = found.section; } } const icon = signerIconName(status) as 'ban' | 'spinner'; return (
{STATUS_COMPLETE.includes(status) && ( )}
{icon === 'spinner' ? : }
{section}.{method}
{error ? (error.message || error) : status}
); } function filterSt (stqueue?: QueueStatus[]): QueueStatus[] { return (stqueue || []).filter(({ isCompleted }) => !isCompleted); } function filterTx (txqueue?: QueueTx[]): [QueueTx[], QueueTx[]] { const allTx = (txqueue || []).filter(({ status }) => !['completed', 'incomplete'].includes(status)); return [allTx, allTx.filter(({ status }) => STATUS_COMPLETE.includes(status))]; } function Status ({ className = '' }: Props): React.ReactElement | null { const { stqueue, txqueue } = useContext(StatusContext); const [allSt, setAllSt] = useState([]); const [[allTx, completedTx], setAllTx] = useState<[QueueTx[], QueueTx[]]>([[], []]); const { t } = useTranslation(); useEffect((): void => { setAllSt(filterSt(stqueue)); }, [stqueue]); useEffect((): void => { setAllTx(filterTx(txqueue)); }, [txqueue]); const _onDismiss = useCallback( (): void => { allSt.map((s) => s.removeItem()); completedTx.map((t) => t.removeItem()); }, [allSt, completedTx] ); if (!allSt.length && !allTx.length) { return null; } return (
{(allSt.length + completedTx.length) > 1 && (
)} {allTx.map(renderItem)} {allSt.map(renderStatus)}
); } export default React.memo(styled(Status)` display: inline-block; position: fixed; right: 0.75rem; top: 0.75rem; width: 23rem; z-index: 1001; .dismiss { margin-bottom: 0.25rem; .ui--Button { border: 1px solid white; } } .item { display: block; > .wrapper > .container { align-items: center; background: #00688b; border-radius: 0.25rem; color: white; display: flex; justify-content: space-between; margin-bottom: 0.25rem; padding: 0 0.5rem; vertical-align: middle; position: relative; .desc { flex: 1; overflow: hidden; padding: 0.5rem 1rem; .status { font-weight: var(--font-weight-normal); } .ui--AddressMini { .ui--AddressMini-address { min-width: 0; text-align: left; } } } .header { opacity: 0.66; } .short { font-size: 2.5rem; opacity: 0.75; padding: 0.5rem 0 0.5rem 0.5rem; .ui--Icon { color: white !important; line-height: 1; } } .padded { padding: 0.25rem 0 0 0 !important; } .ui--Icon.isClickable { position: absolute; top: 0.5rem; right: 0.5rem; cursor: pointer; } } &.cancelled > .wrapper > .container { background: #cd9b1d } &.event > .wrapper > .container { background: teal; } &.completed, &.finalized, &.inblock, &.sent, &.success { & > .wrapper > .container { background: green; } } &.dropped, &.error, &.finalitytimeout, &.invalid, &.usurped { & > .wrapper > .container { background: red; } } } `);