// 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;
}
}
}
`);