Browse Source

Swap referendum pass/fail to Tag (#2448)

Jaco Greeff 5 years ago
parent
commit
f309743b2f

+ 2 - 3
packages/page-accounts/src/Account.tsx

@@ -7,9 +7,8 @@ import { ActionStatus } from '@polkadot/react-components/Status/types';
 import { RecoveryConfig } from '@polkadot/types/interfaces';
 
 import React, { useCallback, useState, useEffect } from 'react';
-import { Label } from 'semantic-ui-react';
 import styled from 'styled-components';
-import { AddressInfo, AddressSmall, Badge, Button, ChainLock, Forget, Icon, IdentityIcon, InputTags, LinkExternal, Menu, Popup, Input } from '@polkadot/react-components';
+import { AddressInfo, AddressSmall, Badge, Button, ChainLock, Forget, Icon, IdentityIcon, Input, InputTags, LinkExternal, Menu, Popup, Tag } from '@polkadot/react-components';
 import { useApi, useCall, useToggle } from '@polkadot/react-hooks';
 import { Option } from '@polkadot/types';
 import keyring from '@polkadot/ui-keyring';
@@ -309,7 +308,7 @@ function Account ({ address, className, filter, isFavorite, toggleFavorite }: Pr
             <div className='tags--toggle' onClick={toggleEditTags}>
               {tags.length
                 ? tags.map((tag): React.ReactNode => (
-                  <Label key={tag} size='tiny' color='grey'>{tag}</Label>
+                  <Tag key={tag} label={tag} />
                 ))
                 : <label>{t('no tags')}</label>
               }

+ 2 - 3
packages/page-address-book/src/Address.tsx

@@ -7,9 +7,8 @@ import { KeyringAddress } from '@polkadot/ui-keyring/types';
 import { ActionStatus } from '@polkadot/react-components/Status/types';
 
 import React, { useEffect, useState } from 'react';
-import { Label } from 'semantic-ui-react';
 import styled from 'styled-components';
-import { AddressSmall, AddressInfo, Button, ChainLock, Icon, InputTags, Input, LinkExternal, Forget, Menu, Popup } from '@polkadot/react-components';
+import { AddressSmall, AddressInfo, Button, ChainLock, Icon, InputTags, Input, LinkExternal, Forget, Menu, Popup, Tag } from '@polkadot/react-components';
 import { useApi, useCall } from '@polkadot/react-hooks';
 import keyring from '@polkadot/ui-keyring';
 import Transfer from '@polkadot/app-accounts/modals/Transfer';
@@ -222,7 +221,7 @@ function Address ({ address, className, filter, isFavorite, toggleFavorite }: Pr
             <div className='tags--toggle' onClick={_toggleEditTags}>
               {tags.length
                 ? tags.map((tag): React.ReactNode => (
-                  <Label key={tag} size='tiny' color='grey'>{tag}</Label>
+                  <Tag key={tag} label={tag} />
                 ))
                 : <label>{t('no tags')}</label>
               }

+ 4 - 6
packages/page-democracy/src/Overview/Referendum.tsx

@@ -7,7 +7,7 @@ import { BlockNumber } from '@polkadot/types/interfaces';
 
 import React, { useMemo } from 'react';
 import styled from 'styled-components';
-import { AddressMini, Badge, Button, Expander, Icon, LinkExternal } from '@polkadot/react-components';
+import { AddressMini, Button, Expander, LinkExternal, Tag } from '@polkadot/react-components';
 import { useApi, useCall } from '@polkadot/react-hooks';
 import { FormatBalance, BlockToTime } from '@polkadot/react-query';
 import { formatNumber, isBoolean } from '@polkadot/util';
@@ -84,12 +84,10 @@ function Referendum ({ className, value }: Props): React.ReactElement<Props> | n
       </td>
       <td className='padtop top'>
         {isBoolean(isPassing) && (
-          <Badge
+          <Tag
+            color={isPassing ? 'green' : 'red'}
             hover={isPassing ? t('{{threshold}}, passing', { replace: { threshold } }) : t('{{threshold}}, not passing', { replace: { threshold } })}
-            info={<Icon name={isPassing ? 'check' : 'cancel'} />}
-            isInline
-            isTooltip
-            type={isPassing ? 'green' : 'brown'}
+            label={isPassing ? t('passing') : t('failing')}
           />
         )}
       </td>

+ 21 - 31
packages/page-democracy/src/Overview/useIsPassing.ts

@@ -46,17 +46,11 @@ function newtonIteration (n: BN, x0: BN): BN {
   return newtonIteration(n, x1);
 }
 
-// https://golb.hplar.ch/2018/09/javascript-bigint.html
-function sqrt (value: BN): BN {
-  if (value.ltn(0)) {
-    throw new Error('square root of negative numbers is not supported');
-  }
-
-  if (value.ltn(2)) {
-    return value;
-  }
-
-  return newtonIteration(value, new BN(1));
+// TODO Replace with bnSqrt from @polkadot/util once that hits 2.7
+function bnSqrt (value: BN): BN {
+  return value.ltn(2)
+    ? value
+    : newtonIteration(value, new BN(1));
 }
 
 export default function useIsPassing (referendum: DerivedReferendum): boolean | undefined {
@@ -65,26 +59,22 @@ export default function useIsPassing (referendum: DerivedReferendum): boolean |
   const [isPassing, setIsPassing] = useState<boolean | undefined>(undefined);
 
   useEffect((): void => {
-    try {
-      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
-      const { tally, threshold } = (referendum.status as ReferendumStatus);
-
-      if (totalIssuance && tally) {
-        const sqrtVoters = sqrt(tally.turnout);
-        const sqrtElectorate = sqrt(totalIssuance);
-
-        setIsPassing(
-          sqrtVoters.isZero()
-            ? false
-            : threshold.isSimplemajority
-              ? tally.ayes.gt(tally.nays)
-              : threshold.isSupermajorityapproval
-                ? compareRationals(tally.nays, sqrtVoters, tally.ayes, sqrtElectorate)
-                : compareRationals(tally.nays, sqrtElectorate, tally.ayes, sqrtVoters)
-        );
-      }
-    } catch (error) {
-      console.error(error);
+    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
+    const { tally, threshold } = (referendum.status as ReferendumStatus);
+
+    if (totalIssuance && tally) {
+      const sqrtVoters = bnSqrt(tally.turnout);
+      const sqrtElectorate = bnSqrt(totalIssuance);
+
+      setIsPassing(
+        sqrtVoters.isZero()
+          ? false
+          : threshold.isSimplemajority
+            ? tally.ayes.gt(tally.nays)
+            : threshold.isSupermajorityapproval
+              ? compareRationals(tally.nays, sqrtVoters, tally.ayes, sqrtElectorate)
+              : compareRationals(tally.nays, sqrtElectorate, tally.ayes, sqrtVoters)
+      );
     }
   }, [referendum, totalIssuance]);
 

+ 3 - 3
packages/react-components/src/Badge.tsx

@@ -22,12 +22,12 @@ interface Props {
 let badgeId = 0;
 
 function Badge ({ className, hover, info, isGray, isInline, isSmall, isTooltip, onClick, type }: Props): React.ReactElement<Props> | null {
-  const [key] = useState(`${Date.now()}-${badgeId++}`);
+  const [trigger] = useState(`badge-hover-${Date.now()}-${badgeId++}`);
 
   return (
     <div
       className={`ui--Badge ${isGray && 'isGray'} ${isInline && 'isInline'} ${isTooltip && 'isTooltip'} ${isSmall && 'isSmall'} ${onClick && 'isClickable'} ${type} ${className}`}
-      data-for={`badge-status-${key}`}
+      data-for={trigger}
       data-tip={true}
       data-tip-disable={!isTooltip}
       onClick={onClick}
@@ -40,7 +40,7 @@ function Badge ({ className, hover, info, isGray, isInline, isSmall, isTooltip,
       </div>
       {hover && (
         <Tooltip
-          trigger={`badge-status-${key}`}
+          trigger={trigger}
           text={hover}
         />
       )}

+ 2 - 2
packages/react-components/src/Row.tsx

@@ -5,7 +5,6 @@
 import { DeriveAccountInfo } from '@polkadot/api-derive/types';
 import { KeyringItemType } from '@polkadot/ui-keyring/types';
 
-import { Label } from 'semantic-ui-react';
 import React from 'react';
 
 import Button from './Button';
@@ -13,6 +12,7 @@ import { classes, toShortAddress } from './util';
 import CopyButton from './CopyButton';
 import Input from './Input';
 import InputTags from './InputTags';
+import Tag from './Tag';
 
 export const styles = `
   text-align: left;
@@ -354,7 +354,7 @@ export default class Row<P extends RowProps, S extends RowState> extends React.P
             !tags.length
               ? (isEditable ? <span className='addTags'>add tags</span> : undefined)
               : tags.map((tag): React.ReactNode => (
-                <Label key={tag} size='tiny' color='grey'>{tag}</Label>
+                <Tag key={tag} label={tag} />
               ))
           }
           {isEditable && this.renderEditIcon()}

+ 42 - 0
packages/react-components/src/Tag.tsx

@@ -0,0 +1,42 @@
+// Copyright 2017-2020 @polkadot/react-components authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import React, { useState } from 'react';
+import { Label } from 'semantic-ui-react';
+
+import Tooltip from './Tooltip';
+
+interface Props {
+  className?: string;
+  color?: 'green' | 'grey' | 'red';
+  hover?: React.ReactNode;
+  label: React.ReactNode;
+}
+
+let tagId = 0;
+
+function Tag ({ className, color, hover, label }: Props): React.ReactElement<Props> {
+  const [trigger] = useState(`tag-hover-${Date.now()}-${tagId++}`);
+
+  return (
+    <Label
+      className={className}
+      color={color || 'grey'}
+      data-for={trigger}
+      data-tip={true}
+      size='small'
+      tag
+    >
+      {label}
+      {hover && (
+        <Tooltip
+          trigger={trigger}
+          text={hover}
+        />
+      )}
+    </Label>
+  );
+}
+
+export default React.memo(Tag);

+ 1 - 0
packages/react-components/src/index.tsx

@@ -77,6 +77,7 @@ export { default as Status, StatusContext } from './Status';
 export { default as SummaryBox } from './SummaryBox';
 export { default as Table } from './Table';
 export { default as Tabs } from './Tabs';
+export { default as Tag } from './Tag';
 export { default as Toggle } from './Toggle';
 export { default as Tooltip } from './Tooltip';
 export { default as TxButton } from './TxButton';