React.memo-ize more func. components (#2389)
* React.memo-ize more func. components * Rework status display determination * isApiReady && * ApiSigner private class interface * readonly # * Remove isPrimary on council vote
This commit is contained in:
parent
6530e49c3e
commit
e97868348b
@ -10,8 +10,10 @@ type Props = {};
|
||||
|
||||
const defaultTo = `/${routing.default}`;
|
||||
|
||||
export default function NotFound (): React.ReactElement<Props> {
|
||||
function NotFound (): React.ReactElement<Props> {
|
||||
return (
|
||||
<Redirect to={defaultTo} />
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(NotFound);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
// Copyright 2017-2020 @polkadot/apps authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
@ -24,54 +23,58 @@ interface Props {
|
||||
|
||||
let prevEventHash: string;
|
||||
|
||||
export default function Status ({ optionsAll, queueAction, stqueue, txqueue }: Props): React.ReactElement<Props> {
|
||||
function filterEvents (allAccounts: string[], t: (key: string, opts?: object) => string, optionsAll?: KeyringOptions, events?: EventRecord[]): ActionStatus[] | null {
|
||||
const eventHash = xxhashAsHex(stringToU8a(JSON.stringify(events)));
|
||||
|
||||
if (!optionsAll || !events || eventHash === prevEventHash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
prevEventHash = eventHash;
|
||||
|
||||
return events
|
||||
.map(({ event: { data, method, section } }): ActionStatus | null => {
|
||||
if (section === 'balances' && method === 'Transfer') {
|
||||
const account = data[1].toString();
|
||||
|
||||
if (allAccounts.includes(account)) {
|
||||
return {
|
||||
account,
|
||||
action: `${section}.${method}`,
|
||||
status: 'event',
|
||||
message: t('transfer received')
|
||||
};
|
||||
}
|
||||
} else if (section === 'democracy') {
|
||||
const index = data[0].toString();
|
||||
|
||||
return {
|
||||
action: `${section}.${method}`,
|
||||
status: 'event',
|
||||
message: t('update on #{{index}}', {
|
||||
replace: {
|
||||
index
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
.filter((item): item is ActionStatus => !!item);
|
||||
}
|
||||
|
||||
function Status ({ optionsAll, queueAction, stqueue, txqueue }: Props): React.ReactElement<Props> {
|
||||
const { api, isApiReady } = useApi();
|
||||
const { allAccounts } = useAccounts();
|
||||
const { t } = useTranslation();
|
||||
const events = useCall<EventRecord[]>(isApiReady ? api.query.system?.events : undefined, []);
|
||||
const events = useCall<EventRecord[]>(isApiReady && api.query.system?.events, []);
|
||||
|
||||
useEffect((): void => {
|
||||
const eventHash = xxhashAsHex(stringToU8a(JSON.stringify(events)));
|
||||
const filtered = filterEvents(allAccounts, t, optionsAll, events);
|
||||
|
||||
if (!optionsAll || eventHash === prevEventHash) {
|
||||
return;
|
||||
}
|
||||
|
||||
prevEventHash = eventHash;
|
||||
|
||||
const statusses = events && events
|
||||
.map(({ event: { data, method, section } }): ActionStatus | null => {
|
||||
if (section === 'balances' && method === 'Transfer') {
|
||||
const account = data[1].toString();
|
||||
|
||||
if (allAccounts.includes(account)) {
|
||||
return {
|
||||
account,
|
||||
action: `${section}.${method}`,
|
||||
status: 'event',
|
||||
message: t('transfer received')
|
||||
};
|
||||
}
|
||||
} else if (section === 'democracy') {
|
||||
const index = data[0].toString();
|
||||
|
||||
return {
|
||||
action: `${section}.${method}`,
|
||||
status: 'event',
|
||||
message: t('update on #{{index}}', {
|
||||
replace: {
|
||||
index
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
.filter((item): boolean => !!item) as ActionStatus[];
|
||||
|
||||
statusses && statusses.length && queueAction(statusses);
|
||||
}, [events]);
|
||||
filtered && queueAction(filtered);
|
||||
}, [allAccounts, events, optionsAll]);
|
||||
|
||||
return (
|
||||
<StatusDisplay
|
||||
@ -80,3 +83,5 @@ export default function Status ({ optionsAll, queueAction, stqueue, txqueue }: P
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Status);
|
||||
|
||||
@ -73,12 +73,12 @@ function checkVisible (name: string, { api, isApiReady, isApiConnected }: ApiPro
|
||||
return notFound.length === 0;
|
||||
}
|
||||
|
||||
export default function Item ({ route, isCollapsed, onClick }: Props): React.ReactElement<Props> | null {
|
||||
function Item ({ route, isCollapsed, onClick }: Props): React.ReactElement<Props> | null {
|
||||
const { Modal, useCounter = DUMMY_COUNTER, display, i18n, icon, name } = route;
|
||||
const { t } = useTranslation();
|
||||
const { allAccounts, hasAccounts } = useAccounts();
|
||||
const apiProps = useApi();
|
||||
const sudoKey = useCall<AccountId>(apiProps.isApiReady ? apiProps.api.query.sudo?.key : undefined, []);
|
||||
const sudoKey = useCall<AccountId>(apiProps.isApiReady && apiProps.api.query.sudo?.key, []);
|
||||
const [hasSudo, setHasSudo] = useState(false);
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const count = useCounter();
|
||||
@ -149,3 +149,5 @@ export default function Item ({ route, isCollapsed, onClick }: Props): React.Rea
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Item);
|
||||
|
||||
@ -5,12 +5,12 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
export default function WarmUp (): React.ReactElement {
|
||||
function WarmUp (): React.ReactElement {
|
||||
const { api, isApiReady } = useApi();
|
||||
const fees = useCall<any>(isApiReady && api.derive.balances?.fees, []);
|
||||
const indexes = useCall<any>(isApiReady && api.derive.accounts?.indexes, []);
|
||||
const registrars = useCall<any>(isApiReady && api.query.identity?.registrars, []);
|
||||
const staking = null; // useCall<any>(isApiReady ? api.derive.staking?.overview : undefined, []);
|
||||
const fees = useCall<unknown>(isApiReady && api.derive.balances?.fees, []);
|
||||
const indexes = useCall<unknown>(isApiReady && api.derive.accounts?.indexes, []);
|
||||
const registrars = useCall<unknown>(isApiReady && api.query.identity?.registrars, []);
|
||||
const staking = null; // useCall<unknown>(isApiReady && api.derive.staking?.overview, []);
|
||||
const [hasValues, setHasValues] = useState(false);
|
||||
|
||||
useEffect((): void => {
|
||||
@ -21,3 +21,5 @@ export default function WarmUp (): React.ReactElement {
|
||||
<div className={`apps--api-warm ${hasValues}`} />
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(WarmUp);
|
||||
|
||||
@ -13,7 +13,7 @@ interface Props {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function NetworkModal ({ className, onClose }: Props): React.ReactElement<Props> {
|
||||
function NetworkModal ({ className, onClose }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -30,3 +30,5 @@ export default function NetworkModal ({ className, onClose }: Props): React.Reac
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(NetworkModal);
|
||||
|
||||
@ -71,7 +71,6 @@ export default function Voting ({ hash, idNumber, isDisabled, members, prime, pr
|
||||
<Button
|
||||
icon='check'
|
||||
isDisabled={isDisabled}
|
||||
isPrimary
|
||||
label={t('Vote')}
|
||||
onClick={toggleVoting}
|
||||
/>
|
||||
|
||||
@ -9,7 +9,7 @@ import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
export default function useCounter (): number {
|
||||
const { api, isApiReady } = useApi();
|
||||
const motions = useCall<DerivedCollectiveProposals>(isApiReady ? api.derive.council?.proposals : undefined, []);
|
||||
const motions = useCall<DerivedCollectiveProposals>(isApiReady && api.derive.council?.proposals, []);
|
||||
const [counter, setCounter] = useState(0);
|
||||
|
||||
useEffect((): void => {
|
||||
|
||||
@ -7,8 +7,8 @@ import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
export default function useCounter (): number {
|
||||
const { api, isApiReady } = useApi();
|
||||
const proposals = useCall<any[]>(isApiReady ? api.derive.democracy?.proposals : undefined, []);
|
||||
const referenda = useCall<any[]>(isApiReady ? api.derive.democracy?.referendums : undefined, []);
|
||||
const proposals = useCall<any[]>(isApiReady && api.derive.democracy?.proposals, []);
|
||||
const referenda = useCall<any[]>(isApiReady && api.derive.democracy?.referendums, []);
|
||||
const [counter, setCounter] = useState(0);
|
||||
|
||||
useEffect((): void => {
|
||||
|
||||
@ -9,7 +9,7 @@ import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
export default function useCounter (): number {
|
||||
const { api, isApiReady } = useApi();
|
||||
const proposals = useCall<Hash[]>(isApiReady ? api.query.technicalCommittee?.proposals : undefined, []);
|
||||
const proposals = useCall<Hash[]>(isApiReady && api.query.technicalCommittee?.proposals, []);
|
||||
const [counter, setCounter] = useState(0);
|
||||
|
||||
useEffect((): void => {
|
||||
|
||||
@ -9,7 +9,7 @@ import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
export default function useCounter (): number {
|
||||
const { api, isApiReady } = useApi();
|
||||
const proposals = useCall<DerivedTreasuryProposals>(isApiReady ? api.derive.treasury?.proposals : undefined, []);
|
||||
const proposals = useCall<DerivedTreasuryProposals>(isApiReady && api.derive.treasury?.proposals, []);
|
||||
const [counter, setCounter] = useState(0);
|
||||
|
||||
useEffect((): void => {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
import { QueueStatus, QueueTx, QueueTxStatus } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { registry } from '@polkadot/react-api';
|
||||
|
||||
@ -149,38 +149,53 @@ function renderItem ({ id, extrinsic, error, removeItem, rpc, status }: QueueTx)
|
||||
);
|
||||
}
|
||||
|
||||
function Status ({ className, stqueue = [], txqueue = [] }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const allst: QueueStatus[] = stqueue.filter(({ isCompleted }): boolean => !isCompleted);
|
||||
const alltx: QueueTx[] = txqueue.filter(({ status }): boolean =>
|
||||
!['completed', 'incomplete'].includes(status)
|
||||
);
|
||||
const completedTx = alltx.filter(({ status }): boolean => STATUS_COMPLETE.includes(status));
|
||||
function filterSt (stqueue?: QueueStatus[]): QueueStatus[] {
|
||||
return (stqueue || []).filter(({ isCompleted }): boolean => !isCompleted);
|
||||
}
|
||||
|
||||
if (!allst.length && !alltx.length) {
|
||||
function filterTx (txqueue?: QueueTx[]): [QueueTx[], QueueTx[]] {
|
||||
const allTx = (txqueue || []).filter(({ status }): boolean => !['completed', 'incomplete'].includes(status));
|
||||
|
||||
return [allTx, allTx.filter(({ status }): boolean => STATUS_COMPLETE.includes(status))];
|
||||
}
|
||||
|
||||
function Status ({ className, stqueue, txqueue }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const allSt = useMemo(
|
||||
(): QueueStatus[] => filterSt(stqueue),
|
||||
[stqueue]
|
||||
);
|
||||
const [allTx, completedTx] = useMemo(
|
||||
(): [QueueTx[], QueueTx[]] => filterTx(txqueue),
|
||||
[txqueue]
|
||||
);
|
||||
const _onDismiss = useCallback(
|
||||
(): void => {
|
||||
allSt.map((s): void => s.removeItem());
|
||||
completedTx.map((t): void => t.removeItem());
|
||||
},
|
||||
[allSt, completedTx]
|
||||
);
|
||||
|
||||
if (!allSt.length && !allTx.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _onDismiss = (): void => {
|
||||
allst.map((s): void => s.removeItem());
|
||||
completedTx.map((t): void => t.removeItem());
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`ui--Status ${className}`}>
|
||||
{(allst.length + completedTx.length) > 1 && (
|
||||
{(allSt.length + completedTx.length) > 1 && (
|
||||
<div className='dismiss'>
|
||||
<Button
|
||||
isFluid
|
||||
isNegative
|
||||
isPrimary
|
||||
onClick={_onDismiss}
|
||||
label={t('Dismiss all notifications')}
|
||||
icon='cancel'
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{alltx.map(renderItem)}
|
||||
{allst.map(renderStatus)}
|
||||
{allTx.map(renderItem)}
|
||||
{allSt.map(renderStatus)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ interface Props extends BareProps {
|
||||
|
||||
export default function BestNumber ({ children, className, label, style, withPound }: Props): React.ReactElement<Props> {
|
||||
const { api, isApiReady } = useApi();
|
||||
const bestNumber = useCall<BlockNumber>(isApiReady ? api.derive.chain.bestNumber as any : undefined, []);
|
||||
const bestNumber = useCall<BlockNumber>(isApiReady && api.derive.chain.bestNumber, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@ -12,18 +12,18 @@ import { registry } from '@polkadot/react-api';
|
||||
import { ClassOf } from '@polkadot/types';
|
||||
|
||||
export default class ApiSigner implements Signer {
|
||||
private _queuePayload: QueueTxPayloadAdd;
|
||||
readonly #queuePayload: QueueTxPayloadAdd;
|
||||
|
||||
private _queueSetTxStatus: QueueTxMessageSetStatus;
|
||||
readonly #queueSetTxStatus: QueueTxMessageSetStatus;
|
||||
|
||||
constructor (queuePayload: QueueTxPayloadAdd, queueSetTxStatus: QueueTxMessageSetStatus) {
|
||||
this._queuePayload = queuePayload;
|
||||
this._queueSetTxStatus = queueSetTxStatus;
|
||||
this.#queuePayload = queuePayload;
|
||||
this.#queueSetTxStatus = queueSetTxStatus;
|
||||
}
|
||||
|
||||
public async signPayload (payload: SignerPayloadJSON): Promise<SignerResult> {
|
||||
return new Promise((resolve, reject): void => {
|
||||
this._queuePayload(payload, (id: number, result: SignerResult | null): void => {
|
||||
this.#queuePayload(payload, (id: number, result: SignerResult | null): void => {
|
||||
if (result) {
|
||||
resolve(result);
|
||||
} else {
|
||||
@ -35,9 +35,9 @@ export default class ApiSigner implements Signer {
|
||||
|
||||
public update (id: number, result: Hash | SubmittableResult): void {
|
||||
if (result instanceof ClassOf(registry, 'Hash')) {
|
||||
this._queueSetTxStatus(id, 'sent', result.toHex());
|
||||
this.#queueSetTxStatus(id, 'sent', result.toHex());
|
||||
} else {
|
||||
this._queueSetTxStatus(id, result.status.type.toLowerCase() as QueueTxStatus, status);
|
||||
this.#queueSetTxStatus(id, result.status.type.toLowerCase() as QueueTxStatus, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user