From ea711c9e7731237bc987aa2e0f493d41488fb907 Mon Sep 17 00:00:00 2001 From: Leszek Wiesner Date: Wed, 12 Aug 2020 11:01:21 +0200 Subject: [PATCH 01/15] Adjust polkadot-js/apps and joy-utils, reactivate joy-members --- package.json | 5 +- pioneer/.eslintignore | 3 - .../apps-config/src/api/spec/index.ts | 4 +- .../src/api/spec/joystream-node.ts | 3 + .../apps-config/src/settings/endpoints.ts | 5 + .../apps-config/src/ui/logos/index.ts | 4 +- .../src/ui/logos/nodes/joystream-node.svg | 15 + pioneer/packages/apps-routing/src/index.ts | 58 +--- .../packages/apps-routing/src/joy-members.ts | 15 + .../packages/apps-routing/src/joy-pages.ts | 27 ++ pioneer/packages/apps/src/Apps.tsx | 15 +- pioneer/packages/apps/src/Content/index.tsx | 8 +- .../packages/apps/src/JoyTopBar/TopBar.tsx | 58 ++++ .../packages/apps/src/SideBar/ChainInfo.tsx | 2 +- pioneer/packages/apps/src/SideBar/index.tsx | 27 +- pioneer/packages/apps/src/index.tsx | 33 +- pioneer/packages/joy-members/.skip-build | 0 pioneer/packages/joy-members/package.json | 6 +- .../packages/joy-members/src/Dashboard.tsx | 76 +++-- pioneer/packages/joy-members/src/Details.tsx | 8 +- .../joy-members/src/DetailsByHandle.tsx | 4 +- pioneer/packages/joy-members/src/EditForm.tsx | 63 ++-- pioneer/packages/joy-members/src/List.tsx | 10 +- .../joy-members/src/MemberPreview.tsx | 7 +- pioneer/packages/joy-members/src/index.css | 58 ---- pioneer/packages/joy-members/src/index.tsx | 20 +- pioneer/packages/joy-members/src/style.ts | 62 ++++ pioneer/packages/joy-members/src/utils.ts | 5 +- pioneer/packages/joy-pages/.skip-build | 0 pioneer/packages/joy-pages/package.json | 6 +- .../joy-utils-old/src/functions/misc.ts | 14 - .../src/react/components/index.tsx | 1 - .../joy-utils-old/src/react/context/index.tsx | 1 - .../{joy-utils-old => joy-utils}/README.md | 0 .../{joy-utils-old => joy-utils}/package.json | 6 +- .../src/functions/date.ts | 0 .../src/functions/format.ts | 0 .../packages/joy-utils/src/functions/misc.ts | 157 ++++++++++ .../src/react/components}/FlexCenter.tsx | 0 .../src/react/components}/MutedText.tsx | 0 .../src/react/components}/Section.tsx | 0 .../src/react/components}/TxButton.tsx | 94 +++--- .../src/react/components}/forms.tsx | 3 +- .../joy-utils/src/react/components/index.tsx | 4 + .../src/react/context/account.tsx} | 27 +- .../joy-utils/src/react/context/index.tsx | 2 + .../src/react/context/membership.tsx} | 8 +- .../src/react/helpers/index.ts | 0 .../joy-utils/src/react/hocs/accounts.tsx | 113 +++++++ .../joy-utils/src/react/hocs/guards.tsx | 100 ++++++ .../joy-utils/src/react/hooks/index.ts | 2 + .../src/react/hooks/useMyAccount.tsx | 6 + .../src/react/hooks/useMyMembership.tsx | 6 + .../old-apps/apps-routing/src/joy-pages.ts | 28 -- pioneer/packages/old-apps/apps/src/TopBar.css | 17 -- pioneer/packages/old-apps/apps/src/TopBar.tsx | 47 --- .../src/styles/old-theme.ts-unused | 11 - .../src/InputAddress/index.tsx | 7 + .../react-components/src/Tabs/Tab.tsx | 7 +- .../react-components/src/Tabs/types.ts | 1 + .../react-components/src/styles/index.ts | 4 +- .../react-components/src/styles/joystream.ts | 24 +- .../react-components/src/styles/theme.ts | 2 +- pioneer/tsconfig.json | 16 +- yarn.lock | 286 +++++++++++++++++- 65 files changed, 1138 insertions(+), 463 deletions(-) create mode 100644 pioneer/packages/apps-config/src/api/spec/joystream-node.ts create mode 100644 pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg create mode 100644 pioneer/packages/apps-routing/src/joy-members.ts create mode 100644 pioneer/packages/apps-routing/src/joy-pages.ts create mode 100644 pioneer/packages/apps/src/JoyTopBar/TopBar.tsx delete mode 100644 pioneer/packages/joy-members/.skip-build delete mode 100644 pioneer/packages/joy-members/src/index.css create mode 100644 pioneer/packages/joy-members/src/style.ts delete mode 100644 pioneer/packages/joy-pages/.skip-build delete mode 100644 pioneer/packages/joy-utils-old/src/functions/misc.ts delete mode 100644 pioneer/packages/joy-utils-old/src/react/components/index.tsx delete mode 100644 pioneer/packages/joy-utils-old/src/react/context/index.tsx rename pioneer/packages/{joy-utils-old => joy-utils}/README.md (100%) rename pioneer/packages/{joy-utils-old => joy-utils}/package.json (80%) rename pioneer/packages/{joy-utils-old => joy-utils}/src/functions/date.ts (100%) rename pioneer/packages/{joy-utils-old => joy-utils}/src/functions/format.ts (100%) create mode 100644 pioneer/packages/joy-utils/src/functions/misc.ts rename pioneer/packages/{joy-utils-old/src => joy-utils/src/react/components}/FlexCenter.tsx (100%) rename pioneer/packages/{joy-utils-old/src => joy-utils/src/react/components}/MutedText.tsx (100%) rename pioneer/packages/{joy-utils-old/src => joy-utils/src/react/components}/Section.tsx (100%) rename pioneer/packages/{joy-utils-old/src => joy-utils/src/react/components}/TxButton.tsx (60%) rename pioneer/packages/{joy-utils-old/src => joy-utils/src/react/components}/forms.tsx (97%) create mode 100644 pioneer/packages/joy-utils/src/react/components/index.tsx rename pioneer/packages/{joy-utils-old/src/MyAccountContext.tsx => joy-utils/src/react/context/account.tsx} (77%) create mode 100644 pioneer/packages/joy-utils/src/react/context/index.tsx rename pioneer/packages/{joy-utils-old/src/MyMembershipContext.tsx => joy-utils/src/react/context/membership.tsx} (64%) rename pioneer/packages/{joy-utils-old => joy-utils}/src/react/helpers/index.ts (100%) create mode 100644 pioneer/packages/joy-utils/src/react/hocs/accounts.tsx create mode 100644 pioneer/packages/joy-utils/src/react/hocs/guards.tsx create mode 100644 pioneer/packages/joy-utils/src/react/hooks/index.ts create mode 100644 pioneer/packages/joy-utils/src/react/hooks/useMyAccount.tsx create mode 100644 pioneer/packages/joy-utils/src/react/hooks/useMyMembership.tsx delete mode 100644 pioneer/packages/old-apps/apps-routing/src/joy-pages.ts delete mode 100644 pioneer/packages/old-apps/apps/src/TopBar.css delete mode 100644 pioneer/packages/old-apps/apps/src/TopBar.tsx delete mode 100644 pioneer/packages/old-apps/react-components/src/styles/old-theme.ts-unused rename pioneer/packages/{old-apps => }/react-components/src/styles/joystream.ts (90%) diff --git a/package.json b/package.json index 00ca16a54f..ee308b7e1c 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,10 @@ "pioneer", "pioneer/packages/apps*", "pioneer/packages/page*", - "pioneer/packages/react*" + "pioneer/packages/react*", + "pioneer/packages/joy-utils", + "pioneer/packages/joy-members", + "pioneer/packages/joy-pages" ], "resolutions": { "@polkadot/api": "^1.26.1", diff --git a/pioneer/.eslintignore b/pioneer/.eslintignore index e24e58eaba..42a2471efd 100644 --- a/pioneer/.eslintignore +++ b/pioneer/.eslintignore @@ -2,16 +2,13 @@ **/coverage/* **/node_modules/* packages/old-apps/* -packages/joy-members/* packages/joy-election/* packages/joy-forum/* packages/joy-help/* packages/joy-media/* -packages/joy-pages/* packages/joy-proposals/* packages/joy-roles/* packages/joy-settings/* -packages/joy-utils/* packages/joy-utils-old/* .eslintrc.js i18next-scanner.config.js diff --git a/pioneer/packages/apps-config/src/api/spec/index.ts b/pioneer/packages/apps-config/src/api/spec/index.ts index d65760b541..22e2122aeb 100644 --- a/pioneer/packages/apps-config/src/api/spec/index.ts +++ b/pioneer/packages/apps-config/src/api/spec/index.ts @@ -10,6 +10,7 @@ import encointerNodeTeeproxy from './encointer-node-teeproxy'; import kulupu from './kulupu'; import nodeTemplate from './node-template'; import stablePoc from './stable-poc'; +import joystreamNode from './joystream-node'; export default { acala, @@ -21,5 +22,6 @@ export default { kulupu, 'node-template': nodeTemplate, 'stable-poc': stablePoc, - stable_poc: stablePoc + stable_poc: stablePoc, + 'joystream-node': joystreamNode }; diff --git a/pioneer/packages/apps-config/src/api/spec/joystream-node.ts b/pioneer/packages/apps-config/src/api/spec/joystream-node.ts new file mode 100644 index 0000000000..7e436a96d4 --- /dev/null +++ b/pioneer/packages/apps-config/src/api/spec/joystream-node.ts @@ -0,0 +1,3 @@ +import { types } from '@joystream/types'; + +export default types; diff --git a/pioneer/packages/apps-config/src/settings/endpoints.ts b/pioneer/packages/apps-config/src/settings/endpoints.ts index 0b1b5dd42c..c7d662f519 100644 --- a/pioneer/packages/apps-config/src/settings/endpoints.ts +++ b/pioneer/packages/apps-config/src/settings/endpoints.ts @@ -29,6 +29,11 @@ function createDev (t: TFunction): LinkOption[] { function createLive (t: TFunction): LinkOption[] { return [ + { + info: 'joystream', + text: t('rpc.joystream', 'Joystream (Current Testnet, hosted by Jsgenesis)', { ns: 'apps-config' }), + value: 'wss://rome-rpc-endpoint.joystream.org:9944' + }, { dnslink: 'polkadot', info: 'polkadot', diff --git a/pioneer/packages/apps-config/src/ui/logos/index.ts b/pioneer/packages/apps-config/src/ui/logos/index.ts index 93f37ff13f..b4d0036715 100644 --- a/pioneer/packages/apps-config/src/ui/logos/index.ts +++ b/pioneer/packages/apps-config/src/ui/logos/index.ts @@ -17,6 +17,7 @@ import nodeNodle from './nodes/nodle.svg'; import nodePolkadot from './nodes/polkadot-circle.svg'; import nodePolkadotJs from './nodes/polkadot-js.svg'; import nodeSubstrate from './nodes/substrate-hexagon.svg'; +import nodeJoystream from './nodes/joystream-node.svg'; // extensions import extensionPolkadotJs from './extensions/polkadot-js.svg'; @@ -48,7 +49,8 @@ const nodeLogos: Record = [ ['Nodle Chain Node', nodeNodle], ['parity-polkadot', nodePolkadot], ['polkadot-js', nodePolkadotJs], - ['substrate-node', nodeSubstrate] + ['substrate-node', nodeSubstrate], + ['joystream-node', nodeJoystream] ].reduce((logos, [node, logo]): Record => ({ ...logos, [(node as string).toLowerCase().replace(/-/g, ' ')]: logo diff --git a/pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg b/pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg new file mode 100644 index 0000000000..d032d300fd --- /dev/null +++ b/pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg @@ -0,0 +1,15 @@ + + + background + + + + + + + Layer 1 + + + + + diff --git a/pioneer/packages/apps-routing/src/index.ts b/pioneer/packages/apps-routing/src/index.ts index cc5eab5943..f4ba69e507 100644 --- a/pioneer/packages/apps-routing/src/index.ts +++ b/pioneer/packages/apps-routing/src/index.ts @@ -9,69 +9,43 @@ import appSettings from '@polkadot/ui-settings'; // When adding here, also ensure to add to Dummy.tsx import accounts from './accounts'; -import claims from './claims'; -import contracts from './contracts'; -import council from './council'; -// import dashboard from './dashboard'; -import democracy from './democracy'; import explorer from './explorer'; import extrinsics from './extrinsics'; -import genericAsset from './generic-asset'; import js from './js'; -import parachains from './parachains'; -import poll from './poll'; import settings from './settings'; -import society from './society'; -import staking from './staking'; import storage from './storage'; import sudo from './sudo'; -import techcomm from './techcomm'; import toolbox from './toolbox'; import transfer from './transfer'; -import treasury from './treasury'; +// Joy packages +import members from './joy-members'; +import { terms, privacyPolicy } from './joy-pages'; export default function create (t: (key: string, text: string, options: { ns: string }) => T): Routes { return appSettings.uiMode === 'light' ? [ - // dashboard, - explorer(t), - accounts(t), - claims(t), - poll(t), - transfer(t), - genericAsset(t), - null, - staking(t), - democracy(t), - council(t), - // TODO Not sure about the inclusion of treasury, parachains & society here + members(t), null, + transfer(t), + accounts(t), settings(t) ] : [ - // dashboard(t), - explorer(t), - accounts(t), - claims(t), - poll(t), - transfer(t), - genericAsset(t), + members(t), null, - staking(t), - democracy(t), - council(t), - treasury(t), - techcomm(t), - parachains(t), - society(t), + transfer(t), + accounts(t), + settings(t), null, - contracts(t), + explorer(t), storage(t), extrinsics(t), + js(t), + toolbox(t), sudo(t), null, - settings(t), - toolbox(t), - js(t) + // Those are hidden + terms(t), + privacyPolicy(t) ]; } diff --git a/pioneer/packages/apps-routing/src/joy-members.ts b/pioneer/packages/apps-routing/src/joy-members.ts new file mode 100644 index 0000000000..e8c3712d4d --- /dev/null +++ b/pioneer/packages/apps-routing/src/joy-members.ts @@ -0,0 +1,15 @@ +import { Route } from './types'; + +import Members from '@polkadot/joy-members/index'; + +export default function create (t: (key: string, text: string, options: { ns: string }) => T): Route { + return { + Component: Members, + display: { + needsApi: ['query.members.nextMemberId'] + }, + icon: 'users', + name: 'members', + text: t('nav.membership', 'Membership', { ns: 'apps-routing' }) + }; +} diff --git a/pioneer/packages/apps-routing/src/joy-pages.ts b/pioneer/packages/apps-routing/src/joy-pages.ts new file mode 100644 index 0000000000..a39470e322 --- /dev/null +++ b/pioneer/packages/apps-routing/src/joy-pages.ts @@ -0,0 +1,27 @@ +import { Route } from './types'; + +import { ToS, Privacy } from '@polkadot/joy-pages/index'; + +export function terms (t: (key: string, text: string, options: { ns: string }) => T): Route { + return { + Component: ToS, + display: { + isHidden: true + }, + text: t('nav.terms', 'Terms of Service', { ns: 'apps-routing' }), + icon: 'file', + name: 'pages/tos' + }; +} + +export function privacyPolicy (t: (key: string, text: string, options: { ns: string }) => T): Route { + return { + Component: Privacy, + display: { + isHidden: true + }, + text: t('nav.privacy', 'Privacy Policy', { ns: 'apps-routing' }), + icon: 'file', + name: 'pages/privacy' + }; +} diff --git a/pioneer/packages/apps/src/Apps.tsx b/pioneer/packages/apps/src/Apps.tsx index f0995e28e5..c331f9f976 100644 --- a/pioneer/packages/apps/src/Apps.tsx +++ b/pioneer/packages/apps/src/Apps.tsx @@ -21,6 +21,9 @@ import SideBar from './SideBar'; import WarmUp from './WarmUp'; import { WindowDimensionsCtx } from './WindowDimensions'; +/* Joystream-specific */ +import TopBar from './JoyTopBar/TopBar'; + interface SidebarState { isCollapsed: boolean; isMenu: boolean; @@ -96,7 +99,10 @@ function Apps ({ className = '' }: Props): React.ReactElement { toggleMenu={_toggleMenu} /> - +
+ + +
@@ -222,4 +228,11 @@ export default React.memo(styled(Apps)` opacity: 1; } } + + .apps--Main { + flex-grow: 1; + min-height: 100vh; + overflow-x: hidden; + overflow-y: auto; + } `); diff --git a/pioneer/packages/apps/src/Content/index.tsx b/pioneer/packages/apps/src/Content/index.tsx index 66ea117e5d..63f0238535 100644 --- a/pioneer/packages/apps/src/Content/index.tsx +++ b/pioneer/packages/apps/src/Content/index.tsx @@ -78,15 +78,11 @@ function Content ({ className }: Props): React.ReactElement { } export default React.memo(styled(Content)` - background: #f5f4f3; - flex-grow: 1; - height: 100%; - min-height: 100vh; - overflow-x: hidden; - overflow-y: auto; + background: rgba(250, 250, 250); padding: 0 1.5rem; position: relative; width: 100%; + height: 100%; @media(max-width: 768px) { padding: 0 0.5rem; diff --git a/pioneer/packages/apps/src/JoyTopBar/TopBar.tsx b/pioneer/packages/apps/src/JoyTopBar/TopBar.tsx new file mode 100644 index 0000000000..b5dd4d8e30 --- /dev/null +++ b/pioneer/packages/apps/src/JoyTopBar/TopBar.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { useMyMembership } from '@polkadot/joy-utils/react/hooks'; +import { InputAddress } from '@polkadot/react-components'; +import { Available } from '@polkadot/react-query'; +import styled from 'styled-components'; +import { useApi } from '@polkadot/react-hooks'; + +type Props = {}; + +const StyledTopBar = styled.div` + padding: 0.75rem; + background-color: #3f3f3f; + border-bottom: 1px solid #d4d4d5; + text-align: right; + margin: 0; + + &.NoMyAddress { + background-color: #ffeb83; + color: #000; + text-align: center; + } + + .ui--InputAddress { + display: inline-block; + } +`; + +function JoyTopBar (_props: Props) { + const { + allAccounts, + myAddress + } = useMyMembership(); + + const { isApiReady } = useApi(); + + if (!isApiReady) { + return null; + } + + const balance = Balance: ; + const labelExtra = myAddress + ? + : 'No key selected'; + + return Object.keys(allAccounts || {}).length ? ( + + + + ) : null; +} + +export default JoyTopBar; diff --git a/pioneer/packages/apps/src/SideBar/ChainInfo.tsx b/pioneer/packages/apps/src/SideBar/ChainInfo.tsx index 0e417ee81e..737bed301b 100644 --- a/pioneer/packages/apps/src/SideBar/ChainInfo.tsx +++ b/pioneer/packages/apps/src/SideBar/ChainInfo.tsx @@ -24,7 +24,7 @@ function ChainInfo ({ className = '', onClick }: Props): React.ReactElement
diff --git a/pioneer/packages/apps/src/SideBar/index.tsx b/pioneer/packages/apps/src/SideBar/index.tsx index 7cc71f1bfe..5496e93255 100644 --- a/pioneer/packages/apps/src/SideBar/index.tsx +++ b/pioneer/packages/apps/src/SideBar/index.tsx @@ -7,7 +7,7 @@ import { Routes } from '@polkadot/apps-routing/types'; import React, { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; import createRoutes from '@polkadot/apps-routing'; -import { Button, ChainImg, Icon, Menu, media } from '@polkadot/react-components'; +import { Button, ChainImg, Menu, media } from '@polkadot/react-components'; import { SIDEBAR_MENU_THRESHOLD } from '../constants'; import NetworkModal from '../modals/Network'; @@ -101,27 +101,6 @@ function SideBar ({ className = '', collapse, handleResize, isCollapsed, isMenuO ) ))}
@@ -159,7 +138,7 @@ export default React.memo(styled(SideBar)` .apps--SideBar { align-items: center; - background: #4f5255; + background: #3f3f3f; box-sizing: border-box; display: flex; flex-flow: column; @@ -221,7 +200,7 @@ export default React.memo(styled(SideBar)` } .apps--SideBar-collapse { - background: #4f5255; + background: #3f3f3f; bottom: 0; left: 0; padding: 0.75rem 0 .75rem 0.65rem; diff --git a/pioneer/packages/apps/src/index.tsx b/pioneer/packages/apps/src/index.tsx index 1654bc4541..df91ca7b15 100644 --- a/pioneer/packages/apps/src/index.tsx +++ b/pioneer/packages/apps/src/index.tsx @@ -20,6 +20,9 @@ import settings from '@polkadot/ui-settings'; import Apps from './Apps'; import WindowDimensions from './WindowDimensions'; +/* Joystream-specific */ +import { MyMembershipProvider, MyAccountProvider } from '@polkadot/joy-utils/react/context'; + const rootId = 'root'; const rootElement = document.getElementById(rootId); const theme = { theme: settings.uiTheme }; @@ -38,19 +41,23 @@ store.each((_, key): void => { ReactDOM.render( - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + , rootElement diff --git a/pioneer/packages/joy-members/.skip-build b/pioneer/packages/joy-members/.skip-build deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pioneer/packages/joy-members/package.json b/pioneer/packages/joy-members/package.json index ed610455d8..1cb161c08c 100644 --- a/pioneer/packages/joy-members/package.json +++ b/pioneer/packages/joy-members/package.json @@ -7,9 +7,9 @@ "author": "Joystream contributors", "maintainers": [], "dependencies": { - "@babel/runtime": "^7.7.1", - "@polkadot/react-components": "0.37.0-beta.63", - "@polkadot/react-query": "0.37.0-beta.63", + "@babel/runtime": "^7.10.5", + "@polkadot/react-components": "0.51.1", + "@polkadot/react-query": "0.51.1", "@polkadot/joy-utils": "^0.1.1" } } diff --git a/pioneer/packages/joy-members/src/Dashboard.tsx b/pioneer/packages/joy-members/src/Dashboard.tsx index 3c2bcc78d1..b1d965b23f 100644 --- a/pioneer/packages/joy-members/src/Dashboard.tsx +++ b/pioneer/packages/joy-members/src/Dashboard.tsx @@ -3,12 +3,12 @@ import BN from 'bn.js'; import { ApiProps } from '@polkadot/react-api/types'; import { I18nProps } from '@polkadot/react-components/types'; -import { withCalls } from '@polkadot/react-api/with'; -import { Bubble } from '@polkadot/react-components/index'; +import { withCalls } from '@polkadot/react-api/hoc'; +import { Label } from 'semantic-ui-react'; import { formatNumber } from '@polkadot/util'; import { bool as Bool } from '@polkadot/types'; -import Section from '@polkadot/joy-utils/Section'; +import { Section } from '@polkadot/joy-utils/react/components'; import translate from './translate'; import { queryMembershipToProp } from './utils'; @@ -27,39 +27,57 @@ class Dashboard extends React.PureComponent { renderGeneral () { const p = this.props; const { newMembershipsAllowed: isAllowed } = p; - let isAllowedColor = ''; + let isAllowedColor: 'grey' | 'green' | 'red' = 'grey'; + if (isAllowed) { isAllowedColor = isAllowed.eq(true) ? 'green' : 'red'; } - return
- - {isAllowed && (isAllowed.eq(true) ? 'Yes' : 'No')} - - - {formatNumber(p.nextMemberId)} - - - {formatNumber(FIRST_MEMBER_ID)} - -
; + + return ( +
+ + + + + +
+ ); } renderValidation () { const p = this.props; - return
- - {formatNumber(p.minHandleLength)} chars - - - {formatNumber(p.maxHandleLength)} chars - - - {formatNumber(p.maxAvatarUriLength)} chars - - - {formatNumber(p.maxAboutTextLength)} chars - -
; + + return ( +
+ + + + + + +
+ ); } render () { diff --git a/pioneer/packages/joy-members/src/Details.tsx b/pioneer/packages/joy-members/src/Details.tsx index 3e694ad437..6c2435e7f2 100644 --- a/pioneer/packages/joy-members/src/Details.tsx +++ b/pioneer/packages/joy-members/src/Details.tsx @@ -5,18 +5,18 @@ import ReactMarkdown from 'react-markdown'; import { IdentityIcon } from '@polkadot/react-components'; import { ApiProps } from '@polkadot/react-api/types'; import { I18nProps } from '@polkadot/react-components/types'; -import { withCalls } from '@polkadot/react-api/with'; +import { withCalls } from '@polkadot/react-api/hoc'; import { Option } from '@polkadot/types'; import BalanceDisplay from '@polkadot/react-components/Balance'; -import AddressMini from '@polkadot/react-components/AddressMiniJoy'; +import AddressMini from '@polkadot/react-components/AddressMini'; import { formatNumber } from '@polkadot/util'; import translate from './translate'; import { MemberId, Membership, EntryMethod, Paid, Screening, Genesis, SubscriptionId } from '@joystream/types/members'; import { queryMembershipToProp } from './utils'; import { Seat } from '@joystream/types/council'; -import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/index'; -import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount'; +import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/functions/misc'; +import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/react/hocs/accounts'; type Props = ApiProps & I18nProps & MyAccountProps & { preview?: boolean; diff --git a/pioneer/packages/joy-members/src/DetailsByHandle.tsx b/pioneer/packages/joy-members/src/DetailsByHandle.tsx index 652af8d9c8..ded39c31eb 100644 --- a/pioneer/packages/joy-members/src/DetailsByHandle.tsx +++ b/pioneer/packages/joy-members/src/DetailsByHandle.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { I18nProps } from '@polkadot/react-components/types'; -import { withCalls } from '@polkadot/react-api/with'; +import { withCalls } from '@polkadot/react-api/hoc'; import { stringToU8a, u8aToHex } from '@polkadot/util'; import translate from './translate'; @@ -16,6 +16,7 @@ type DetailsByHandleProps = { function DetailsByHandleInner (p: DetailsByHandleProps) { const { memberIdByHandle: memberId } = p; + return memberId !== undefined // here we can't make distinction value existing and loading ?
@@ -39,6 +40,7 @@ class Component extends React.PureComponent { render () { const { match: { params: { handle } } } = this.props; const handleHex = u8aToHex(stringToU8a(handle)); + return ( ); diff --git a/pioneer/packages/joy-members/src/EditForm.tsx b/pioneer/packages/joy-members/src/EditForm.tsx index 38cd5bbd30..d084987b2d 100644 --- a/pioneer/packages/joy-members/src/EditForm.tsx +++ b/pioneer/packages/joy-members/src/EditForm.tsx @@ -1,19 +1,18 @@ import BN from 'bn.js'; -import React from 'react'; +import React, { useContext } from 'react'; import { Link } from 'react-router-dom'; import { Form, Field, withFormik, FormikProps } from 'formik'; import * as Yup from 'yup'; import { Vec } from '@polkadot/types'; -import Section from '@polkadot/joy-utils/Section'; -import TxButton from '@polkadot/joy-utils/TxButton'; -import * as JoyForms from '@polkadot/joy-utils/forms'; +import { Section, TxButton } from '@polkadot/joy-utils/react/components'; +import * as JoyForms from '@polkadot/joy-utils/react/components/forms'; import { SubmittableResult } from '@polkadot/api'; import { MemberId, Membership, PaidTermId, PaidMembershipTerms } from '@joystream/types/members'; import { OptionText } from '@joystream/types/common'; -import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount'; +import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/react/hocs/accounts'; import { queryMembershipToProp } from './utils'; -import { withCalls } from '@polkadot/react-api/index'; +import { withCalls, ApiContext } from '@polkadot/react-api/index'; import { Button, Message } from 'semantic-ui-react'; import { formatBalance } from '@polkadot/util'; import { TxFailedCallback, TxCallback } from '@polkadot/react-components/Status/types'; @@ -79,6 +78,8 @@ const InnerForm = (props: FormProps) => { memberId } = props; + const { api } = useContext(ApiContext) + const onSubmit = (sendTx: () => void) => { if (isValid) sendTx(); }; @@ -102,7 +103,9 @@ const InnerForm = (props: FormProps) => { // TODO extract to forms.tsx const fieldToTextOption = (field: FieldName): OptionText => { - return isFieldChanged(field) ? OptionText.some(values[field]) : OptionText.none(); + return isFieldChanged(field) + ? api.createType('Option', values[field]) + : api.createType('Option', null) }; const buildTxParams = () => { @@ -165,24 +168,26 @@ const InnerForm = (props: FormProps) => { )} - -
@@ -228,7 +233,9 @@ function WithMembershipDataInner (p: WithMembershipDataProps) { p.maxAvatarUriLength && p.maxAboutTextLength ) { - const membership = p.membership && !p.membership.handle.isEmpty ? p.membership : undefined; + const membership = (p.memberId && p.membership && !p.membership.handle.isEmpty) + ? p.membership + : undefined; if (!membership && p.paidTerms.isEmpty) { console.error('Could not find active paid membership terms'); @@ -280,9 +287,7 @@ function WithMembershipDataWrapperInner (p: WithMembershipDataWrapperProps) { if (p.memberIdsByRootAccountId && p.memberIdsByControllerAccountId && p.paidTermsIds) { if (p.paidTermsIds.length) { - // let member_ids = p.memberIdsByRootAccountId.slice(); // u8a.subarray is not a function!! - p.memberIdsByRootAccountId.concat(p.memberIdsByControllerAccountId); - const memberId = p.memberIdsByRootAccountId.length ? p.memberIdsByRootAccountId[0] : undefined; + const [ memberId ] = p.memberIdsByRootAccountId.toArray().concat(p.memberIdsByControllerAccountId.toArray()); return ; } else { diff --git a/pioneer/packages/joy-members/src/List.tsx b/pioneer/packages/joy-members/src/List.tsx index f5e8db26b8..950e0c00bb 100644 --- a/pioneer/packages/joy-members/src/List.tsx +++ b/pioneer/packages/joy-members/src/List.tsx @@ -4,13 +4,14 @@ import React from 'react'; import { ApiProps } from '@polkadot/react-api/types'; import { I18nProps } from '@polkadot/react-components/types'; -import Section from '@polkadot/joy-utils/Section'; +import { Section } from '@polkadot/joy-utils/react/components'; import translate from './translate'; import Details from './Details'; import { MemberId } from '@joystream/types/members'; import { RouteComponentProps, Redirect } from 'react-router-dom'; import { Pagination, Icon, PaginationProps } from 'semantic-ui-react'; import styled from 'styled-components'; +import { withApi } from '@polkadot/react-api'; const StyledPagination = styled(Pagination)` border-bottom: 1px solid #ddd !important; @@ -55,7 +56,8 @@ class Component extends React.PureComponent { const { firstMemberId, membersCreated, - match: { params: { page } } + match: { params: { page } }, + api } = this.props; const membersCount = membersCreated.toNumber(); @@ -71,7 +73,7 @@ class Component extends React.PureComponent { const firstId = firstMemberId.toNumber() + (currentPage - 1) * MEMBERS_PER_PAGE; const lastId = Math.min(firstId + MEMBERS_PER_PAGE, membersCount) - 1; for (let i = firstId; i <= lastId; i++) { - ids.push(new MemberId(i)); + ids.push(api.createType('MemberId', i)); } } @@ -95,4 +97,4 @@ class Component extends React.PureComponent { } } -export default translate(Component); +export default translate(withApi(Component)); diff --git a/pioneer/packages/joy-members/src/MemberPreview.tsx b/pioneer/packages/joy-members/src/MemberPreview.tsx index abf91d7ed5..7574e9a657 100644 --- a/pioneer/packages/joy-members/src/MemberPreview.tsx +++ b/pioneer/packages/joy-members/src/MemberPreview.tsx @@ -3,7 +3,7 @@ import { Link } from 'react-router-dom'; import { ApiProps } from '@polkadot/react-api/types'; import { I18nProps } from '@polkadot/react-components/types'; -import { withCalls, withMulti } from '@polkadot/react-api/with'; +import { withCalls, withMulti } from '@polkadot/react-api/hoc'; import { Vec } from '@polkadot/types'; import { AccountId } from '@polkadot/types/interfaces'; import IdentityIcon from '@polkadot/react-components/IdentityIcon'; @@ -12,9 +12,8 @@ import translate from './translate'; import { MemberId, Membership } from '@joystream/types/members'; import { queryMembershipToProp } from './utils'; import { Seat } from '@joystream/types/council'; -import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/index'; -import { FlexCenter } from '@polkadot/joy-utils/FlexCenter'; -import { MutedSpan } from '@polkadot/joy-utils/MutedText'; +import { nonEmptyStr, queryToProp } from '@polkadot/joy-utils/functions/misc'; +import { FlexCenter, MutedSpan } from '@polkadot/joy-utils/react/components'; const AvatarSizePx = 36; const InlineAvatarSizePx = 24; diff --git a/pioneer/packages/joy-members/src/index.css b/pioneer/packages/joy-members/src/index.css deleted file mode 100644 index 5215f350ee..0000000000 --- a/pioneer/packages/joy-members/src/index.css +++ /dev/null @@ -1,58 +0,0 @@ -.ProfilePreviews, -.FullProfile { - .item { - .image { - padding: 0 !important; - } - .description { - font-size: 1rem; - } - } -} -.ProfilePreviews { - &.ui.list>.item:first-child { - padding-top: .75rem; - } - &.ui.list>.item:last-child { - padding-bottom: .75rem; - } - .MyProfile { - background-color: #FFF8E1; - } -} -.ProfileDetails { - padding-left: 1rem !important; - .handle { - margin-right: 1rem; - .button { - padding: .5rem .75rem; - } - } -} -.ProfileDetailsTable { - font-size: 1rem !important; - tr td:first-child { - width: 1%; - white-space: nowrap; - } -} - -.JoyMemberPreview { - margin-right: .5rem; - .PrefixLabel { - margin-right: .5rem; - } - .Avatar { - margin-right: .5rem; - border-radius: 100%; - } - .Content { - .Username { - font-weight: bold; - } - .Details { - font-weight: 100; - opacity: .75; - } - } -} \ No newline at end of file diff --git a/pioneer/packages/joy-members/src/index.tsx b/pioneer/packages/joy-members/src/index.tsx index 7b6339c10b..c6b6b79655 100644 --- a/pioneer/packages/joy-members/src/index.tsx +++ b/pioneer/packages/joy-members/src/index.tsx @@ -5,10 +5,9 @@ import { Route, Switch } from 'react-router'; import { AppProps, I18nProps } from '@polkadot/react-components/types'; import { ApiProps } from '@polkadot/react-api/types'; -import { withCalls, withMulti } from '@polkadot/react-api/with'; -import Tabs, { TabItem } from '@polkadot/react-components/Tabs'; - -import './index.css'; +import { withCalls, withMulti } from '@polkadot/react-api/hoc'; +import Tabs from '@polkadot/react-components/Tabs'; +import { TabItem } from '@polkadot/react-components/Tabs/types'; import { queryMembershipToProp } from './utils'; import translate from './translate'; @@ -16,10 +15,15 @@ import Dashboard from './Dashboard'; import List from './List'; import DetailsByHandle from './DetailsByHandle'; import EditForm from './EditForm'; -import { withMyAccount, MyAccountProps } from '@polkadot/joy-utils/MyAccount'; +import { withMyAccount, MyAccountProps } from '@polkadot/joy-utils/react/hocs/accounts'; import { FIRST_MEMBER_ID } from './constants'; import { RouteComponentProps } from 'react-router-dom'; +import styled from 'styled-components'; +import style from './style'; + +const MembersMain = styled.main`${style}`; + // define out internal types type Props = AppProps & ApiProps & I18nProps & MyAccountProps & { nextMemberId?: BN; @@ -33,7 +37,7 @@ class App extends React.PureComponent { { name: 'list', text: t('All members') + ` (${memberCount})`, - forcedExact: false + forceMatchParams: true }, { name: 'edit', @@ -58,7 +62,7 @@ class App extends React.PureComponent { const tabs = this.buildTabs(); return ( -
+
@@ -69,7 +73,7 @@ class App extends React.PureComponent { this.renderList(props) } /> -
+ ); } } diff --git a/pioneer/packages/joy-members/src/style.ts b/pioneer/packages/joy-members/src/style.ts new file mode 100644 index 0000000000..bf36ffbc48 --- /dev/null +++ b/pioneer/packages/joy-members/src/style.ts @@ -0,0 +1,62 @@ +import { css } from 'styled-components'; + +export default css` + .ProfilePreviews, + .FullProfile { + .item { + .image { + padding: 0 !important; + } + .description { + font-size: 1rem; + } + } + } + .ProfilePreviews { + &.ui.list>.item:first-child { + padding-top: .75rem; + } + &.ui.list>.item:last-child { + padding-bottom: .75rem; + } + .MyProfile { + background-color: #FFF8E1; + } + } + .ProfileDetails { + padding-left: 1rem !important; + .handle { + margin-right: 1rem; + .button { + padding: .5rem .75rem; + } + } + } + .ProfileDetailsTable { + font-size: 1rem !important; + tr td:first-child { + width: 1%; + white-space: nowrap; + } + } + + .JoyMemberPreview { + margin-right: .5rem; + .PrefixLabel { + margin-right: .5rem; + } + .Avatar { + margin-right: .5rem; + border-radius: 100%; + } + .Content { + .Username { + font-weight: bold; + } + .Details { + font-weight: 100; + opacity: .75; + } + } + } +`; diff --git a/pioneer/packages/joy-members/src/utils.ts b/pioneer/packages/joy-members/src/utils.ts index 12149af347..95d209d09d 100644 --- a/pioneer/packages/joy-members/src/utils.ts +++ b/pioneer/packages/joy-members/src/utils.ts @@ -1,5 +1,6 @@ -import { queryToProp } from '@polkadot/joy-utils/index'; -import { Options as QueryOptions } from '@polkadot/react-api/with/types'; +// TODO: Move to joy-utils? +import { queryToProp } from '@polkadot/joy-utils/functions/misc'; +import { Options as QueryOptions } from '@polkadot/react-api/hoc/types'; export const queryMembershipToProp = (storageItem: string, paramNameOrOpts?: string | QueryOptions) => { return queryToProp(`query.members.${storageItem}`, paramNameOrOpts); diff --git a/pioneer/packages/joy-pages/.skip-build b/pioneer/packages/joy-pages/.skip-build deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pioneer/packages/joy-pages/package.json b/pioneer/packages/joy-pages/package.json index eba65b99b1..bbd6934caf 100644 --- a/pioneer/packages/joy-pages/package.json +++ b/pioneer/packages/joy-pages/package.json @@ -7,9 +7,9 @@ "author": "Joystream contributors", "maintainers": [], "dependencies": { - "@babel/runtime": "^7.7.1", - "@polkadot/react-components": "0.37.0-beta.63", - "@polkadot/react-query": "0.37.0-beta.63", + "@babel/runtime": "^7.10.5", + "@polkadot/react-components": "0.51.1", + "@polkadot/react-query": "0.51.1", "@polkadot/joy-utils": "^0.1.1" } } diff --git a/pioneer/packages/joy-utils-old/src/functions/misc.ts b/pioneer/packages/joy-utils-old/src/functions/misc.ts deleted file mode 100644 index 7e5d815e65..0000000000 --- a/pioneer/packages/joy-utils-old/src/functions/misc.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Bytes } from '@polkadot/types/primitive'; - -export function includeKeys (obj: T, ...allowedKeys: string[]) { - return Object.keys(obj).filter(objKey => { - return allowedKeys.reduce( - (hasAllowed: boolean, allowedKey: string) => hasAllowed || objKey.includes(allowedKey), - false - ); - }); -} - -export function bytesToString (bytes: Bytes) { - return Buffer.from(bytes.toString().substr(2), 'hex').toString(); -} diff --git a/pioneer/packages/joy-utils-old/src/react/components/index.tsx b/pioneer/packages/joy-utils-old/src/react/components/index.tsx deleted file mode 100644 index 65cbe1f3b0..0000000000 --- a/pioneer/packages/joy-utils-old/src/react/components/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default as PromiseComponent } from './PromiseComponent'; diff --git a/pioneer/packages/joy-utils-old/src/react/context/index.tsx b/pioneer/packages/joy-utils-old/src/react/context/index.tsx deleted file mode 100644 index 94bb6cf018..0000000000 --- a/pioneer/packages/joy-utils-old/src/react/context/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { TransportContext, TransportProvider } from './transport'; diff --git a/pioneer/packages/joy-utils-old/README.md b/pioneer/packages/joy-utils/README.md similarity index 100% rename from pioneer/packages/joy-utils-old/README.md rename to pioneer/packages/joy-utils/README.md diff --git a/pioneer/packages/joy-utils-old/package.json b/pioneer/packages/joy-utils/package.json similarity index 80% rename from pioneer/packages/joy-utils-old/package.json rename to pioneer/packages/joy-utils/package.json index dfc2f2e963..b6d4546cee 100644 --- a/pioneer/packages/joy-utils-old/package.json +++ b/pioneer/packages/joy-utils/package.json @@ -7,9 +7,9 @@ "author": "Joystream contributors", "maintainers": [], "dependencies": { - "@babel/runtime": "^7.7.1", - "@polkadot/react-components": "0.37.0-beta.63", - "@polkadot/react-query": "0.37.0-beta.63", + "@babel/runtime": "^7.10.5", + "@polkadot/react-components": "0.51.1", + "@polkadot/react-query": "0.51.1", "@types/query-string": "^6.2.0", "@types/uuid": "^3.4.4", "@types/yup": "^0.26.10", diff --git a/pioneer/packages/joy-utils-old/src/functions/date.ts b/pioneer/packages/joy-utils/src/functions/date.ts similarity index 100% rename from pioneer/packages/joy-utils-old/src/functions/date.ts rename to pioneer/packages/joy-utils/src/functions/date.ts diff --git a/pioneer/packages/joy-utils-old/src/functions/format.ts b/pioneer/packages/joy-utils/src/functions/format.ts similarity index 100% rename from pioneer/packages/joy-utils-old/src/functions/format.ts rename to pioneer/packages/joy-utils/src/functions/format.ts diff --git a/pioneer/packages/joy-utils/src/functions/misc.ts b/pioneer/packages/joy-utils/src/functions/misc.ts new file mode 100644 index 0000000000..ab4663e108 --- /dev/null +++ b/pioneer/packages/joy-utils/src/functions/misc.ts @@ -0,0 +1,157 @@ +import { Bytes } from '@polkadot/types/primitive'; +import BN from 'bn.js'; +import keyring from '@polkadot/ui-keyring'; +import { ElectionStake, Backer } from '@joystream/types/council'; +import { Options as QueryOptions } from '@polkadot/react-api/hoc/types'; +import queryString from 'query-string'; +import { SubmittableResult } from '@polkadot/api'; +import { Codec } from '@polkadot/types/types'; + +export const ZERO = new BN(0); + +export function bnToStr (bn?: BN, dflt = ''): string { + return bn ? bn.toString() : dflt; +} + +export const notDefined = (x: any): boolean => + x === null || typeof x === 'undefined'; + +export const isDefined = (x: any): boolean => + !notDefined(x); + +export const isDef = isDefined; + +export const notDef = notDefined; + +export const isObj = (x: any): boolean => + x !== null && typeof x === 'object'; + +export const isStr = (x: any): boolean => + typeof x === 'string'; + +export const isNum = (x: any): boolean => + typeof x === 'number'; + +export const isEmptyStr = (x: any): boolean => + notDefined(x) || (isStr(x) && x.trim().length === 0); + +export const nonEmptyStr = (x?: any) => + isStr(x) && x.trim().length > 0; + +export const parseNumStr = (num: string): number | undefined => { + try { + return parseInt(num, undefined); + } catch (err) { + return undefined; + } +}; + +export const nonEmptyArr = (x: any): boolean => + Array.isArray(x) && x.length > 0; + +export const isEmptyArr = (x: any): boolean => + !nonEmptyArr(x); + +export function findNameByAddress (address: string): string | undefined { + let keyring_address; + try { + keyring_address = keyring.getAccount(address); + } catch (error) { + try { + keyring_address = keyring.getAddress(address); + } catch (error) { + // do nothing + } + } + return keyring_address ? keyring_address.meta.name : undefined; +} + +export function isKnownAddress (address: string): boolean { + return isDefined(findNameByAddress(address)); +} + +export function calcTotalStake (stakes: ElectionStake | ElectionStake[] | undefined): BN { + if (typeof stakes === 'undefined') { + return ZERO; + } + const total = (stake: ElectionStake) => stake.new.add(stake.transferred); + try { + if (Array.isArray(stakes)) { + return stakes.reduce((accum, stake) => { + return accum.add(total(stake)); + }, ZERO); + } else { + return total(stakes); + } + } catch (err) { + console.log('Failed to calculate a total stake', stakes, err); + return ZERO; + } +} + +export function calcBackersStake (backers: Backer[]): BN { + return backers.map(b => b.stake).reduce((accum, stake) => { + return accum.add(stake); + }, ZERO); +} + +/** Example of apiQuery: 'query.councilElection.round' */ +export function queryToProp ( + apiQuery: string, + paramNameOrOpts?: string | QueryOptions +): [string, QueryOptions] { + let paramName: string | undefined; + let propName: string | undefined; + + if (typeof paramNameOrOpts === 'string') { + paramName = paramNameOrOpts; + } else if (paramNameOrOpts) { + paramName = paramNameOrOpts.paramName; + propName = paramNameOrOpts.propName; + } + + // If prop name is still undefined, derive it from the name of storage item: + if (!propName) { + propName = apiQuery.split('.').slice(-1)[0]; + } + + return [apiQuery, { paramName, propName }]; +} + +export function getUrlParam (location: Location, paramName: string, deflt: string | null = null): string | null { + const params = queryString.parse(location.search); + return params[paramName] ? params[paramName] as string : deflt; +} + +export function filterSubstrateEventsAndExtractData (txResult: SubmittableResult, eventName: string): Codec[][] { + const res: Codec[][] = []; + txResult.events.forEach((event) => { + const { event: { method, data } } = event; + if (method === eventName) { + res.push(data.toArray()); + } + }); + return res; +} + +export function findFirstParamOfSubstrateEvent (txResult: SubmittableResult, eventName: string): T | undefined { + const data = filterSubstrateEventsAndExtractData(txResult, eventName); + if (data && data.length) { + return data[0][0] as T; + } + return undefined; +} + + +export function includeKeys (obj: T, ...allowedKeys: string[]) { + return Object.keys(obj).filter(objKey => { + return allowedKeys.reduce( + (hasAllowed: boolean, allowedKey: string) => hasAllowed || objKey.includes(allowedKey), + false + ); + }); +} + +export function bytesToString (bytes: Bytes) { + return Buffer.from(bytes.toString().substr(2), 'hex').toString(); +} diff --git a/pioneer/packages/joy-utils-old/src/FlexCenter.tsx b/pioneer/packages/joy-utils/src/react/components/FlexCenter.tsx similarity index 100% rename from pioneer/packages/joy-utils-old/src/FlexCenter.tsx rename to pioneer/packages/joy-utils/src/react/components/FlexCenter.tsx diff --git a/pioneer/packages/joy-utils-old/src/MutedText.tsx b/pioneer/packages/joy-utils/src/react/components/MutedText.tsx similarity index 100% rename from pioneer/packages/joy-utils-old/src/MutedText.tsx rename to pioneer/packages/joy-utils/src/react/components/MutedText.tsx diff --git a/pioneer/packages/joy-utils-old/src/Section.tsx b/pioneer/packages/joy-utils/src/react/components/Section.tsx similarity index 100% rename from pioneer/packages/joy-utils-old/src/Section.tsx rename to pioneer/packages/joy-utils/src/react/components/Section.tsx diff --git a/pioneer/packages/joy-utils-old/src/TxButton.tsx b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx similarity index 60% rename from pioneer/packages/joy-utils-old/src/TxButton.tsx rename to pioneer/packages/joy-utils/src/react/components/TxButton.tsx index f1e6d6b0db..253a26feb6 100644 --- a/pioneer/packages/joy-utils-old/src/TxButton.tsx +++ b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx @@ -5,11 +5,8 @@ import { Button } from '@polkadot/react-components/index'; import { QueueConsumer } from '@polkadot/react-components/Status/Context'; import { withApi } from '@polkadot/react-api/index'; import { assert } from '@polkadot/util'; -import { withMyAccount, MyAccountProps } from '@polkadot/joy-utils/MyAccount'; -import { useTransportContext } from '@polkadot/joy-media/TransportContext'; -import { MockTransport } from '@polkadot/joy-media/transport.mock'; -import { Button$Sizes } from '@polkadot/react-components/Button/types'; -import { SemanticShorthandItem, IconProps } from 'semantic-ui-react'; +import { withMyAccount, MyAccountProps } from '../hocs/accounts'; +import { IconName } from '@fortawesome/fontawesome-svg-core'; type InjectedProps = { queueExtrinsic: QueueTxExtrinsicAdd; @@ -20,9 +17,7 @@ export type OnTxButtonClick = (sendTx: () => void) => void; type BasicButtonProps = { accountId?: string; type?: 'submit' | 'button'; - size?: Button$Sizes; isBasic?: boolean; - isPrimary?: boolean; isDisabled?: boolean; label?: React.ReactNode; params: Array; @@ -32,7 +27,7 @@ type BasicButtonProps = { style?: Record; children?: React.ReactNode; compact?: boolean; - icon?: boolean | SemanticShorthandItem; + icon?: IconName; onClick?: OnTxButtonClick; txFailedCb?: TxFailedCallback; @@ -45,15 +40,14 @@ type PropsWithApi = BareProps & ApiProps & MyAccountProps & PartialQueueTxExtrin class TxButtonInner extends React.PureComponent { render () { - const { myAddress, accountId, isPrimary = true, isDisabled, icon = '', onClick } = this.props; + const { myAddress, accountId, isDisabled, icon = "paper-plane", onClick } = this.props; const origin = accountId || myAddress; return (
@@ -196,8 +197,9 @@ const InnerForm = (props: FormProps) => { const EditForm = withFormik({ // Transform outer props into form values - mapPropsToValues: props => { + mapPropsToValues: (props) => { const { profile: p } = props; + return { handle: p ? p.handle.toString() : '', avatar: p ? p.avatar_uri.toString() : '', @@ -207,7 +209,7 @@ const EditForm = withFormik({ validationSchema: buildSchema, - handleSubmit: values => { + handleSubmit: (values) => { // do submitting things } })(InnerForm); @@ -225,6 +227,7 @@ type WithMembershipDataProps = { function WithMembershipDataInner (p: WithMembershipDataProps) { const triedToFindProfile = !p.memberId || p.membership; + if ( triedToFindProfile && p.paidTerms && @@ -274,10 +277,10 @@ type WithMembershipDataWrapperProps = MyAccountProps & { function WithMembershipDataWrapperInner (p: WithMembershipDataWrapperProps) { if (p.allAccounts && !Object.keys(p.allAccounts).length) { return ( - + Please create a key to get started.
- + Create key
@@ -287,7 +290,7 @@ function WithMembershipDataWrapperInner (p: WithMembershipDataWrapperProps) { if (p.memberIdsByRootAccountId && p.memberIdsByControllerAccountId && p.paidTermsIds) { if (p.paidTermsIds.length) { - const [ memberId ] = p.memberIdsByRootAccountId.toArray().concat(p.memberIdsByControllerAccountId.toArray()); + const [memberId] = p.memberIdsByRootAccountId.toArray().concat(p.memberIdsByControllerAccountId.toArray()); return ; } else { diff --git a/pioneer/packages/joy-members/src/List.tsx b/pioneer/packages/joy-members/src/List.tsx index 950e0c00bb..cd259e271c 100644 --- a/pioneer/packages/joy-members/src/List.tsx +++ b/pioneer/packages/joy-members/src/List.tsx @@ -32,6 +32,7 @@ class Component extends React.PureComponent { onPageChange = (e: React.MouseEvent, data: PaginationProps) => { const { history } = this.props; + history.push(`/members/list/${data.activePage}`); } @@ -69,9 +70,11 @@ class Component extends React.PureComponent { } const ids: MemberId[] = []; + if (membersCount > 0) { const firstId = firstMemberId.toNumber() + (currentPage - 1) * MEMBERS_PER_PAGE; const lastId = Math.min(firstId + MEMBERS_PER_PAGE, membersCount) - 1; + for (let i = firstId; i <= lastId; i++) { ids.push(api.createType('MemberId', i)); } diff --git a/pioneer/packages/joy-members/src/MemberPreview.tsx b/pioneer/packages/joy-members/src/MemberPreview.tsx index 7574e9a657..9c8d6b87a9 100644 --- a/pioneer/packages/joy-members/src/MemberPreview.tsx +++ b/pioneer/packages/joy-members/src/MemberPreview.tsx @@ -32,6 +32,7 @@ type MemberPreviewProps = ApiProps & I18nProps & { class InnerMemberPreview extends React.PureComponent { render () { const { membership } = this.props; + return membership && !membership.handle.isEmpty ? this.renderProfile(membership) : null; @@ -42,7 +43,7 @@ class InnerMemberPreview extends React.PureComponent { const { handle, avatar_uri } = membership; const hasAvatar = avatar_uri && nonEmptyStr(avatar_uri.toString()); - const isCouncilor: boolean = accountId !== undefined && activeCouncil.find(x => accountId.eq(x.member)) !== undefined; + const isCouncilor: boolean = accountId !== undefined && activeCouncil.find((x) => accountId.eq(x.member)) !== undefined; const avatarSize = inline ? InlineAvatarSizePx : AvatarSizePx; @@ -52,9 +53,9 @@ class InnerMemberPreview extends React.PureComponent { {prefixLabel} } {hasAvatar ? ( - + ) : ( - + ) }
diff --git a/pioneer/packages/joy-members/src/index.tsx b/pioneer/packages/joy-members/src/index.tsx index c6b6b79655..6edd9a828c 100644 --- a/pioneer/packages/joy-members/src/index.tsx +++ b/pioneer/packages/joy-members/src/index.tsx @@ -52,6 +52,7 @@ class App extends React.PureComponent { private renderList (routeProps: RouteComponentProps) { const { nextMemberId, ...otherProps } = this.props; + return nextMemberId ? : Loading...; @@ -69,9 +70,9 @@ class App extends React.PureComponent { - this.renderList(props) } /> + this.renderList(props) } /> - this.renderList(props) } /> + this.renderList(props) } /> ); diff --git a/pioneer/packages/joy-pages/src/index.tsx b/pioneer/packages/joy-pages/src/index.tsx index f55100e9e8..aa18def5ba 100644 --- a/pioneer/packages/joy-pages/src/index.tsx +++ b/pioneer/packages/joy-pages/src/index.tsx @@ -4,9 +4,11 @@ import Page from './Page'; import ToS_md from './md/ToS.md'; import Privacy_md from './md/Privacy.md'; + export function ToS () { return ; } + export function Privacy () { return ; } diff --git a/pioneer/packages/joy-utils/src/functions/misc.ts b/pioneer/packages/joy-utils/src/functions/misc.ts index ab4663e108..7263bc8cd1 100644 --- a/pioneer/packages/joy-utils/src/functions/misc.ts +++ b/pioneer/packages/joy-utils/src/functions/misc.ts @@ -54,6 +54,7 @@ export const isEmptyArr = (x: any): boolean => export function findNameByAddress (address: string): string | undefined { let keyring_address; + try { keyring_address = keyring.getAccount(address); } catch (error) { @@ -63,6 +64,7 @@ export function findNameByAddress (address: string): string | undefined { // do nothing } } + return keyring_address ? keyring_address.meta.name : undefined; } @@ -74,7 +76,9 @@ export function calcTotalStake (stakes: ElectionStake | ElectionStake[] | undefi if (typeof stakes === 'undefined') { return ZERO; } + const total = (stake: ElectionStake) => stake.new.add(stake.transferred); + try { if (Array.isArray(stakes)) { return stakes.reduce((accum, stake) => { @@ -85,12 +89,13 @@ export function calcTotalStake (stakes: ElectionStake | ElectionStake[] | undefi } } catch (err) { console.log('Failed to calculate a total stake', stakes, err); + return ZERO; } } export function calcBackersStake (backers: Backer[]): BN { - return backers.map(b => b.stake).reduce((accum, stake) => { + return backers.map((b) => b.stake).reduce((accum, stake) => { return accum.add(stake); }, ZERO); } @@ -120,31 +125,36 @@ export function queryToProp ( export function getUrlParam (location: Location, paramName: string, deflt: string | null = null): string | null { const params = queryString.parse(location.search); + return params[paramName] ? params[paramName] as string : deflt; } export function filterSubstrateEventsAndExtractData (txResult: SubmittableResult, eventName: string): Codec[][] { const res: Codec[][] = []; + txResult.events.forEach((event) => { const { event: { method, data } } = event; + if (method === eventName) { res.push(data.toArray()); } }); + return res; } export function findFirstParamOfSubstrateEvent (txResult: SubmittableResult, eventName: string): T | undefined { const data = filterSubstrateEventsAndExtractData(txResult, eventName); + if (data && data.length) { return data[0][0] as T; } + return undefined; } - export function includeKeys (obj: T, ...allowedKeys: string[]) { - return Object.keys(obj).filter(objKey => { + return Object.keys(obj).filter((objKey) => { return allowedKeys.reduce( (hasAllowed: boolean, allowedKey: string) => hasAllowed || objKey.includes(allowedKey), false diff --git a/pioneer/packages/joy-utils/src/react/components/MutedText.tsx b/pioneer/packages/joy-utils/src/react/components/MutedText.tsx index a981133680..f9eb1309b1 100644 --- a/pioneer/packages/joy-utils/src/react/components/MutedText.tsx +++ b/pioneer/packages/joy-utils/src/react/components/MutedText.tsx @@ -8,15 +8,18 @@ type Props = React.PropsWithChildren<{ function getClassNames (props: Props): string { const { smaller = false, className } = props; + return `grey text ${smaller ? 'smaller' : ''} ${className}`; } export const MutedSpan = (props: Props) => { const { style, children } = props; + return {children}; }; export const MutedDiv = (props: Props) => { const { style, children } = props; + return
{children}
; }; diff --git a/pioneer/packages/joy-utils/src/react/components/Section.tsx b/pioneer/packages/joy-utils/src/react/components/Section.tsx index 09d85b29bd..f9b0d61546 100644 --- a/pioneer/packages/joy-utils/src/react/components/Section.tsx +++ b/pioneer/packages/joy-utils/src/react/components/Section.tsx @@ -46,6 +46,7 @@ type Props = BareProps & { export default class Section extends React.PureComponent { render () { let { className, children, pagination } = this.props; + className = (className || '') + ' JoySection'; return ( @@ -62,10 +63,12 @@ export default class Section extends React.PureComponent { private renderTitle = () => { const { title, level = 2, pagination } = this.props; + if (!title) return null; const className = 'JoySection-title'; const style = pagination ? { margin: '0' } : {}; + return React.createElement( `h${level}`, { className, style }, diff --git a/pioneer/packages/joy-utils/src/react/components/TxButton.tsx b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx index 253a26feb6..216e22ee7d 100644 --- a/pioneer/packages/joy-utils/src/react/components/TxButton.tsx +++ b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx @@ -40,7 +40,7 @@ type PropsWithApi = BareProps & ApiProps & MyAccountProps & PartialQueueTxExtrin class TxButtonInner extends React.PureComponent { render () { - const { myAddress, accountId, isDisabled, icon = "paper-plane", onClick } = this.props; + const { myAddress, accountId, isDisabled, icon = 'paper-plane', onClick } = this.props; const origin = accountId || myAddress; return ( diff --git a/pioneer/packages/joy-utils/src/react/components/forms.tsx b/pioneer/packages/joy-utils/src/react/components/forms.tsx index 4fe8e7d391..4badc9706c 100644 --- a/pioneer/packages/joy-utils/src/react/components/forms.tsx +++ b/pioneer/packages/joy-utils/src/react/components/forms.tsx @@ -37,9 +37,9 @@ export function LabelledField () { const renderLabel = () => nonEmptyStr(label) ? <> - {required && * } - {label} - + {required && * } + {label} + : null; return (label || invisibleLabel) @@ -56,6 +56,7 @@ export function LabelledField () { {fieldWithError}
; }; + return LabelledFieldInner; } diff --git a/pioneer/packages/joy-utils/src/react/context/account.tsx b/pioneer/packages/joy-utils/src/react/context/account.tsx index 095cdf3624..e7b329a024 100644 --- a/pioneer/packages/joy-utils/src/react/context/account.tsx +++ b/pioneer/packages/joy-utils/src/react/context/account.tsx @@ -6,7 +6,9 @@ export const MY_ADDRESS_STORAGE_KEY = 'joy.myAddress'; function readMyAddress (): string | undefined { const myAddress: string | undefined = store.get(MY_ADDRESS_STORAGE_KEY); + console.log('Read my address from the local storage:', myAddress); + return myAddress; } @@ -24,6 +26,7 @@ function reducer (state: MyAccountState, action: MyAccountAction): MyAccountStat function forget () { console.log('Forget my address'); store.remove(MY_ADDRESS_STORAGE_KEY); + return { ...state, address: undefined }; } @@ -33,29 +36,35 @@ function reducer (state: MyAccountState, action: MyAccountAction): MyAccountStat case 'reload': { address = readMyAddress(); console.log('Reload my address:', address); + return { ...state, address, inited: true }; } case 'set': { address = action.address; + if (address !== state.address) { if (address) { console.log('Set my new address:', address); store.set(MY_ADDRESS_STORAGE_KEY, address); + return { ...state, address, inited: true }; } else { return forget(); } } + return state; } case 'forget': { address = action.address; const isMyAddress = address && address === readMyAddress(); + if (!address || isMyAddress) { return forget(); } + return state; } @@ -94,15 +103,17 @@ export function MyAccountProvider (props: React.PropsWithChildren<{}>) { const handleAccountChangeEvent = (e: Event) => { const { detail: address } = e as CustomEvent; + dispatch({ type: 'set', address }); - } + }; useEffect(() => { window.addEventListener(ACCOUNT_CHANGED_EVENT_NAME, handleAccountChangeEvent); + return () => { window.removeEventListener(ACCOUNT_CHANGED_EVENT_NAME, handleAccountChangeEvent); - } - }) + }; + }); useEffect(() => { if (!state.inited) { diff --git a/pioneer/packages/joy-utils/src/react/hocs/accounts.tsx b/pioneer/packages/joy-utils/src/react/hocs/accounts.tsx index 2e3acfc736..96a4363e40 100644 --- a/pioneer/packages/joy-utils/src/react/hocs/accounts.tsx +++ b/pioneer/packages/joy-utils/src/react/hocs/accounts.tsx @@ -45,9 +45,12 @@ function withMyAddress

(Component: React.ComponentType const myAccountId = (address && api.isReady) ? api.createType('AccountId', address) : undefined; + return ; }; + ResultComponent.displayName = `withMyAddress(${componentName(Component)})`; + return ResultComponent; } @@ -63,8 +66,10 @@ function withMyMembership

(Component: React.ComponentT const myMemberIdChecked = memberIdsByRootAccountId && memberIdsByControllerAccountId; let myMemberId: MemberId | undefined; + if (memberIdsByRootAccountId && memberIdsByControllerAccountId) { - let [ memberIdByAccount ] = memberIdsByRootAccountId.toArray().concat(memberIdsByControllerAccountId.toArray()); + const [memberIdByAccount] = memberIdsByRootAccountId.toArray().concat(memberIdsByControllerAccountId.toArray()); + myMemberId = memberIdByAccount; } @@ -78,17 +83,23 @@ function withMyMembership

(Component: React.ComponentT return ; }; + ResultComponent.displayName = `withMyMembership(${componentName(Component)})`; + return ResultComponent; } function resolveMyProfile

(Component: React.ComponentType

) { const ResultComponent: React.FunctionComponent

= (props: P) => { let { myMembership } = props; + myMembership = (!myMembership || myMembership.handle.isEmpty) ? null : myMembership; + return ; }; + ResultComponent.displayName = `resolveMyProfile(${componentName(Component)})`; + return ResultComponent; } @@ -107,7 +118,7 @@ export const withMyAccount =

(Component: React.Compone withMyAddress, withMyMemberIds, withMyMembership, - withMyProfile, + withMyProfile // withContentWorkingGroup, // withCurationActor ); diff --git a/pioneer/packages/joy-utils/src/react/hocs/guards.tsx b/pioneer/packages/joy-utils/src/react/hocs/guards.tsx index 0158fb34ee..e2a3388ee8 100644 --- a/pioneer/packages/joy-utils/src/react/hocs/guards.tsx +++ b/pioneer/packages/joy-utils/src/react/hocs/guards.tsx @@ -47,21 +47,23 @@ export function MembershipRequired

(Component: React.ComponentType } return ( - + Only members can access this functionality.

- + Register here or - + Change key
); }; + ResultComponent.displayName = `MembershipRequired(${componentName(Component)})`; + return ResultComponent; } @@ -71,10 +73,10 @@ export function AccountRequired

(Component: React.ComponentType

if (allAccounts && !Object.keys(allAccounts).length) { return ( - + Please create a key to get started.

- + Create key
@@ -84,7 +86,9 @@ export function AccountRequired

(Component: React.ComponentType

return ; }; + ResultComponent.displayName = `AccountRequired(${componentName(Component)})`; + return ResultComponent; } diff --git a/pioneer/packages/joy-utils/src/react/hooks/index.ts b/pioneer/packages/joy-utils/src/react/hooks/index.ts index 511bdddcf3..f95a7d97e0 100644 --- a/pioneer/packages/joy-utils/src/react/hooks/index.ts +++ b/pioneer/packages/joy-utils/src/react/hooks/index.ts @@ -1,2 +1,2 @@ -export { default as useMyAccount } from './useMyAccount' -export { default as useMyMembership } from './useMyMembership' +export { default as useMyAccount } from './useMyAccount'; +export { default as useMyMembership } from './useMyMembership'; diff --git a/pioneer/packages/joy-utils/src/react/hooks/useMyAccount.tsx b/pioneer/packages/joy-utils/src/react/hooks/useMyAccount.tsx index f86aaa96a9..26ad3a32ea 100644 --- a/pioneer/packages/joy-utils/src/react/hooks/useMyAccount.tsx +++ b/pioneer/packages/joy-utils/src/react/hooks/useMyAccount.tsx @@ -1,5 +1,5 @@ -import { useContext } from 'react' -import { MyAccountContext } from '../context/account' +import { useContext } from 'react'; +import { MyAccountContext } from '../context/account'; export default function useMyAccount () { return useContext(MyAccountContext); diff --git a/pioneer/packages/joy-utils/src/react/hooks/useMyMembership.tsx b/pioneer/packages/joy-utils/src/react/hooks/useMyMembership.tsx index 2ba407cb35..bbf8959a66 100644 --- a/pioneer/packages/joy-utils/src/react/hooks/useMyMembership.tsx +++ b/pioneer/packages/joy-utils/src/react/hooks/useMyMembership.tsx @@ -1,5 +1,5 @@ -import { useContext } from 'react' -import { MyMembershipContext } from '../context' +import { useContext } from 'react'; +import { MyMembershipContext } from '../context'; export default function useMyMembership () { return useContext(MyMembershipContext); diff --git a/pioneer/packages/react-components/src/InputAddress/index.tsx b/pioneer/packages/react-components/src/InputAddress/index.tsx index 0cc98afbad..f458d76b8a 100644 --- a/pioneer/packages/react-components/src/InputAddress/index.tsx +++ b/pioneer/packages/react-components/src/InputAddress/index.tsx @@ -117,6 +117,7 @@ function setLastValue (type: KeyringOption$Type = DEFAULT_TYPE, value: string): options.defaults[type] = value; store.set(STORAGE_KEY, options); + if (type === 'account') { // This lets us update joy-utils account context in order to always be in sync // with options:InputAddress: { defaults: { account } }) from local storage From 83d22c4016c293500857ce1093f65d0d31fcfcac Mon Sep 17 00:00:00 2001 From: Leszek Wiesner Date: Wed, 12 Aug 2020 12:59:33 +0200 Subject: [PATCH 03/15] Linter: Manual fixes --- pioneer/packages/apps/src/JoyTopBar/TopBar.tsx | 4 +--- pioneer/packages/joy-members/src/Details.tsx | 2 +- pioneer/packages/joy-members/src/List.tsx | 4 ++-- pioneer/packages/joy-members/src/MemberPreview.tsx | 2 +- pioneer/packages/joy-members/src/index.tsx | 2 +- pioneer/packages/joy-pages/src/index.tsx | 4 ++-- pioneer/packages/joy-utils/src/functions/format.ts | 4 ++-- pioneer/packages/joy-utils/src/functions/misc.ts | 4 ++-- .../packages/joy-utils/src/react/components/FlexCenter.tsx | 2 +- .../packages/joy-utils/src/react/components/MutedText.tsx | 2 +- .../packages/joy-utils/src/react/components/TxButton.tsx | 2 +- pioneer/packages/joy-utils/src/react/context/account.tsx | 4 ++-- pioneer/packages/joy-utils/src/react/hocs/guards.tsx | 6 +++--- 13 files changed, 20 insertions(+), 22 deletions(-) diff --git a/pioneer/packages/apps/src/JoyTopBar/TopBar.tsx b/pioneer/packages/apps/src/JoyTopBar/TopBar.tsx index b5dd4d8e30..807141b73c 100644 --- a/pioneer/packages/apps/src/JoyTopBar/TopBar.tsx +++ b/pioneer/packages/apps/src/JoyTopBar/TopBar.tsx @@ -5,8 +5,6 @@ import { Available } from '@polkadot/react-query'; import styled from 'styled-components'; import { useApi } from '@polkadot/react-hooks'; -type Props = {}; - const StyledTopBar = styled.div` padding: 0.75rem; background-color: #3f3f3f; @@ -25,7 +23,7 @@ const StyledTopBar = styled.div` } `; -function JoyTopBar (_props: Props) { +function JoyTopBar () { const { allAccounts, myAddress diff --git a/pioneer/packages/joy-members/src/Details.tsx b/pioneer/packages/joy-members/src/Details.tsx index 3756395782..e0c0d77a41 100644 --- a/pioneer/packages/joy-members/src/Details.tsx +++ b/pioneer/packages/joy-members/src/Details.tsx @@ -61,7 +61,7 @@ class Component extends React.PureComponent { return ( <> -

+
{hasAvatar ? : diff --git a/pioneer/packages/joy-members/src/List.tsx b/pioneer/packages/joy-members/src/List.tsx index cd259e271c..e82d92ef46 100644 --- a/pioneer/packages/joy-members/src/List.tsx +++ b/pioneer/packages/joy-members/src/List.tsx @@ -23,7 +23,7 @@ type Props = ApiProps & I18nProps & RouteComponentProps & { match: { params: { page?: string } }; }; -type State = {}; +type State = Record; const MEMBERS_PER_PAGE = 20; @@ -33,7 +33,7 @@ class Component extends React.PureComponent { onPageChange = (e: React.MouseEvent, data: PaginationProps) => { const { history } = this.props; - history.push(`/members/list/${data.activePage}`); + history.push(`/members/list/${data.activePage || 1}`); } renderPagination (currentPage: number, pagesCount: number) { diff --git a/pioneer/packages/joy-members/src/MemberPreview.tsx b/pioneer/packages/joy-members/src/MemberPreview.tsx index 9c8d6b87a9..7af4e59633 100644 --- a/pioneer/packages/joy-members/src/MemberPreview.tsx +++ b/pioneer/packages/joy-members/src/MemberPreview.tsx @@ -47,7 +47,7 @@ class InnerMemberPreview extends React.PureComponent { const avatarSize = inline ? InlineAvatarSizePx : AvatarSizePx; - return
+ return
{prefixLabel && {prefixLabel} diff --git a/pioneer/packages/joy-members/src/index.tsx b/pioneer/packages/joy-members/src/index.tsx index 6edd9a828c..15613c0f8e 100644 --- a/pioneer/packages/joy-members/src/index.tsx +++ b/pioneer/packages/joy-members/src/index.tsx @@ -36,7 +36,7 @@ class App extends React.PureComponent { return [ { name: 'list', - text: t('All members') + ` (${memberCount})`, + text: t('All members') + ` (${memberCount?.toString() || '-'})`, forceMatchParams: true }, { diff --git a/pioneer/packages/joy-pages/src/index.tsx b/pioneer/packages/joy-pages/src/index.tsx index aa18def5ba..189dc921f3 100644 --- a/pioneer/packages/joy-pages/src/index.tsx +++ b/pioneer/packages/joy-pages/src/index.tsx @@ -6,9 +6,9 @@ import ToS_md from './md/ToS.md'; import Privacy_md from './md/Privacy.md'; export function ToS () { - return ; + return ; } export function Privacy () { - return ; + return ; } diff --git a/pioneer/packages/joy-utils/src/functions/format.ts b/pioneer/packages/joy-utils/src/functions/format.ts index 199032140b..8e776a6e5d 100644 --- a/pioneer/packages/joy-utils/src/functions/format.ts +++ b/pioneer/packages/joy-utils/src/functions/format.ts @@ -16,7 +16,7 @@ export const formatReward = ( : next_payment_at_block; return ( - `${formatBalance(amount)}${interval.isSome ? ` / ${interval.unwrap()} block(s)` : ''}` + - ((showNextPaymentBlock && nextPaymentBlock) ? ` (Next payment: #${nextPaymentBlock})` : '') + `${formatBalance(amount)}${interval.isSome ? ` / ${interval.unwrap().toString()} block(s)` : ''}` + + ((showNextPaymentBlock && nextPaymentBlock) ? ` (Next payment: #${nextPaymentBlock.toString()})` : '') ); }; diff --git a/pioneer/packages/joy-utils/src/functions/misc.ts b/pioneer/packages/joy-utils/src/functions/misc.ts index 7263bc8cd1..5f9deaf90e 100644 --- a/pioneer/packages/joy-utils/src/functions/misc.ts +++ b/pioneer/packages/joy-utils/src/functions/misc.ts @@ -33,10 +33,10 @@ export const isNum = (x: any): boolean => typeof x === 'number'; export const isEmptyStr = (x: any): boolean => - notDefined(x) || (isStr(x) && x.trim().length === 0); + notDefined(x) || (isStr(x) && (x as string).trim().length === 0); export const nonEmptyStr = (x?: any) => - isStr(x) && x.trim().length > 0; + isStr(x) && (x as string).trim().length > 0; export const parseNumStr = (num: string): number | undefined => { try { diff --git a/pioneer/packages/joy-utils/src/react/components/FlexCenter.tsx b/pioneer/packages/joy-utils/src/react/components/FlexCenter.tsx index da77d6182b..95a85ea343 100644 --- a/pioneer/packages/joy-utils/src/react/components/FlexCenter.tsx +++ b/pioneer/packages/joy-utils/src/react/components/FlexCenter.tsx @@ -1,5 +1,5 @@ import React from 'react'; -export function FlexCenter (props: React.PropsWithChildren<{}>) { +export function FlexCenter (props: React.PropsWithChildren) { return
{props.children}
; } diff --git a/pioneer/packages/joy-utils/src/react/components/MutedText.tsx b/pioneer/packages/joy-utils/src/react/components/MutedText.tsx index f9eb1309b1..f776a7021e 100644 --- a/pioneer/packages/joy-utils/src/react/components/MutedText.tsx +++ b/pioneer/packages/joy-utils/src/react/components/MutedText.tsx @@ -9,7 +9,7 @@ type Props = React.PropsWithChildren<{ function getClassNames (props: Props): string { const { smaller = false, className } = props; - return `grey text ${smaller ? 'smaller' : ''} ${className}`; + return `grey text ${smaller ? 'smaller' : ''} ${className || ''}`; } export const MutedSpan = (props: Props) => { diff --git a/pioneer/packages/joy-utils/src/react/components/TxButton.tsx b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx index 216e22ee7d..1c8b43c089 100644 --- a/pioneer/packages/joy-utils/src/react/components/TxButton.tsx +++ b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx @@ -68,7 +68,7 @@ class TxButtonInner extends React.PureComponent { queueExtrinsic({ accountId: origin, - extrinsic: api.tx[section][method](...params) as any, // ??? + extrinsic: api.tx[section][method](...params), txFailedCb, txSuccessCb, txStartCb, diff --git a/pioneer/packages/joy-utils/src/react/context/account.tsx b/pioneer/packages/joy-utils/src/react/context/account.tsx index e7b329a024..b3fe56fb48 100644 --- a/pioneer/packages/joy-utils/src/react/context/account.tsx +++ b/pioneer/packages/joy-utils/src/react/context/account.tsx @@ -5,7 +5,7 @@ export const ACCOUNT_CHANGED_EVENT_NAME = 'account-changed'; export const MY_ADDRESS_STORAGE_KEY = 'joy.myAddress'; function readMyAddress (): string | undefined { - const myAddress: string | undefined = store.get(MY_ADDRESS_STORAGE_KEY); + const myAddress = store.get(MY_ADDRESS_STORAGE_KEY) as string | undefined; console.log('Read my address from the local storage:', myAddress); @@ -98,7 +98,7 @@ const contextStub: MyAccountContextProps = { export const MyAccountContext = createContext(contextStub); -export function MyAccountProvider (props: React.PropsWithChildren<{}>) { +export function MyAccountProvider (props: React.PropsWithChildren) { const [state, dispatch] = useReducer(reducer, initialState); const handleAccountChangeEvent = (e: Event) => { diff --git a/pioneer/packages/joy-utils/src/react/hocs/guards.tsx b/pioneer/packages/joy-utils/src/react/hocs/guards.tsx index e2a3388ee8..399052167f 100644 --- a/pioneer/packages/joy-utils/src/react/hocs/guards.tsx +++ b/pioneer/packages/joy-utils/src/react/hocs/guards.tsx @@ -36,7 +36,7 @@ export type MyAccountProps = MyAddressProps & { allAccounts?: SubjectInfo; }; -export function MembershipRequired

(Component: React.ComponentType

): React.ComponentType

{ +export function MembershipRequired

> (Component: React.ComponentType

): React.ComponentType

{ const ResultComponent: React.FunctionComponent

= (props: P) => { const { myMemberIdChecked, iAmMember } = useMyMembership(); @@ -67,7 +67,7 @@ export function MembershipRequired

(Component: React.ComponentType return ResultComponent; } -export function AccountRequired

(Component: React.ComponentType

): React.ComponentType

{ +export function AccountRequired

> (Component: React.ComponentType

): React.ComponentType

{ const ResultComponent: React.FunctionComponent

= (props: P) => { const { allAccounts } = useMyMembership(); @@ -97,7 +97,7 @@ export function AccountRequired

(Component: React.ComponentType

export const withOnlyAccounts =

(Component: React.ComponentType

): React.ComponentType

=> withMulti(Component, withMyAccount, AccountRequired); -export const withMembershipRequired =

(Component: React.ComponentType

): React.ComponentType

=> +export const withMembershipRequired =

> (Component: React.ComponentType

): React.ComponentType

=> withMulti(Component, AccountRequired, MembershipRequired); export const withOnlyMembers =

(Component: React.ComponentType

): React.ComponentType

=> From 8a8f85aee35153a905856dcfb4ab4b8bd4e97f11 Mon Sep 17 00:00:00 2001 From: Leszek Wiesner Date: Wed, 12 Aug 2020 14:49:07 +0200 Subject: [PATCH 04/15] Branding --- .../src/ui/logos/nodes/joystream-node.svg | 16 +--------------- pioneer/packages/apps/public/favicon.ico | Bin 38078 -> 105002 bytes pioneer/packages/apps/webpack.config.js | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) mode change 100644 => 100755 pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg diff --git a/pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg b/pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg old mode 100644 new mode 100755 index d032d300fd..67dd1b71f2 --- a/pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg +++ b/pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg @@ -1,15 +1 @@ - - - background - - - - - - - Layer 1 - - - - - +Icon-mono-white-1bg-blue \ No newline at end of file diff --git a/pioneer/packages/apps/public/favicon.ico b/pioneer/packages/apps/public/favicon.ico index ec3c167a5bf8b409f54ee4dfbce5dc84b70bcfc0..a3d783d522915c1142a139ef9e2eb015c8b8785b 100644 GIT binary patch literal 105002 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 b7`UR9(L4-Gr2@eWR4I)3%LrP2X)W}BdOrD8 literal 38078 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 Date: Fri, 14 Aug 2020 10:37:49 +0200 Subject: [PATCH 05/15] Add gtag in production --- pioneer/packages/apps/public/index.html | 11 +++++++++++ pioneer/packages/apps/webpack.config.js | 1 + 2 files changed, 12 insertions(+) diff --git a/pioneer/packages/apps/public/index.html b/pioneer/packages/apps/public/index.html index c9efd8fa30..d8318bd0c3 100644 --- a/pioneer/packages/apps/public/index.html +++ b/pioneer/packages/apps/public/index.html @@ -6,6 +6,17 @@ <%= htmlWebpackPlugin.options.PAGE_TITLE %> + <% if (htmlWebpackPlugin.options.IS_PROD) { %> + + + + <% } %> diff --git a/pioneer/packages/apps/webpack.config.js b/pioneer/packages/apps/webpack.config.js index bbd5565d56..041f8f8356 100644 --- a/pioneer/packages/apps/webpack.config.js +++ b/pioneer/packages/apps/webpack.config.js @@ -20,6 +20,7 @@ module.exports = merge( devtool: process.env.BUILD_ANALYZE ? 'source-map' : false, plugins: [ new HtmlWebpackPlugin({ + IS_PROD: ENV === 'production', PAGE_TITLE: 'Joystream Network Portal', inject: true, template: path.join(context, `${hasPublic ? 'public/' : ''}index.html`) From 28a4d5584b9d8ba7d7c0fd750b76c9e324188c16 Mon Sep 17 00:00:00 2001 From: Leszek Wiesner Date: Fri, 14 Aug 2020 10:38:47 +0200 Subject: [PATCH 06/15] Fix semantic-ui icons and some minor styles --- pioneer/packages/apps/webpack.base.config.js | 14 +++----------- pioneer/packages/joy-members/src/Details.tsx | 2 +- .../joy-utils/src/react/components/TxButton.tsx | 2 +- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/pioneer/packages/apps/webpack.base.config.js b/pioneer/packages/apps/webpack.base.config.js index 4fb1d34154..c0f79a4010 100644 --- a/pioneer/packages/apps/webpack.base.config.js +++ b/pioneer/packages/apps/webpack.base.config.js @@ -98,7 +98,7 @@ function createWebpack (ENV, context) { ] }, { - exclude: [/semantic-ui-css/], + // Original config had "exclude: [/semantic-ui-css/]" test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], use: [ { @@ -112,7 +112,8 @@ function createWebpack (ENV, context) { ] }, { - exclude: [/semantic-ui-css/], + // Original config had "exclude: [/semantic-ui-css/]", because Semantic UI Icons + // are not used in polkadot-js/apps repository, but they are used in ours test: [/\.eot$/, /\.ttf$/, /\.svg$/, /\.woff$/, /\.woff2$/], use: [ { @@ -123,15 +124,6 @@ function createWebpack (ENV, context) { } } ] - }, - { - include: [/semantic-ui-css/], - test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.eot$/, /\.ttf$/, /\.svg$/, /\.woff$/, /\.woff2$/], - use: [ - { - loader: require.resolve('null-loader') - } - ] } ] }, diff --git a/pioneer/packages/joy-members/src/Details.tsx b/pioneer/packages/joy-members/src/Details.tsx index e0c0d77a41..fa2375c690 100644 --- a/pioneer/packages/joy-members/src/Details.tsx +++ b/pioneer/packages/joy-members/src/Details.tsx @@ -73,7 +73,7 @@ class Component extends React.PureComponent {

{isCouncilor && - + Council member } diff --git a/pioneer/packages/joy-utils/src/react/components/TxButton.tsx b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx index 1c8b43c089..73eb3b3bbe 100644 --- a/pioneer/packages/joy-utils/src/react/components/TxButton.tsx +++ b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx @@ -40,7 +40,7 @@ type PropsWithApi = BareProps & ApiProps & MyAccountProps & PartialQueueTxExtrin class TxButtonInner extends React.PureComponent { render () { - const { myAddress, accountId, isDisabled, icon = 'paper-plane', onClick } = this.props; + const { myAddress, accountId, isDisabled, icon = 'check', onClick } = this.props; const origin = accountId || myAddress; return ( From 5d4a1949599cb2f04f2b8951c7aff10d0fc39a37 Mon Sep 17 00:00:00 2001 From: Leszek Wiesner Date: Fri, 14 Aug 2020 10:23:35 +0200 Subject: [PATCH 07/15] Upgrade joy-election --- package.json | 3 +- pioneer/.eslintignore | 1 - pioneer/packages/apps-routing/src/index.ts | 3 + .../packages/apps-routing/src/joy-election.ts | 17 +++ pioneer/packages/apps-routing/src/types.ts | 2 + pioneer/packages/apps/src/Content/index.tsx | 29 +++- pioneer/packages/apps/src/SideBar/Item.tsx | 7 +- pioneer/packages/joy-election/.skip-build | 0 pioneer/packages/joy-election/package.json | 6 +- .../packages/joy-election/src/Applicant.tsx | 4 +- .../packages/joy-election/src/Applicants.tsx | 29 ++-- .../packages/joy-election/src/ApplyForm.tsx | 40 +++--- .../joy-election/src/CandidatePreview.tsx | 4 +- pioneer/packages/joy-election/src/Council.tsx | 6 +- .../packages/joy-election/src/Dashboard.tsx | 128 +++++++++++------- pioneer/packages/joy-election/src/Reveals.tsx | 28 ++-- .../packages/joy-election/src/SealedVote.tsx | 20 ++- .../packages/joy-election/src/SealedVotes.tsx | 29 ++-- .../joy-election/src/SidebarSubtitle.tsx | 34 +++++ .../packages/joy-election/src/VoteForm.tsx | 54 ++++---- pioneer/packages/joy-election/src/Votes.tsx | 35 ++++- pioneer/packages/joy-election/src/index.css | 28 ---- pioneer/packages/joy-election/src/index.tsx | 22 +-- .../packages/joy-election/src/myVotesStore.ts | 2 +- pioneer/packages/joy-election/src/style.ts | 21 +++ pioneer/packages/joy-election/src/utils.tsx | 3 +- .../packages/joy-utils-old/src/InputStake.tsx | 35 ----- .../src/MemberByAccountPreview.tsx | 48 ------- .../joy-utils-old/src/transport/base.ts | 107 --------------- .../joy-utils-old/src/transport/index.ts | 34 ----- .../src/react/components/InputStake.tsx | 46 +++++++ .../components/MemberByAccountPreview.tsx | 43 ++++++ .../components}/MemberProfilePreview.tsx | 0 .../src/react/components}/MembersDropdown.tsx | 14 +- .../src/react/components/PromiseComponent.tsx | 0 .../joy-utils/src/react/context/index.tsx | 1 + .../src/react/context/transport.tsx | 0 .../joy-utils/src/react/hooks/index.ts | 2 + .../src/react/hooks/usePromise.tsx | 0 .../src/react/hooks/useTransport.tsx | 0 .../src/transport}/APIQueryCache.ts | 0 .../packages/joy-utils/src/transport/base.ts | 66 +++++++++ .../packages/joy-utils/src/transport/index.ts | 34 +++++ .../src/transport/members.ts | 16 +++ .../src/types/members.ts | 4 + .../old-apps/apps-routing/src/joy-election.ts | 19 --- .../react-components/src/styles/joystream.ts | 93 +++++-------- pioneer/tsconfig.json | 5 +- 48 files changed, 609 insertions(+), 513 deletions(-) create mode 100644 pioneer/packages/apps-routing/src/joy-election.ts delete mode 100644 pioneer/packages/joy-election/.skip-build create mode 100644 pioneer/packages/joy-election/src/SidebarSubtitle.tsx delete mode 100644 pioneer/packages/joy-election/src/index.css create mode 100644 pioneer/packages/joy-election/src/style.ts delete mode 100644 pioneer/packages/joy-utils-old/src/InputStake.tsx delete mode 100644 pioneer/packages/joy-utils-old/src/MemberByAccountPreview.tsx delete mode 100644 pioneer/packages/joy-utils-old/src/transport/base.ts delete mode 100644 pioneer/packages/joy-utils-old/src/transport/index.ts create mode 100644 pioneer/packages/joy-utils/src/react/components/InputStake.tsx create mode 100644 pioneer/packages/joy-utils/src/react/components/MemberByAccountPreview.tsx rename pioneer/packages/{joy-utils-old/src => joy-utils/src/react/components}/MemberProfilePreview.tsx (100%) rename pioneer/packages/{joy-utils-old/src => joy-utils/src/react/components}/MembersDropdown.tsx (82%) rename pioneer/packages/{joy-utils-old => joy-utils}/src/react/components/PromiseComponent.tsx (100%) rename pioneer/packages/{joy-utils-old => joy-utils}/src/react/context/transport.tsx (100%) rename pioneer/packages/{joy-utils-old => joy-utils}/src/react/hooks/usePromise.tsx (100%) rename pioneer/packages/{joy-utils-old => joy-utils}/src/react/hooks/useTransport.tsx (100%) rename pioneer/packages/{joy-utils-old/src => joy-utils/src/transport}/APIQueryCache.ts (100%) create mode 100644 pioneer/packages/joy-utils/src/transport/base.ts create mode 100644 pioneer/packages/joy-utils/src/transport/index.ts rename pioneer/packages/{joy-utils-old => joy-utils}/src/transport/members.ts (53%) rename pioneer/packages/{joy-utils-old => joy-utils}/src/types/members.ts (64%) delete mode 100644 pioneer/packages/old-apps/apps-routing/src/joy-election.ts diff --git a/package.json b/package.json index 2928330f15..ad47384381 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "pioneer/packages/react*", "pioneer/packages/joy-utils", "pioneer/packages/joy-members", - "pioneer/packages/joy-pages" + "pioneer/packages/joy-pages", + "pioneer/packages/joy-election" ], "resolutions": { "@polkadot/api": "1.26.1", diff --git a/pioneer/.eslintignore b/pioneer/.eslintignore index 42a2471efd..57bb4f9e3e 100644 --- a/pioneer/.eslintignore +++ b/pioneer/.eslintignore @@ -2,7 +2,6 @@ **/coverage/* **/node_modules/* packages/old-apps/* -packages/joy-election/* packages/joy-forum/* packages/joy-help/* packages/joy-media/* diff --git a/pioneer/packages/apps-routing/src/index.ts b/pioneer/packages/apps-routing/src/index.ts index f4ba69e507..36f9671d31 100644 --- a/pioneer/packages/apps-routing/src/index.ts +++ b/pioneer/packages/apps-routing/src/index.ts @@ -20,11 +20,13 @@ import transfer from './transfer'; // Joy packages import members from './joy-members'; import { terms, privacyPolicy } from './joy-pages'; +import election from './joy-election'; export default function create (t: (key: string, text: string, options: { ns: string }) => T): Routes { return appSettings.uiMode === 'light' ? [ members(t), + election(t), null, transfer(t), accounts(t), @@ -32,6 +34,7 @@ export default function create (t: (key: string, text: string, opti ] : [ members(t), + election(t), null, transfer(t), accounts(t), diff --git a/pioneer/packages/apps-routing/src/joy-election.ts b/pioneer/packages/apps-routing/src/joy-election.ts new file mode 100644 index 0000000000..ebf857ad81 --- /dev/null +++ b/pioneer/packages/apps-routing/src/joy-election.ts @@ -0,0 +1,17 @@ +import { Route } from './types'; + +import Election from '@polkadot/joy-election/index'; +import SidebarSubtitle from '@polkadot/joy-election/SidebarSubtitle'; + +export default function create (t: (key: string, text: string, options: { ns: string }) => T): Route { + return { + Component: Election, + display: { + needsApi: ['query.council.activeCouncil', 'query.councilElection.stage'] + }, + text: t('nav.election', 'Council', { ns: 'apps-routing' }), + icon: 'university', + name: 'council', + SubtitleComponent: SidebarSubtitle + } +} diff --git a/pioneer/packages/apps-routing/src/types.ts b/pioneer/packages/apps-routing/src/types.ts index 6dce432d8c..4a6695fef2 100644 --- a/pioneer/packages/apps-routing/src/types.ts +++ b/pioneer/packages/apps-routing/src/types.ts @@ -24,6 +24,8 @@ export interface Route { name: string; text: string; useCounter?: () => number | string | null; + // Joystream-specific + SubtitleComponent?: React.ComponentType; } export type Routes = (Route | null)[]; diff --git a/pioneer/packages/apps/src/Content/index.tsx b/pioneer/packages/apps/src/Content/index.tsx index 63f0238535..cf2dc00224 100644 --- a/pioneer/packages/apps/src/Content/index.tsx +++ b/pioneer/packages/apps/src/Content/index.tsx @@ -16,6 +16,11 @@ import { useTranslation } from '../translate'; import NotFound from './NotFound'; import Status from './Status'; +// Joystream-specific +// We must use transport provider here instead of /apps/src/index +// to avoid "Cannot create Transport: The Substrate API is not ready yet." error +import { TransportProvider } from '@polkadot/joy-utils/react/context'; + interface Props { className?: string; } @@ -60,11 +65,25 @@ function Content ({ className }: Props): React.ReactElement { ? : ( - + { needsApi + // Add transport provider for routes that need the api + // (the above condition makes sure it's aleady initialized at this point) + ? ( + + + + ) + : ( + + ) } ) } diff --git a/pioneer/packages/apps/src/SideBar/Item.tsx b/pioneer/packages/apps/src/SideBar/Item.tsx index abcd801144..629f9c9c19 100644 --- a/pioneer/packages/apps/src/SideBar/Item.tsx +++ b/pioneer/packages/apps/src/SideBar/Item.tsx @@ -79,12 +79,15 @@ function Item ({ isCollapsed, onClick, route }: Props): React.ReactElement - {text} + + {text} + { SubtitleComponent && } + {!!count && ( ; + stage?: Option; }; class Applicants extends React.PureComponent { @@ -38,12 +41,21 @@ class Applicants extends React.PureComponent { ) render () { - const { myAddress, applicants = [], candidacyLimit = new BN(0) } = this.props; + const { myAddress, applicants = [], candidacyLimit = new BN(0), stage } = this.props; const title = Applicants {applicants.length}/{formatNumber(candidacyLimit)}; return <>
- + { stage?.unwrapOr(undefined)?.isOfType('Announcing') + ? ( + + ) + : ( + + Applying to council is only possible during Announcing stage. + + ) + }
{!applicants.length @@ -59,6 +71,7 @@ class Applicants extends React.PureComponent { export default translate( withCalls( queryToProp('query.councilElection.candidacyLimit'), - queryToProp('query.councilElection.applicants') + queryToProp('query.councilElection.applicants'), + queryToProp('query.councilElection.stage') )(withMyAccount(Applicants)) ); diff --git a/pioneer/packages/joy-election/src/ApplyForm.tsx b/pioneer/packages/joy-election/src/ApplyForm.tsx index f058fc992c..f0f753f37c 100644 --- a/pioneer/packages/joy-election/src/ApplyForm.tsx +++ b/pioneer/packages/joy-election/src/ApplyForm.tsx @@ -3,21 +3,21 @@ import React from 'react'; import { I18nProps } from '@polkadot/react-components/types'; import { ApiProps } from '@polkadot/react-api/types'; -import { withCalls, withMulti } from '@polkadot/react-api/with'; +import { withCalls, withMulti } from '@polkadot/react-api/hoc'; import { Labelled } from '@polkadot/react-components/index'; import { Balance } from '@polkadot/types/interfaces'; import translate from './translate'; -import TxButton from '@polkadot/joy-utils/TxButton'; -import InputStake from '@polkadot/joy-utils/InputStake'; +import TxButton from '@polkadot/joy-utils/react/components/TxButton'; +import InputStake from '@polkadot/joy-utils/react/components/InputStake'; import { ElectionStake } from '@joystream/types/council'; -import { calcTotalStake, ZERO } from '@polkadot/joy-utils/index'; -import { MyAddressProps, withOnlyMembers } from '@polkadot/joy-utils/MyAccount'; +import { calcTotalStake, ZERO } from '@polkadot/joy-utils/functions/misc'; +import { MyAddressProps } from '@polkadot/joy-utils/react/hocs/accounts'; +import { withOnlyMembers } from '@polkadot/joy-utils/react/hocs/guards'; type Props = ApiProps & I18nProps & MyAddressProps & { minStake?: Balance; alreadyStaked?: ElectionStake; - myBalance?: Balance; }; type State = { @@ -48,15 +48,17 @@ class ApplyForm extends React.PureComponent { isValid={isStakeValid} onChange={this.onChangeStake} /> - - - +
+ + + +
); } @@ -71,10 +73,8 @@ class ApplyForm extends React.PureComponent { private onChangeStake = (stake?: BN): void => { stake = stake || ZERO; - const { myBalance = ZERO } = this.props; - const isStakeLteBalance = stake.lte(myBalance); const isStakeGteMinStake = stake.add(this.alreadyStaked()).gte(this.minStake()); - const isStakeValid = !stake.isZero() && isStakeGteMinStake && isStakeLteBalance; + const isStakeValid = !stake.isZero() && isStakeGteMinStake; this.setState({ stake, isStakeValid }); } } @@ -88,8 +88,6 @@ export default withMulti( ['query.councilElection.minCouncilStake', { propName: 'minStake' }], ['query.councilElection.applicantStakes', - { paramName: 'myAddress', propName: 'alreadyStaked' }], - ['query.balances.freeBalance', - { paramName: 'myAddress', propName: 'myBalance' }] + { paramName: 'myAddress', propName: 'alreadyStaked' }] ) ); diff --git a/pioneer/packages/joy-election/src/CandidatePreview.tsx b/pioneer/packages/joy-election/src/CandidatePreview.tsx index 9e6571efb6..bab07182e7 100644 --- a/pioneer/packages/joy-election/src/CandidatePreview.tsx +++ b/pioneer/packages/joy-election/src/CandidatePreview.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import AddressMini from '@polkadot/react-components/AddressMiniJoy'; -import MemberByAccount from '@polkadot/joy-utils/MemberByAccountPreview'; +import AddressMini from '@polkadot/react-components/AddressMini'; +import MemberByAccount from '@polkadot/joy-utils/react/components/MemberByAccountPreview'; import { AccountId } from '@polkadot/types/interfaces'; import styled from 'styled-components'; diff --git a/pioneer/packages/joy-election/src/Council.tsx b/pioneer/packages/joy-election/src/Council.tsx index b81c144883..72f4ff5ea8 100644 --- a/pioneer/packages/joy-election/src/Council.tsx +++ b/pioneer/packages/joy-election/src/Council.tsx @@ -2,15 +2,15 @@ import React from 'react'; import { ApiProps } from '@polkadot/react-api/types'; import { I18nProps } from '@polkadot/react-components/types'; -import { withCalls } from '@polkadot/react-api/with'; +import { withCalls } from '@polkadot/react-api/hoc'; import { Table } from 'semantic-ui-react'; import { formatBalance } from '@polkadot/util'; import CouncilCandidate from './CandidatePreview'; -import { calcBackersStake } from '@polkadot/joy-utils/index'; +import { calcBackersStake } from '@polkadot/joy-utils/functions/misc'; import { Seat } from '@joystream/types/council'; import translate from './translate'; -import Section from '@polkadot/joy-utils/Section'; +import Section from '@polkadot/joy-utils/react/components/Section'; type Props = ApiProps & I18nProps & { diff --git a/pioneer/packages/joy-election/src/Dashboard.tsx b/pioneer/packages/joy-election/src/Dashboard.tsx index c7f64ef811..b962c1e5aa 100644 --- a/pioneer/packages/joy-election/src/Dashboard.tsx +++ b/pioneer/packages/joy-election/src/Dashboard.tsx @@ -3,14 +3,14 @@ import React from 'react'; import { ApiProps } from '@polkadot/react-api/types'; import { I18nProps } from '@polkadot/react-components/types'; -import { withCalls } from '@polkadot/react-api/with'; +import { withCalls } from '@polkadot/react-api/hoc'; import { Option } from '@polkadot/types'; import { BlockNumber, Balance } from '@polkadot/types/interfaces'; -import { Bubble } from '@polkadot/react-components/index'; +import { Label, Icon } from 'semantic-ui-react'; import { formatNumber, formatBalance } from '@polkadot/util'; -import Section from '@polkadot/joy-utils/Section'; -import { queryToProp } from '@polkadot/joy-utils/index'; +import Section from '@polkadot/joy-utils/react/components/Section'; +import { queryToProp } from '@polkadot/joy-utils/functions/misc'; import { ElectionStage, Seat } from '@joystream/types/council'; import translate from './translate'; @@ -45,12 +45,17 @@ class Dashboard extends React.PureComponent { const title = `Council ${activeCouncil.length > 0 ? '' : '(not elected)'}`; return
- - {activeCouncil.length} - - - {formatNumber(p.termEndsAt)} - + + + +
; } @@ -76,20 +81,28 @@ class Dashboard extends React.PureComponent { const title = <>Election ({stateText}); return
- - {formatNumber(round)} - - {isRunning && <> - - {stageName} - - - {formatNumber(leftBlocks)} - - - {formatNumber(stageEndsAt)} - - } + + + {isRunning && <> + + + + } +
; } @@ -98,33 +111,46 @@ class Dashboard extends React.PureComponent { const isAutoStart = (p.autoStart || false).valueOf(); return
- - {isAutoStart ? 'Yes' : 'No'} - - - {formatNumber(p.newTermDuration)} - - - {formatNumber(p.candidacyLimit)} - - - {formatNumber(p.councilSize)} - - - {formatBalance(p.minCouncilStake)} - - - {formatBalance(p.minVotingStake)} - - - {formatNumber(p.announcingPeriod)} blocks - - - {formatNumber(p.votingPeriod)} blocks - - - {formatNumber(p.revealingPeriod)} blocks - + + + + + + + + + + + + +
; } diff --git a/pioneer/packages/joy-election/src/Reveals.tsx b/pioneer/packages/joy-election/src/Reveals.tsx index 6a20dad6f9..b54330d5f7 100644 --- a/pioneer/packages/joy-election/src/Reveals.tsx +++ b/pioneer/packages/joy-election/src/Reveals.tsx @@ -2,16 +2,16 @@ import React from 'react'; import { AppProps, I18nProps } from '@polkadot/react-components/types'; import { ApiProps } from '@polkadot/react-api/types'; -import { withCalls, withMulti } from '@polkadot/react-api/with'; +import { withCalls, withMulti } from '@polkadot/react-api/hoc'; import { AccountId } from '@polkadot/types/interfaces'; import { Input, Labelled, InputAddress } from '@polkadot/react-components/index'; import translate from './translate'; -import { nonEmptyStr, queryToProp, getUrlParam } from '@polkadot/joy-utils/index'; +import { nonEmptyStr, queryToProp, getUrlParam } from '@polkadot/joy-utils/functions/misc'; import { accountIdsToOptions, hashVote } from './utils'; -import TxButton from '@polkadot/joy-utils/TxButton'; +import TxButton from '@polkadot/joy-utils/react/components/TxButton'; import { findVoteByHash } from './myVotesStore'; -import { withOnlyMembers } from '@polkadot/joy-utils/MyAccount'; +import { withOnlyMembers } from '@polkadot/joy-utils/react/hocs/guards'; // AppsProps is needed to get a location from the route. type Props = AppProps & ApiProps & I18nProps & { @@ -81,15 +81,17 @@ class RevealVoteForm extends React.PureComponent { onChange={this.onChangeSalt} />
} - - - +
+ + + +
); } diff --git a/pioneer/packages/joy-election/src/SealedVote.tsx b/pioneer/packages/joy-election/src/SealedVote.tsx index 54650328c1..b935d04e11 100644 --- a/pioneer/packages/joy-election/src/SealedVote.tsx +++ b/pioneer/packages/joy-election/src/SealedVote.tsx @@ -1,28 +1,30 @@ import React from 'react'; import { Link } from 'react-router-dom'; -import { Table } from 'semantic-ui-react'; +import { Table, Message } from 'semantic-ui-react'; import { I18nProps } from '@polkadot/react-components/types'; import { ApiProps } from '@polkadot/react-api/types'; -import { withCalls } from '@polkadot/react-api/with'; +import { withCalls } from '@polkadot/react-api/hoc'; import { Hash } from '@polkadot/types/interfaces'; import { formatBalance } from '@polkadot/util'; import translate from './translate'; -import { calcTotalStake } from '@polkadot/joy-utils/index'; +import { calcTotalStake } from '@polkadot/joy-utils/functions/misc'; import { SealedVote } from '@joystream/types/council'; -import AddressMini from '@polkadot/react-components/AddressMiniJoy'; +import AddressMini from '@polkadot/react-components/AddressMini'; import CandidatePreview from './CandidatePreview'; import { findVoteByHash } from './myVotesStore'; type Props = ApiProps & I18nProps & { hash: Hash; sealedVote?: SealedVote; + isStageRevealing: boolean; + isMyVote: boolean; }; class Comp extends React.PureComponent { renderCandidateOrAction () { - const { hash, sealedVote } = this.props; + const { hash, sealedVote, isStageRevealing, isMyVote } = this.props; if (!sealedVote) { return Unknown hashed vote: {hash.toHex()}; } @@ -30,10 +32,16 @@ class Comp extends React.PureComponent { if (sealedVote.vote.isSome) { const candidateId = sealedVote.vote.unwrap(); return ; - } else { + } else if (isStageRevealing && isMyVote) { const revealUrl = `/council/reveals?hashedVote=${hash.toHex()}`; return Reveal this vote; } + else if (isMyVote) { + return Wait until Revealing stage in order to reveal this vote. + } + else { + return This vote has not been revealed yet. + } } render () { diff --git a/pioneer/packages/joy-election/src/SealedVotes.tsx b/pioneer/packages/joy-election/src/SealedVotes.tsx index 1f03b66ac0..8dd5abf374 100644 --- a/pioneer/packages/joy-election/src/SealedVotes.tsx +++ b/pioneer/packages/joy-election/src/SealedVotes.tsx @@ -4,19 +4,20 @@ import { Button } from 'semantic-ui-react'; import { I18nProps } from '@polkadot/react-components/types'; import { ApiProps } from '@polkadot/react-api/types'; -import { withCalls } from '@polkadot/react-api/with'; +import { withCalls } from '@polkadot/react-api/hoc'; import { Hash } from '@polkadot/types/interfaces'; import translate from './translate'; import SealedVote from './SealedVote'; -import { queryToProp } from '@polkadot/joy-utils/index'; -import { MyAddressProps } from '@polkadot/joy-utils/MyAccount'; +import { queryToProp } from '@polkadot/joy-utils/functions/misc'; +import { MyAddressProps } from '@polkadot/joy-utils/react/hocs/accounts'; import { SavedVote } from './myVotesStore'; -import Section from '@polkadot/joy-utils/Section'; +import Section from '@polkadot/joy-utils/react/components/Section'; type Props = ApiProps & I18nProps & MyAddressProps & { myVotes?: SavedVote[]; commitments?: Hash[]; + isStageRevealing: boolean; }; class Comp extends React.PureComponent { @@ -28,9 +29,13 @@ class Comp extends React.PureComponent { return commitments.filter(x => myVotesOnly === isMyVote(x.toHex())); } - private renderVotes = (votes: Hash[]) => { + private renderVotes = (votes: Hash[], areVotesMine: boolean) => { return votes.map((hash, index) => - + ); } @@ -39,17 +44,19 @@ class Comp extends React.PureComponent { const otherVotes = this.filterVotes(false); return <> -
{ +
+ { !myVotes.length ? No votes by the current account found on the current browser. - : this.renderVotes(myVotes) - }
+ : this.renderVotes(myVotes, true) + } + { this.props.isStageRevealing && } +
- { !otherVotes.length ? No votes submitted by other accounts yet. - : this.renderVotes(otherVotes) + : this.renderVotes(otherVotes, false) }
; diff --git a/pioneer/packages/joy-election/src/SidebarSubtitle.tsx b/pioneer/packages/joy-election/src/SidebarSubtitle.tsx new file mode 100644 index 0000000000..bbd59e6c6b --- /dev/null +++ b/pioneer/packages/joy-election/src/SidebarSubtitle.tsx @@ -0,0 +1,34 @@ +/** Component providing election stage subtitle for SideBar menu **/ +import React from 'react'; +import { ElectionStage } from '@joystream/types/council'; +import { Option } from '@polkadot/types/codec'; +import { useApi, useCall } from '@polkadot/react-hooks'; +import styled from 'styled-components'; + +const colorByStage = { + Announcing: '#4caf50', + Voting: '#2196f3', + Revealing: '#ff5722' +} as const; + +type StyledSubtitleProps = { + stage?: keyof typeof colorByStage; +} +const StyledSubtitle = styled.div` + display: block; + font-size: 0.85rem; + color: ${ (props: StyledSubtitleProps) => props.stage ? colorByStage[props.stage] : 'grey' }; +`; + +export default function SidebarSubtitle () { + const apiProps = useApi(); + const electionStage = useCall>(apiProps.isApiReady && apiProps.api.query.councilElection.stage, []); + + if (electionStage) { + const stageName = electionStage.unwrapOr(undefined)?.type; + const text = stageName ? `${stageName} stage` : 'No active election'; + return {text}; + } + + return null; +} diff --git a/pioneer/packages/joy-election/src/VoteForm.tsx b/pioneer/packages/joy-election/src/VoteForm.tsx index 63fbb78b17..b567669d7f 100644 --- a/pioneer/packages/joy-election/src/VoteForm.tsx +++ b/pioneer/packages/joy-election/src/VoteForm.tsx @@ -6,7 +6,7 @@ import { Message, Table } from 'semantic-ui-react'; import { AppProps, I18nProps } from '@polkadot/react-components/types'; import { ApiProps } from '@polkadot/react-api/types'; -import { withCalls, withMulti } from '@polkadot/react-api/with'; +import { withCalls, withMulti } from '@polkadot/react-api/hoc'; import { AccountId, Balance } from '@polkadot/types/interfaces'; import { Button, Input, Labelled } from '@polkadot/react-components/index'; import { SubmittableResult } from '@polkadot/api'; @@ -14,12 +14,13 @@ import { formatBalance } from '@polkadot/util'; import translate from './translate'; import { hashVote } from './utils'; -import { queryToProp, ZERO, getUrlParam, nonEmptyStr } from '@polkadot/joy-utils/index'; -import TxButton from '@polkadot/joy-utils/TxButton'; -import InputStake from '@polkadot/joy-utils/InputStake'; +import { queryToProp, ZERO, getUrlParam, nonEmptyStr } from '@polkadot/joy-utils/functions/misc'; +import TxButton from '@polkadot/joy-utils/react/components/TxButton'; +import InputStake from '@polkadot/joy-utils/react/components/InputStake'; import CandidatePreview from './CandidatePreview'; -import { MyAccountProps, withOnlyMembers } from '@polkadot/joy-utils/MyAccount'; -import MembersDropdown from '@polkadot/joy-utils/MembersDropdown'; +import { MyAccountProps } from '@polkadot/joy-utils/react/hocs/accounts'; +import { withOnlyMembers } from '@polkadot/joy-utils/react/hocs/guards' +import MembersDropdown from '@polkadot/joy-utils/react/components/MembersDropdown'; import { saveVote, NewVote } from './myVotesStore'; import { TxFailedCallback } from '@polkadot/react-components/Status/types'; @@ -103,14 +104,11 @@ class Component extends React.PureComponent { - -
// New vote form: @@ -137,7 +135,7 @@ class Component extends React.PureComponent { onChange={this.onChangeSalt} />
- +
@@ -148,18 +146,20 @@ class Component extends React.PureComponent { value={hashedVote} /> - - this.onTxSuccess(buildNewVote() as NewVote, txResult)} - /> - +
+ + this.onTxSuccess(buildNewVote() as NewVote, txResult)} + /> + +
} ); diff --git a/pioneer/packages/joy-election/src/Votes.tsx b/pioneer/packages/joy-election/src/Votes.tsx index a1558406e6..d238dcd6c6 100644 --- a/pioneer/packages/joy-election/src/Votes.tsx +++ b/pioneer/packages/joy-election/src/Votes.tsx @@ -2,30 +2,51 @@ import React from 'react'; import { AppProps, I18nProps } from '@polkadot/react-components/types'; import { ApiProps } from '@polkadot/react-api/types'; +import { withCalls } from '@polkadot/react-api/hoc'; +import { Message } from 'semantic-ui-react'; +import { Option } from '@polkadot/types'; import translate from './translate'; import SealedVotes from './SealedVotes'; -import Section from '@polkadot/joy-utils/Section'; -import { withMyAccount, MyAccountProps } from '@polkadot/joy-utils/MyAccount'; +import Section from '@polkadot/joy-utils/react/components/Section'; +import { withMyAccount, MyAccountProps } from '@polkadot/joy-utils/react/hocs/accounts'; import { getVotesByVoter } from './myVotesStore'; import VoteForm from './VoteForm'; +import { queryToProp } from '@polkadot/joy-utils/functions/misc'; +import { ElectionStage } from '@joystream/types/src/council'; -type Props = AppProps & ApiProps & I18nProps & MyAccountProps & {}; +type Props = AppProps & ApiProps & I18nProps & MyAccountProps & { + stage?: Option; +}; class Component extends React.PureComponent { render () { - const { myAddress } = this.props; + const { myAddress, stage } = this.props; const myVotes = myAddress ? getVotesByVoter(myAddress) : []; return <>
- + { stage?.unwrapOr(undefined)?.isOfType('Voting') + ? ( + + ) + : ( + + Voting is only possible during Voting stage. + + ) + }
- + ; } } export default translate( - withMyAccount(Component) + withCalls( + queryToProp('query.councilElection.stage') + )(withMyAccount(Component)) ); diff --git a/pioneer/packages/joy-election/src/index.css b/pioneer/packages/joy-election/src/index.css deleted file mode 100644 index 5ad24c8384..0000000000 --- a/pioneer/packages/joy-election/src/index.css +++ /dev/null @@ -1,28 +0,0 @@ - -.JoyElection--NotRunning { - /* nothing yet */ -} -.JoyElection--Running { - font-style: italic; - color: green; -} -.SealedVoteTable { - -webkit-box-shadow: 0 1px 2px 0 rgba(34,36,38,.15) !important; - box-shadow: 0 1px 2px 0 rgba(34,36,38,.15) !important; - tr td:first-child { - color: #999 !important; - font-weight: normal !important; - } -} - -.SidebarSubtitle { - &.Announcing { - color: #4caf50; /* green */ - } - &.Voting { - color: #2196f3; /* blue */ - } - &.Revealing { - color: #ff5722; /* red */ - } -} \ No newline at end of file diff --git a/pioneer/packages/joy-election/src/index.tsx b/pioneer/packages/joy-election/src/index.tsx index c4206c3aeb..9a6490b190 100644 --- a/pioneer/packages/joy-election/src/index.tsx +++ b/pioneer/packages/joy-election/src/index.tsx @@ -1,14 +1,16 @@ import React from 'react'; import { Route, Switch } from 'react-router'; -import { AppProps, I18nProps } from '@polkadot/react-components/types'; -import { ApiProps } from '@polkadot/react-api/types'; -import { withCalls } from '@polkadot/react-api/with'; +import { I18nProps } from '@polkadot/react-components/types'; +import { RouteProps } from '@polkadot/apps-routing/types'; +import { withCalls } from '@polkadot/react-api/hoc'; import { AccountId, Hash } from '@polkadot/types/interfaces'; -import Tabs, { TabItem } from '@polkadot/react-components/Tabs'; +import Tabs from '@polkadot/react-components/Tabs'; +import { TabItem } from '@polkadot/react-components/Tabs/types'; // our app-specific styles -import './index.css'; +import style from './style'; +import styled from 'styled-components'; // local imports and components import translate from './translate'; @@ -17,11 +19,13 @@ import Council from './Council'; import Applicants from './Applicants'; import Votes from './Votes'; import Reveals from './Reveals'; -import { queryToProp } from '@polkadot/joy-utils/index'; +import { queryToProp } from '@polkadot/joy-utils/functions/misc'; import { Seat } from '@joystream/types/council'; +const ElectionMain = styled.main`${style}`; + // define out internal types -type Props = AppProps & ApiProps & I18nProps & { +type Props = RouteProps & I18nProps & { activeCouncil?: Seat[]; applicants?: AccountId[]; commitments?: Hash[]; @@ -59,7 +63,7 @@ class App extends React.PureComponent { const { basePath } = this.props; const tabs = this.buildTabs(); return ( -
+
@@ -70,7 +74,7 @@ class App extends React.PureComponent { -
+ ); } } diff --git a/pioneer/packages/joy-election/src/myVotesStore.ts b/pioneer/packages/joy-election/src/myVotesStore.ts index 46a500780f..cfc3bc3d96 100644 --- a/pioneer/packages/joy-election/src/myVotesStore.ts +++ b/pioneer/packages/joy-election/src/myVotesStore.ts @@ -1,5 +1,5 @@ import store from 'store'; -import { nonEmptyArr } from '@polkadot/joy-utils/index'; +import { nonEmptyArr } from '@polkadot/joy-utils/functions/misc'; const MY_VOTES = 'joy.myVotes'; diff --git a/pioneer/packages/joy-election/src/style.ts b/pioneer/packages/joy-election/src/style.ts new file mode 100644 index 0000000000..74bc548645 --- /dev/null +++ b/pioneer/packages/joy-election/src/style.ts @@ -0,0 +1,21 @@ +import { css } from 'styled-components'; + +const style = css` + .JoyElection--NotRunning { + /* nothing yet */ + } + .JoyElection--Running { + font-style: italic; + color: green; + } + .SealedVoteTable { + -webkit-box-shadow: 0 1px 2px 0 rgba(34,36,38,.15) !important; + box-shadow: 0 1px 2px 0 rgba(34,36,38,.15) !important; + tr td:first-child { + color: #999 !important; + font-weight: normal !important; + } + } +`; + +export default style; diff --git a/pioneer/packages/joy-election/src/utils.tsx b/pioneer/packages/joy-election/src/utils.tsx index 1a82754ee0..5a4cafb55a 100644 --- a/pioneer/packages/joy-election/src/utils.tsx +++ b/pioneer/packages/joy-election/src/utils.tsx @@ -1,10 +1,11 @@ +// TODO: Move to joy-utils? import { AccountId } from '@polkadot/types/interfaces'; // Keyring / identicon / address // ----------------------------------- import createItem from '@polkadot/ui-keyring/options/item'; -import { findNameByAddress } from '@polkadot/joy-utils/index'; +import { findNameByAddress } from '@polkadot/joy-utils/functions/misc'; // Hash // ----------------------------------- diff --git a/pioneer/packages/joy-utils-old/src/InputStake.tsx b/pioneer/packages/joy-utils-old/src/InputStake.tsx deleted file mode 100644 index a6385a19e4..0000000000 --- a/pioneer/packages/joy-utils-old/src/InputStake.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import BN from 'bn.js'; -import React from 'react'; -import { InputBalance, Bubble } from '@polkadot/react-components/index'; -import { formatBalance } from '@polkadot/util'; - -type Props = { - label?: string; - min?: BN; - isValid?: boolean; - onChange: (stake?: BN) => void; -}; - -export default class Component extends React.PureComponent { - render () { - const { min, label, isValid, onChange } = this.props; - return ( -
- - {min && !min.isZero() &&
- - {formatBalance(min)} - -
} -
- ); - } -} diff --git a/pioneer/packages/joy-utils-old/src/MemberByAccountPreview.tsx b/pioneer/packages/joy-utils-old/src/MemberByAccountPreview.tsx deleted file mode 100644 index 7eeb618a24..0000000000 --- a/pioneer/packages/joy-utils-old/src/MemberByAccountPreview.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { useEffect, useState, useContext } from 'react'; - -import { Loader } from 'semantic-ui-react'; -import { ApiContext } from '@polkadot/react-api'; -import ProfilePreview from './MemberProfilePreview'; -import { AccountId } from '@polkadot/types/interfaces'; -import { memberFromAccount, MemberFromAccount } from './accounts'; - -import styled from 'styled-components'; - -const MemberByAccount = styled.div``; - -type Props = { - accountId: AccountId | string; -}; - -const MemberByAccountPreview: React.FunctionComponent = ({ accountId }) => { - const { api } = useContext(ApiContext); - const [member, setMember] = useState(null as MemberFromAccount | null); - useEffect( - () => { - let isSubscribed = true; - memberFromAccount(api, accountId).then(member => isSubscribed && setMember(member)); - return () => { isSubscribed = false; }; - }, - [accountId] - ); - - return ( - - { member - ? ( - member.profile - ? - : 'Member profile not found!' - ) - : Fetching member profile... - } - - ); -}; - -export default MemberByAccountPreview; diff --git a/pioneer/packages/joy-utils-old/src/transport/base.ts b/pioneer/packages/joy-utils-old/src/transport/base.ts deleted file mode 100644 index 9375f99c14..0000000000 --- a/pioneer/packages/joy-utils-old/src/transport/base.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { ApiPromise } from '@polkadot/api'; -import { Codec } from '@polkadot/types/types'; -import { APIQueryCache } from '../APIQueryCache'; - -export default abstract class BaseTransport { - protected api: ApiPromise; - protected cacheApi: APIQueryCache; - - constructor (api: ApiPromise, cacheApi: APIQueryCache) { - this.api = api; - this.cacheApi = cacheApi; - } - - protected get proposalsEngine () { - return this.cacheApi.query.proposalsEngine; - } - - protected get proposalsCodex () { - return this.cacheApi.query.proposalsCodex; - } - - protected get proposalsDiscussion () { - return this.cacheApi.query.proposalsDiscussion; - } - - protected get members () { - return this.cacheApi.query.members; - } - - protected get council () { - return this.cacheApi.query.council; - } - - protected get councilElection () { - return this.cacheApi.query.councilElection; - } - - protected get actors () { - return this.cacheApi.query.actors; - } - - protected get contentWorkingGroup () { - return this.cacheApi.query.contentWorkingGroup; - } - - protected get minting () { - return this.cacheApi.query.minting; - } - - protected get hiring () { - return this.cacheApi.query.hiring; - } - - protected get stake () { - return this.cacheApi.query.stake; - } - - protected get recurringRewards () { - return this.cacheApi.query.recurringRewards; - } - - protected queryMethodByName (name: string) { - const [module, method] = name.split('.'); - return this.api.query[module][method]; - } - - // Fetch all double map entries using only the first key - // - // TODO: FIXME: This may be a risky implementation, because it relies on a few assumptions about how the data is stored etc. - // With the current runtime version we can rely on the fact that all storage keys for double-map values start with the same - // 32-bytes prefix assuming a given (fixed) value of the first key (ie. for all values like map[x][y], the storage key starts - // with the same prefix as long as x remains the same. Changing y will not affect this prefix) - protected async doubleMapEntries ( - methodName: string, - firstKey: Codec, - valueConverter: (hex: string) => T, - getEntriesCount: () => Promise, - secondKeyStart = 1 - ): Promise<{ secondKey: number; value: T}[]> { - // Get prefix and storage keys of all entries - const firstEntryStorageKey = this.queryMethodByName(methodName).key(firstKey, secondKeyStart); - const entryStorageKeyPrefix = firstEntryStorageKey.substr(0, 66); // "0x" + 64 hex characters (32 bytes) - const allEntriesStorageKeys = await this.api.rpc.state.getKeys(entryStorageKeyPrefix); - - // Create storageKey-to-secondKey map - const maxSecondKey = (await getEntriesCount()) - 1 + secondKeyStart; - const storageKeyToSecondKey: { [key: string]: number } = {}; - for (let secondKey = secondKeyStart; secondKey <= maxSecondKey; ++secondKey) { - const storageKey = this.queryMethodByName(methodName).key(firstKey, secondKey); - storageKeyToSecondKey[storageKey] = secondKey; - } - - // Create the resulting entries array - const entries: { secondKey: number; value: T }[] = []; - for (const key of allEntriesStorageKeys) { - const value: any = await this.api.rpc.state.getStorage(key); - if (typeof value === 'object' && value !== null && value.raw) { - entries.push({ - secondKey: storageKeyToSecondKey[key.toString()], - value: valueConverter(value.raw.toString()) - }); - } - } - - return entries; - } -} diff --git a/pioneer/packages/joy-utils-old/src/transport/index.ts b/pioneer/packages/joy-utils-old/src/transport/index.ts deleted file mode 100644 index a4296adc40..0000000000 --- a/pioneer/packages/joy-utils-old/src/transport/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ApiPromise } from '@polkadot/api'; -import ChainTransport from './chain'; -import ContentWorkingGroupTransport from './contentWorkingGroup'; -import ProposalsTransport from './proposals'; -import MembersTransport from './members'; -import CouncilTransport from './council'; -import ValidatorsTransport from './validators'; -import WorkingGroupsTransport from './workingGroups'; -import { APIQueryCache } from '../APIQueryCache'; - -export default class Transport { - protected api: ApiPromise; - protected cacheApi: APIQueryCache; - // Specific transports - public chain: ChainTransport; - public members: MembersTransport; - public council: CouncilTransport; - public proposals: ProposalsTransport; - public contentWorkingGroup: ContentWorkingGroupTransport; - public validators: ValidatorsTransport; - public workingGroups: WorkingGroupsTransport; - - constructor (api: ApiPromise) { - this.api = api; - this.cacheApi = new APIQueryCache(api); - this.chain = new ChainTransport(api, this.cacheApi); - this.members = new MembersTransport(api, this.cacheApi); - this.validators = new ValidatorsTransport(api, this.cacheApi); - this.council = new CouncilTransport(api, this.cacheApi, this.members, this.chain); - this.contentWorkingGroup = new ContentWorkingGroupTransport(api, this.cacheApi, this.members); - this.proposals = new ProposalsTransport(api, this.cacheApi, this.members, this.chain, this.council); - this.workingGroups = new WorkingGroupsTransport(api, this.cacheApi, this.members); - } -} diff --git a/pioneer/packages/joy-utils/src/react/components/InputStake.tsx b/pioneer/packages/joy-utils/src/react/components/InputStake.tsx new file mode 100644 index 0000000000..8e012fe42f --- /dev/null +++ b/pioneer/packages/joy-utils/src/react/components/InputStake.tsx @@ -0,0 +1,46 @@ +import BN from 'bn.js'; +import React from 'react'; +import { InputBalance } from '@polkadot/react-components/index'; +import { Label } from 'semantic-ui-react'; +import { formatBalance } from '@polkadot/util'; + +type Props = { + label?: string; + min?: BN; + isValid?: boolean; + onChange: (stake?: BN) => void; +}; + +export default class Component extends React.PureComponent { + render () { + const { min, label, isValid, onChange } = this.props; + return ( +
+ + {min && !min.isZero() && ( +
+ +
+ ) } +
+ ); + } +} diff --git a/pioneer/packages/joy-utils/src/react/components/MemberByAccountPreview.tsx b/pioneer/packages/joy-utils/src/react/components/MemberByAccountPreview.tsx new file mode 100644 index 0000000000..2fc8e28d83 --- /dev/null +++ b/pioneer/packages/joy-utils/src/react/components/MemberByAccountPreview.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +import ProfilePreview from './MemberProfilePreview'; +import { AccountId } from '@polkadot/types/interfaces'; +import { MemberFromAccount } from '../../types/members'; +import { useTransport, usePromise } from '../hooks'; + +import styled from 'styled-components'; +import PromiseComponent from './PromiseComponent'; + +const MemberByAccount = styled.div``; + +type Props = { + accountId: AccountId | string; +}; + +const MemberByAccountPreview: React.FunctionComponent = ({ accountId }) => { + const transport = useTransport(); + const [member, error, loading] = usePromise( + () => transport.members.membershipFromAccount(accountId), + null, + [accountId] + ); + + return ( + + + { member && ( + member.profile + ? + : 'Member profile not found!' + ) } + + + ); +}; + +export default MemberByAccountPreview; diff --git a/pioneer/packages/joy-utils-old/src/MemberProfilePreview.tsx b/pioneer/packages/joy-utils/src/react/components/MemberProfilePreview.tsx similarity index 100% rename from pioneer/packages/joy-utils-old/src/MemberProfilePreview.tsx rename to pioneer/packages/joy-utils/src/react/components/MemberProfilePreview.tsx diff --git a/pioneer/packages/joy-utils-old/src/MembersDropdown.tsx b/pioneer/packages/joy-utils/src/react/components/MembersDropdown.tsx similarity index 82% rename from pioneer/packages/joy-utils-old/src/MembersDropdown.tsx rename to pioneer/packages/joy-utils/src/react/components/MembersDropdown.tsx index a547bbd406..accada8040 100644 --- a/pioneer/packages/joy-utils-old/src/MembersDropdown.tsx +++ b/pioneer/packages/joy-utils/src/react/components/MembersDropdown.tsx @@ -1,9 +1,9 @@ -import React, { useEffect, useState, useContext } from 'react'; +import React, { useEffect, useState } from 'react'; import { Dropdown, DropdownItemProps, DropdownProps } from 'semantic-ui-react'; import { Membership } from '@joystream/types/members'; -import { memberFromAccount, MemberFromAccount } from './accounts'; +import { MemberFromAccount } from '../../types/members'; +import { useTransport } from '../hooks'; import { AccountId } from '@polkadot/types/interfaces'; -import { ApiContext } from '@polkadot/react-api'; import styled from 'styled-components'; const StyledMembersDropdown = styled(Dropdown)` @@ -16,9 +16,9 @@ const StyledMembersDropdown = styled(Dropdown)` function membersToOptions (members: MemberFromAccount[]) { const validMembers = members.filter(m => m.profile !== undefined) as (MemberFromAccount & { profile: Membership })[]; return validMembers - .map(({ id, profile, account }) => ({ + .map(({ memberId, profile, account }) => ({ key: profile.handle, - text: `${profile.handle} (id:${id})`, + text: `${profile.handle} (id:${memberId})`, value: account, image: profile.avatar_uri.toString() ? { avatar: true, src: profile.avatar_uri } : null })); @@ -33,7 +33,7 @@ type Props = { }; const MembersDropdown: React.FunctionComponent = ({ accounts, ...passedProps }) => { - const { api } = useContext(ApiContext); + const transport = useTransport(); // State const [loading, setLoading] = useState(true); const [membersOptions, setMembersOptions] = useState([] as DropdownItemProps[]); @@ -41,7 +41,7 @@ const MembersDropdown: React.FunctionComponent = ({ accounts, ...passedPr useEffect(() => { let isSubscribed = true; Promise - .all(accounts.map(acc => memberFromAccount(api, acc))) + .all(accounts.map(acc => transport.members.membershipFromAccount(acc))) .then(members => { if (isSubscribed) { setMembersOptions(membersToOptions(members)); diff --git a/pioneer/packages/joy-utils-old/src/react/components/PromiseComponent.tsx b/pioneer/packages/joy-utils/src/react/components/PromiseComponent.tsx similarity index 100% rename from pioneer/packages/joy-utils-old/src/react/components/PromiseComponent.tsx rename to pioneer/packages/joy-utils/src/react/components/PromiseComponent.tsx diff --git a/pioneer/packages/joy-utils/src/react/context/index.tsx b/pioneer/packages/joy-utils/src/react/context/index.tsx index 7f1069a262..b3cfe458cc 100644 --- a/pioneer/packages/joy-utils/src/react/context/index.tsx +++ b/pioneer/packages/joy-utils/src/react/context/index.tsx @@ -1,2 +1,3 @@ export { MyAccountContext, MyAccountProvider } from './account'; export { MyMembershipContext, MyMembershipProvider } from './membership'; +export { TransportContext, TransportProvider } from './transport'; diff --git a/pioneer/packages/joy-utils-old/src/react/context/transport.tsx b/pioneer/packages/joy-utils/src/react/context/transport.tsx similarity index 100% rename from pioneer/packages/joy-utils-old/src/react/context/transport.tsx rename to pioneer/packages/joy-utils/src/react/context/transport.tsx diff --git a/pioneer/packages/joy-utils/src/react/hooks/index.ts b/pioneer/packages/joy-utils/src/react/hooks/index.ts index f95a7d97e0..fdea80a3df 100644 --- a/pioneer/packages/joy-utils/src/react/hooks/index.ts +++ b/pioneer/packages/joy-utils/src/react/hooks/index.ts @@ -1,2 +1,4 @@ export { default as useMyAccount } from './useMyAccount'; export { default as useMyMembership } from './useMyMembership'; +export { default as usePromise } from './usePromise'; +export { default as useTransport } from './useTransport'; diff --git a/pioneer/packages/joy-utils-old/src/react/hooks/usePromise.tsx b/pioneer/packages/joy-utils/src/react/hooks/usePromise.tsx similarity index 100% rename from pioneer/packages/joy-utils-old/src/react/hooks/usePromise.tsx rename to pioneer/packages/joy-utils/src/react/hooks/usePromise.tsx diff --git a/pioneer/packages/joy-utils-old/src/react/hooks/useTransport.tsx b/pioneer/packages/joy-utils/src/react/hooks/useTransport.tsx similarity index 100% rename from pioneer/packages/joy-utils-old/src/react/hooks/useTransport.tsx rename to pioneer/packages/joy-utils/src/react/hooks/useTransport.tsx diff --git a/pioneer/packages/joy-utils-old/src/APIQueryCache.ts b/pioneer/packages/joy-utils/src/transport/APIQueryCache.ts similarity index 100% rename from pioneer/packages/joy-utils-old/src/APIQueryCache.ts rename to pioneer/packages/joy-utils/src/transport/APIQueryCache.ts diff --git a/pioneer/packages/joy-utils/src/transport/base.ts b/pioneer/packages/joy-utils/src/transport/base.ts new file mode 100644 index 0000000000..b8a1433d1b --- /dev/null +++ b/pioneer/packages/joy-utils/src/transport/base.ts @@ -0,0 +1,66 @@ +import { ApiPromise } from '@polkadot/api'; +import { Codec } from '@polkadot/types/types'; +import { APIQueryCache } from './APIQueryCache'; + +export default abstract class BaseTransport { + protected api: ApiPromise; + protected cacheApi: APIQueryCache; + + constructor (api: ApiPromise, cacheApi: APIQueryCache) { + this.api = api; + this.cacheApi = cacheApi; + } + + protected get proposalsEngine () { + return this.cacheApi.query.proposalsEngine; + } + + protected get proposalsCodex () { + return this.cacheApi.query.proposalsCodex; + } + + protected get proposalsDiscussion () { + return this.cacheApi.query.proposalsDiscussion; + } + + protected get members () { + return this.cacheApi.query.members; + } + + protected get council () { + return this.cacheApi.query.council; + } + + protected get councilElection () { + return this.cacheApi.query.councilElection; + } + + protected get actors () { + return this.cacheApi.query.actors; + } + + protected get contentWorkingGroup () { + return this.cacheApi.query.contentWorkingGroup; + } + + protected get minting () { + return this.cacheApi.query.minting; + } + + protected get hiring () { + return this.cacheApi.query.hiring; + } + + protected get stake () { + return this.cacheApi.query.stake; + } + + protected get recurringRewards () { + return this.cacheApi.query.recurringRewards; + } + + protected queryMethodByName (name: string) { + const [module, method] = name.split('.'); + return this.api.query[module][method]; + } +} diff --git a/pioneer/packages/joy-utils/src/transport/index.ts b/pioneer/packages/joy-utils/src/transport/index.ts new file mode 100644 index 0000000000..3060094ec0 --- /dev/null +++ b/pioneer/packages/joy-utils/src/transport/index.ts @@ -0,0 +1,34 @@ +import { ApiPromise } from '@polkadot/api'; +// import ChainTransport from './chain'; +// import ContentWorkingGroupTransport from './contentWorkingGroup'; +// import ProposalsTransport from './proposals'; +import MembersTransport from './members'; +// import CouncilTransport from './council'; +// import ValidatorsTransport from './validators'; +// import WorkingGroupsTransport from './workingGroups'; +import { APIQueryCache } from './APIQueryCache'; + +export default class Transport { + protected api: ApiPromise; + protected cacheApi: APIQueryCache; + // Specific transports + // public chain: ChainTransport; + public members: MembersTransport; + // public council: CouncilTransport; + // public proposals: ProposalsTransport; + // public contentWorkingGroup: ContentWorkingGroupTransport; + // public validators: ValidatorsTransport; + // public workingGroups: WorkingGroupsTransport; + + constructor (api: ApiPromise) { + this.api = api; + this.cacheApi = new APIQueryCache(api); + // this.chain = new ChainTransport(api, this.cacheApi); + this.members = new MembersTransport(api, this.cacheApi); + // this.validators = new ValidatorsTransport(api, this.cacheApi); + // this.council = new CouncilTransport(api, this.cacheApi, this.members, this.chain); + // this.contentWorkingGroup = new ContentWorkingGroupTransport(api, this.cacheApi, this.members); + // this.proposals = new ProposalsTransport(api, this.cacheApi, this.members, this.chain, this.council); + // this.workingGroups = new WorkingGroupsTransport(api, this.cacheApi, this.members); + } +} diff --git a/pioneer/packages/joy-utils-old/src/transport/members.ts b/pioneer/packages/joy-utils/src/transport/members.ts similarity index 53% rename from pioneer/packages/joy-utils-old/src/transport/members.ts rename to pioneer/packages/joy-utils/src/transport/members.ts index 8263d87d59..5a90bf74df 100644 --- a/pioneer/packages/joy-utils-old/src/transport/members.ts +++ b/pioneer/packages/joy-utils/src/transport/members.ts @@ -1,5 +1,8 @@ import BaseTransport from './base'; import { MemberId, Membership } from '@joystream/types/members'; +import { Vec } from '@polkadot/types/codec'; +import { AccountId } from '@polkadot/types/interfaces'; +import { MemberFromAccount } from '../types/members'; export default class MembersTransport extends BaseTransport { async membershipById (id: MemberId | number): Promise { @@ -21,4 +24,17 @@ export default class MembersTransport extends BaseTransport { async nextMemberId (): Promise { return (await this.members.nextMemberId() as MemberId).toNumber(); } + + async membershipFromAccount (accountId: AccountId | string): Promise { + const memberIdsRoot = (await this.members.memberIdsByRootAccountId(accountId)) as Vec; + const memberIdsController = (await this.members.memberIdsByControllerAccountId(accountId)) as Vec; + const memberId: MemberId | undefined = memberIdsRoot.toArray().concat(memberIdsController.toArray())[0]; + const profile = memberId ? await this.expectedMembership(memberId) : undefined; + + return { + account: accountId.toString(), + memberId: memberId && memberId.toNumber(), + profile, + }; + } } diff --git a/pioneer/packages/joy-utils-old/src/types/members.ts b/pioneer/packages/joy-utils/src/types/members.ts similarity index 64% rename from pioneer/packages/joy-utils-old/src/types/members.ts rename to pioneer/packages/joy-utils/src/types/members.ts index 76f5882de1..1528222ebe 100644 --- a/pioneer/packages/joy-utils-old/src/types/members.ts +++ b/pioneer/packages/joy-utils/src/types/members.ts @@ -1,3 +1,5 @@ +import { Membership } from '@joystream/types/members'; + export type ParsedMember = { about: string; avatar_uri: string; @@ -10,3 +12,5 @@ export type ParsedMember = { subscription: any; suspended: boolean; }; + +export type MemberFromAccount = { account: string; memberId?: number; profile?: Membership }; diff --git a/pioneer/packages/old-apps/apps-routing/src/joy-election.ts b/pioneer/packages/old-apps/apps-routing/src/joy-election.ts deleted file mode 100644 index 2f88963545..0000000000 --- a/pioneer/packages/old-apps/apps-routing/src/joy-election.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Routes } from './types'; - -import Election from '@polkadot/joy-election/index'; - -export const councilSidebarName = 'council'; - -export default [ - { - Component: Election, - display: { - needsApi: ['query.council.activeCouncil', 'query.councilElection.stage'] - }, - i18n: { - defaultValue: 'Council' - }, - icon: 'university', - name: councilSidebarName - } -] as Routes; diff --git a/pioneer/packages/react-components/src/styles/joystream.ts b/pioneer/packages/react-components/src/styles/joystream.ts index 4e5054789e..8f79fa4993 100644 --- a/pioneer/packages/react-components/src/styles/joystream.ts +++ b/pioneer/packages/react-components/src/styles/joystream.ts @@ -31,60 +31,6 @@ export default css` } } - .ui--AddressMini { - .ui--IdentityIcon { - margin-left: 0; - } - .ui--AddressMini-info { - display: block; - } - .ui--AddressMini-details { - display: block; - text-align: left; - } - .ui--AddressSummary-name, - .ui--AddressSummary-balance, - .ui--AddressSummary-memo { - display: inline-block; - margin-top: 0; - padding-top: 0; - font-size: 0.8rem !important; - margin-right: 1rem; - font-weight: 100; - opacity: 0.8; - overflow: hidden; - } - } - - .ui--Bubble.ui.label { - background-color: #f2f2f2; - margin: 0.25rem 0; - margin-right: 0.5rem; - - &.pointing:before { - background-color: #e6e6e6; - } - &.warn { - color: #f2711c !important; - border: 1px solid; - } - &.ok { - color: #21ba45 !important; - border: 1px solid; - } - } - - .SidebarItem { - display: inline-flex; - flex-direction: column; - - .SidebarSubtitle { - display: block; - font-size: 0.85rem; - color: grey; - } - } - .JoySection { margin: 2rem 0; @@ -185,19 +131,50 @@ export default css` color: #3b83c0; } - /* Overrides */ + /* Remove IdentityIcon border (not working well for members list) */ .ui--IdentityIcon { border: none !important; } - /* Normalize SideBar icons width */ - .apps--SideBar-Item-NavLink svg { - width: 20px !important; + + .apps--SideBar-Item-NavLink { + /* Normalize SideBar icons width */ + svg { + width: 20px !important; + } + /* Display SideBar subtitle below title */ + .text { + display: inline-flex; + flex-direction: column; + } } + /* Fix "collapsed" sidebar on mobile */ .apps--Wrapper:not(.menu-open) .apps--SideBar-Scroll { padding: 0 !important; } + + /* Turn off global text-transform on h1 */ h1 { text-transform: none; } + + /* AddressMini customization */ + .ui--AddressMini { + display: grid; + grid-template-rows: auto auto; + grid-template-columns: min-content min-content; + .ui--AddressMini-icon { + grid-row: 1/3; + grid-column: 2/3; + align-self: center; + } + .ui--AddressMini-balances .ui--FormatBalance { + font-size: 1rem !important; + margin: 0 !important; + } + .ui--AddressMini-info { + min-width: 10em; + max-width: 10em; + } + } `; diff --git a/pioneer/tsconfig.json b/pioneer/tsconfig.json index 2226b26297..d884cad8f0 100644 --- a/pioneer/tsconfig.json +++ b/pioneer/tsconfig.json @@ -4,7 +4,6 @@ "build/**/*", "**/build/**/*", "packages/old-apps/**", - "packages/joy-election/**/*", "packages/joy-forum/**/*", "packages/joy-help/**/*", "packages/joy-media/**/*", @@ -23,8 +22,8 @@ "@polkadot/types/augment": [ "../types/src/definitions/augment-types.ts" ], // "@joystream/types/": [ "../types/src/" ], // "@joystream/types/*": [ "../types/src/*" ], - // "@polkadot/joy-election/": [ "packages/joy-election/src/" ], - // "@polkadot/joy-election/*": [ "packages/joy-election/src/*" ], + "@polkadot/joy-election/": [ "packages/joy-election/src/" ], + "@polkadot/joy-election/*": [ "packages/joy-election/src/*" ], // "@polkadot/joy-forum/": [ "packages/joy-forum/src/" ], // "@polkadot/joy-forum/*": [ "packages/joy-forum/src/*" ], // "@polkadot/joy-help/": [ "packages/joy-help/src/" ], From ea98e5dd637fd54e4b096e8e1d8554a50ea287b1 Mon Sep 17 00:00:00 2001 From: Leszek Wiesner Date: Fri, 14 Aug 2020 11:24:10 +0200 Subject: [PATCH 08/15] Linter autofix --- .../packages/apps-routing/src/joy-election.ts | 2 +- .../packages/joy-election/src/ApplyForm.tsx | 1 + pioneer/packages/joy-election/src/Council.tsx | 3 ++- .../packages/joy-election/src/Dashboard.tsx | 17 ++++++++++------- pioneer/packages/joy-election/src/Reveals.tsx | 2 ++ .../packages/joy-election/src/SealedVote.tsx | 13 +++++++------ .../packages/joy-election/src/SealedVotes.tsx | 18 ++++++++++-------- .../joy-election/src/SidebarSubtitle.tsx | 3 ++- pioneer/packages/joy-election/src/VoteForm.tsx | 9 +++++++-- pioneer/packages/joy-election/src/Votes.tsx | 4 ++-- pioneer/packages/joy-election/src/index.tsx | 2 ++ .../packages/joy-election/src/myVotesStore.ts | 12 ++++++++---- pioneer/packages/joy-election/src/utils.tsx | 9 +++++++-- .../src/react/components/InputStake.tsx | 3 ++- .../components/MemberByAccountPreview.tsx | 2 +- .../react/components/MemberProfilePreview.tsx | 5 +++-- .../src/react/components/MembersDropdown.tsx | 10 +++++++--- .../src/react/components/PromiseComponent.tsx | 2 ++ .../joy-utils/src/react/hooks/usePromise.tsx | 9 +++++++-- .../joy-utils/src/transport/APIQueryCache.ts | 10 ++++++++-- .../packages/joy-utils/src/transport/base.ts | 1 + .../joy-utils/src/transport/members.ts | 4 +++- 22 files changed, 95 insertions(+), 46 deletions(-) diff --git a/pioneer/packages/apps-routing/src/joy-election.ts b/pioneer/packages/apps-routing/src/joy-election.ts index ebf857ad81..cbff554d99 100644 --- a/pioneer/packages/apps-routing/src/joy-election.ts +++ b/pioneer/packages/apps-routing/src/joy-election.ts @@ -13,5 +13,5 @@ export default function create (t: (key: string, text: string, opti icon: 'university', name: 'council', SubtitleComponent: SidebarSubtitle - } + }; } diff --git a/pioneer/packages/joy-election/src/ApplyForm.tsx b/pioneer/packages/joy-election/src/ApplyForm.tsx index f0f753f37c..5685d3371b 100644 --- a/pioneer/packages/joy-election/src/ApplyForm.tsx +++ b/pioneer/packages/joy-election/src/ApplyForm.tsx @@ -75,6 +75,7 @@ class ApplyForm extends React.PureComponent { stake = stake || ZERO; const isStakeGteMinStake = stake.add(this.alreadyStaked()).gte(this.minStake()); const isStakeValid = !stake.isZero() && isStakeGteMinStake; + this.setState({ stake, isStakeValid }); } } diff --git a/pioneer/packages/joy-election/src/Council.tsx b/pioneer/packages/joy-election/src/Council.tsx index 72f4ff5ea8..6ad36df3f5 100644 --- a/pioneer/packages/joy-election/src/Council.tsx +++ b/pioneer/packages/joy-election/src/Council.tsx @@ -53,9 +53,10 @@ class Council extends React.PureComponent { render () { const { council = [] } = this.props; + // console.log({ council }); return ( -
+
{!council.length ? Council is not elected yet : this.renderTable(council)}
); diff --git a/pioneer/packages/joy-election/src/Dashboard.tsx b/pioneer/packages/joy-election/src/Dashboard.tsx index b962c1e5aa..f115cc1917 100644 --- a/pioneer/packages/joy-election/src/Dashboard.tsx +++ b/pioneer/packages/joy-election/src/Dashboard.tsx @@ -45,13 +45,13 @@ class Dashboard extends React.PureComponent { const title = `Council ${activeCouncil.length > 0 ? '' : '(not elected)'}`; return
- + @@ -64,13 +64,16 @@ class Dashboard extends React.PureComponent { let stageName: string | undefined; let stageEndsAt: BlockNumber | undefined; + if (stage && stage.isSome) { const stageValue = stage.value as ElectionStage; + stageEndsAt = stageValue.value as BlockNumber; // contained value stageName = stageValue.type; // name of Enum variant } let leftBlocks: BN | undefined; + if (stageEndsAt && bestNumber) { leftBlocks = stageEndsAt.sub(bestNumber); } @@ -81,9 +84,9 @@ class Dashboard extends React.PureComponent { const title = <>Election ({stateText}); return
- + @@ -97,7 +100,7 @@ class Dashboard extends React.PureComponent { {formatNumber(leftBlocks)} @@ -111,7 +114,7 @@ class Dashboard extends React.PureComponent { const isAutoStart = (p.autoStart || false).valueOf(); return
- + - +