diff --git a/package.json b/package.json index 6a05398d80..ee24adaf31 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,9 @@ "pioneer/packages/apps*", "pioneer/packages/page*", "pioneer/packages/react*", + "pioneer/packages/joy-utils", + "pioneer/packages/joy-members", + "pioneer/packages/joy-pages", "utils/api-examples" ], "resolutions": { 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/.eslintrc.js b/pioneer/.eslintrc.js index ada8259c1e..a909f51bfc 100644 --- a/pioneer/.eslintrc.js +++ b/pioneer/.eslintrc.js @@ -13,14 +13,20 @@ module.exports = { rules: { ...base.rules, '@typescript-eslint/no-explicit-any': 'off', - 'react/prop-types': 'off', 'new-cap': 'off', '@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/ban-ts-comment': 'error', // why only required in VSCode!?!? is eslint plugin not working like eslint commandline? // Or are we having to add this because of new versions of eslint-config-* ? 'no-console': 'off', - 'header/header': 'off' // Temporary disable polkadot's rule + // Override some extended config rules: + 'camelcase': 'off', + 'header/header': 'off', + 'sort-keys': 'off', + 'react/jsx-sort-props': 'off', + 'react/jsx-max-props-per-line': 'off', + 'sort-destructure-keys/sort-destructure-keys': 'off', + '@typescript-eslint/unbound-method': 'warn', // Doesn't work well with our version of Formik, see: https://github.com/formium/formik/issues/2589 }, // isolate pioneer from monorepo eslint rules root: true 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 100755 index 0000000000..67dd1b71f2 --- /dev/null +++ b/pioneer/packages/apps-config/src/ui/logos/nodes/joystream-node.svg @@ -0,0 +1 @@ +Icon-mono-white-1bg-blue \ No newline at end of file diff --git a/pioneer/packages/apps-routing/src/index.ts b/pioneer/packages/apps-routing/src/index.ts index cc5eab5943..47899c3931 100644 --- a/pioneer/packages/apps-routing/src/index.ts +++ b/pioneer/packages/apps-routing/src/index.ts @@ -9,69 +9,49 @@ 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, + members(t), staking(t), - democracy(t), - council(t), - // TODO Not sure about the inclusion of treasury, parachains & society here null, - settings(t) + transfer(t), + accounts(t), + settings(t), + // Those are hidden + terms(t), + privacyPolicy(t) ] : [ - // dashboard(t), - explorer(t), - accounts(t), - claims(t), - poll(t), - transfer(t), - genericAsset(t), - null, + members(t), staking(t), - democracy(t), - council(t), - treasury(t), - techcomm(t), - parachains(t), - society(t), null, - contracts(t), + transfer(t), + accounts(t), + settings(t), + null, + 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/public/favicon.ico b/pioneer/packages/apps/public/favicon.ico index ec3c167a5b..a3d783d522 100644 Binary files a/pioneer/packages/apps/public/favicon.ico and b/pioneer/packages/apps/public/favicon.ico differ 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/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/NotFound.tsx b/pioneer/packages/apps/src/Content/NotFound.tsx index f3addbaa45..f2c58785c9 100644 --- a/pioneer/packages/apps/src/Content/NotFound.tsx +++ b/pioneer/packages/apps/src/Content/NotFound.tsx @@ -7,7 +7,7 @@ import { Redirect } from 'react-router'; function NotFound (): React.ReactElement { return ( - + ); } 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..807141b73c --- /dev/null +++ b/pioneer/packages/apps/src/JoyTopBar/TopBar.tsx @@ -0,0 +1,56 @@ +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'; + +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 () { + 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/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/apps/webpack.config.js b/pioneer/packages/apps/webpack.config.js index f31f22bbe1..041f8f8356 100644 --- a/pioneer/packages/apps/webpack.config.js +++ b/pioneer/packages/apps/webpack.config.js @@ -20,7 +20,8 @@ module.exports = merge( devtool: process.env.BUILD_ANALYZE ? 'source-map' : false, plugins: [ new HtmlWebpackPlugin({ - PAGE_TITLE: 'Polkadot/Substrate Portal', + IS_PROD: ENV === 'production', + PAGE_TITLE: 'Joystream Network Portal', inject: true, template: path.join(context, `${hasPublic ? 'public/' : ''}index.html`) }) 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..fa2375c690 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; @@ -28,6 +28,7 @@ type Props = ApiProps & I18nProps & MyAccountProps & { class Component extends React.PureComponent { render () { const { membership } = this.props; + return membership && !membership.handle.isEmpty ? this.renderProfile(membership) : ( @@ -54,34 +55,34 @@ class Component extends React.PureComponent { const hasAvatar = avatar_uri && nonEmptyStr(avatar_uri.toString()); const isMyProfile = myAddress && (myAddress === root_account.toString() || myAddress === controller_account.toString()); const isCouncilor: boolean = ( - (activeCouncil.find(x => root_account.eq(x.member)) !== undefined) || - (activeCouncil.find(x => controller_account.eq(x.member)) !== undefined) + (activeCouncil.find((x) => root_account.eq(x.member)) !== undefined) || + (activeCouncil.find((x) => controller_account.eq(x.member)) !== undefined) ); return ( <> -
- {hasAvatar - ? - : - } -
-
- {handle.toString()} - {isMyProfile && Edit my profile} -
-
- {isCouncilor && - +
+ {hasAvatar + ? + : + } +
+
+ {handle.toString()} + {isMyProfile && Edit my profile} +
+
+ {isCouncilor && + Council member } - -
MemberId: {this.props.memberId.toString()}
+ +
MemberId: {this.props.memberId.toString()}
+
-
- {!preview && this.renderDetails(membership, isCouncilor)} + {!preview && this.renderDetails(membership, isCouncilor)} ); } @@ -147,11 +148,14 @@ class Component extends React.PureComponent { private renderEntryMethod (entry: EntryMethod) { const etype = entry.type; + if (etype === Paid.name) { const paid = entry.value as Paid; + return
Paid, terms ID: {paid.toNumber()}
; } else if (etype === Screening.name) { const accountId = entry.value as Screening; + return
Screened by
; } else if (etype === Genesis.name) { return
Created at Genesis
; 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..9d0c229173 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,12 +78,15 @@ const InnerForm = (props: FormProps) => { memberId } = props; + const { api } = useContext(ApiContext); + const onSubmit = (sendTx: () => void) => { if (isValid) sendTx(); }; const onTxFailed: TxFailedCallback = (txResult: SubmittableResult | null) => { setSubmitting(false); + if (txResult == null) { // Tx cancelled. @@ -102,7 +104,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 = () => { @@ -126,29 +130,29 @@ const InnerForm = (props: FormProps) => { // TODO show warning that you don't have enough balance to buy a membership return ( -
-
+
+ - + {!profile && paidTerms && ( @@ -165,24 +169,26 @@ const InnerForm = (props: FormProps) => { )} - -
@@ -191,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() : '', @@ -202,7 +209,7 @@ const EditForm = withFormik({ validationSchema: buildSchema, - handleSubmit: values => { + handleSubmit: (values) => { // do submitting things } })(InnerForm); @@ -220,6 +227,7 @@ type WithMembershipDataProps = { function WithMembershipDataInner (p: WithMembershipDataProps) { const triedToFindProfile = !p.memberId || p.membership; + if ( triedToFindProfile && p.paidTerms && @@ -228,7 +236,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'); @@ -267,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
@@ -280,9 +290,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..e82d92ef46 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; @@ -22,7 +23,7 @@ type Props = ApiProps & I18nProps & RouteComponentProps & { match: { params: { page?: string } }; }; -type State = {}; +type State = Record; const MEMBERS_PER_PAGE = 20; @@ -31,7 +32,8 @@ 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) { @@ -55,7 +57,8 @@ class Component extends React.PureComponent { const { firstMemberId, membersCreated, - match: { params: { page } } + match: { params: { page } }, + api } = this.props; const membersCount = membersCreated.toNumber(); @@ -67,11 +70,13 @@ 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(new MemberId(i)); + ids.push(api.createType('MemberId', i)); } } @@ -95,4 +100,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..7af4e59633 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; @@ -33,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; @@ -43,19 +43,19 @@ 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; - return
+ return
{prefixLabel && {prefixLabel} } {hasAvatar ? ( - + ) : ( - + ) }
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..15613c0f8e 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; @@ -32,8 +36,8 @@ class App extends React.PureComponent { return [ { name: 'list', - text: t('All members') + ` (${memberCount})`, - forcedExact: false + text: t('All members') + ` (${memberCount?.toString() || '-'})`, + forceMatchParams: true }, { name: 'edit', @@ -48,6 +52,7 @@ class App extends React.PureComponent { private renderList (routeProps: RouteComponentProps) { const { nextMemberId, ...otherProps } = this.props; + return nextMemberId ? : Loading...; @@ -58,18 +63,18 @@ class App extends React.PureComponent { const tabs = this.buildTabs(); return ( -
+
- this.renderList(props) } /> + this.renderList(props) } /> - this.renderList(props) } /> + 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-pages/src/index.tsx b/pioneer/packages/joy-pages/src/index.tsx index f55100e9e8..189dc921f3 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 ; + return ; } + export function Privacy () { - return ; + return ; } 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 89% rename from pioneer/packages/joy-utils-old/src/functions/format.ts rename to pioneer/packages/joy-utils/src/functions/format.ts index 199032140b..8e776a6e5d 100644 --- a/pioneer/packages/joy-utils-old/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 new file mode 100644 index 0000000000..5f9deaf90e --- /dev/null +++ b/pioneer/packages/joy-utils/src/functions/misc.ts @@ -0,0 +1,167 @@ +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 as string).trim().length === 0); + +export const nonEmptyStr = (x?: any) => + isStr(x) && (x as string).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 56% rename from pioneer/packages/joy-utils-old/src/FlexCenter.tsx rename to pioneer/packages/joy-utils/src/react/components/FlexCenter.tsx index da77d6182b..95a85ea343 100644 --- a/pioneer/packages/joy-utils-old/src/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-old/src/MutedText.tsx b/pioneer/packages/joy-utils/src/react/components/MutedText.tsx similarity index 88% rename from pioneer/packages/joy-utils-old/src/MutedText.tsx rename to pioneer/packages/joy-utils/src/react/components/MutedText.tsx index a981133680..f776a7021e 100644 --- a/pioneer/packages/joy-utils-old/src/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}`; + + 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-old/src/Section.tsx b/pioneer/packages/joy-utils/src/react/components/Section.tsx similarity index 99% rename from pioneer/packages/joy-utils-old/src/Section.tsx rename to pioneer/packages/joy-utils/src/react/components/Section.tsx index 09d85b29bd..f9b0d61546 100644 --- a/pioneer/packages/joy-utils-old/src/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-old/src/TxButton.tsx b/pioneer/packages/joy-utils/src/react/components/TxButton.tsx similarity index 59% rename from pioneer/packages/joy-utils-old/src/TxButton.tsx rename to pioneer/packages/joy-utils/src/react/components/TxButton.tsx index f1e6d6b0db..73eb3b3bbe 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 = 'check', onClick } = this.props; const origin = accountId || myAddress; return (
; }; + return LabelledFieldInner; } diff --git a/pioneer/packages/joy-utils/src/react/components/index.tsx b/pioneer/packages/joy-utils/src/react/components/index.tsx new file mode 100644 index 0000000000..0ead2f86e7 --- /dev/null +++ b/pioneer/packages/joy-utils/src/react/components/index.tsx @@ -0,0 +1,4 @@ +export { default as Section } from './Section'; +export { default as TxButton } from './TxButton'; +export { MutedSpan, MutedDiv } from './MutedText'; +export { FlexCenter } from './FlexCenter'; diff --git a/pioneer/packages/joy-utils-old/src/MyAccountContext.tsx b/pioneer/packages/joy-utils/src/react/context/account.tsx similarity index 77% rename from pioneer/packages/joy-utils-old/src/MyAccountContext.tsx rename to pioneer/packages/joy-utils/src/react/context/account.tsx index ebb1baee20..b3fe56fb48 100644 --- a/pioneer/packages/joy-utils-old/src/MyAccountContext.tsx +++ b/pioneer/packages/joy-utils/src/react/context/account.tsx @@ -1,11 +1,14 @@ -import React, { useReducer, createContext, useContext, useEffect } from 'react'; +import React, { useReducer, createContext, useEffect } from 'react'; import store from 'store'; -export const MY_ADDRESS = 'joy.myAddress'; +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); + const myAddress = store.get(MY_ADDRESS_STORAGE_KEY) as string | undefined; + console.log('Read my address from the local storage:', myAddress); + return myAddress; } @@ -22,7 +25,8 @@ type MyAccountAction = { function reducer (state: MyAccountState, action: MyAccountAction): MyAccountState { function forget () { console.log('Forget my address'); - store.remove(MY_ADDRESS); + store.remove(MY_ADDRESS_STORAGE_KEY); + return { ...state, address: undefined }; } @@ -32,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, 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; } @@ -88,9 +98,23 @@ 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) => { + 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) { dispatch({ type: 'reload' }); @@ -110,7 +134,3 @@ export function MyAccountProvider (props: React.PropsWithChildren<{}>) { ); } - -export function useMyAccount () { - return useContext(MyAccountContext); -} diff --git a/pioneer/packages/joy-utils/src/react/context/index.tsx b/pioneer/packages/joy-utils/src/react/context/index.tsx new file mode 100644 index 0000000000..7f1069a262 --- /dev/null +++ b/pioneer/packages/joy-utils/src/react/context/index.tsx @@ -0,0 +1,2 @@ +export { MyAccountContext, MyAccountProvider } from './account'; +export { MyMembershipContext, MyMembershipProvider } from './membership'; diff --git a/pioneer/packages/joy-utils-old/src/MyMembershipContext.tsx b/pioneer/packages/joy-utils/src/react/context/membership.tsx similarity index 64% rename from pioneer/packages/joy-utils-old/src/MyMembershipContext.tsx rename to pioneer/packages/joy-utils/src/react/context/membership.tsx index bc6d7977ef..ecc737c257 100644 --- a/pioneer/packages/joy-utils-old/src/MyMembershipContext.tsx +++ b/pioneer/packages/joy-utils/src/react/context/membership.tsx @@ -1,5 +1,5 @@ -import React, { createContext, useContext } from 'react'; -import { MyAccountProps, withMyAccount } from './MyAccount'; +import React, { createContext } from 'react'; +import { MyAccountProps, withMyAccount } from '../hocs/accounts'; export const MyMembershipContext = createContext({}); @@ -12,7 +12,3 @@ function InnerMyMembershipProvider (props: React.PropsWithChildren; + memberIdsByControllerAccountId?: Vec; + myMemberIdChecked?: boolean; + iAmMember?: boolean; + myMembership?: Membership | null; + + // Content Working Group + curatorEntries?: any; // entire linked_map: CuratorId => Curator + isLeadSet?: Option; + contentLeadId?: LeadId; + contentLeadEntry?: any; // linked_map value + + curationActor?: any; + allAccounts?: SubjectInfo; +}; + +function withMyAddress

(Component: React.ComponentType

) { + const ResultComponent: React.FunctionComponent

= (props: P) => { + const { + state: { address } + } = useMyAccount(); + const { api } = useContext(ApiContext); + const myAccountId = (address && api.isReady) + ? api.createType('AccountId', address) + : undefined; + + return ; + }; + + ResultComponent.displayName = `withMyAddress(${componentName(Component)})`; + + return ResultComponent; +} + +const withMyMemberIds = withCalls( + queryMembershipToProp('memberIdsByRootAccountId', 'myAddress'), + queryMembershipToProp('memberIdsByControllerAccountId', 'myAddress') +); + +function withMyMembership

(Component: React.ComponentType

) { + const ResultComponent: React.FunctionComponent

= (props: P) => { + const { memberIdsByRootAccountId, memberIdsByControllerAccountId } = props; + + const myMemberIdChecked = memberIdsByRootAccountId && memberIdsByControllerAccountId; + + let myMemberId: MemberId | undefined; + + if (memberIdsByRootAccountId && memberIdsByControllerAccountId) { + const [memberIdByAccount] = memberIdsByRootAccountId.toArray().concat(memberIdsByControllerAccountId.toArray()); + + myMemberId = memberIdByAccount; + } + + const iAmMember = myMemberId !== undefined; + + const newProps = { + myMemberIdChecked, + myMemberId, + iAmMember + }; + + 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; +} + +const withMyProfileCall = withCalls(queryMembershipToProp('membershipById', { + paramName: 'myMemberId', + propName: 'myMembership' +})); + +const withMyProfile =

(Component: React.ComponentType

) => + withMulti(Component, withMyProfileCall, resolveMyProfile); + +export const withMyAccount =

(Component: React.ComponentType

) => + withMulti( + Component, + withObservable(accountObservable.subject, { propName: 'allAccounts' }), + withMyAddress, + withMyMemberIds, + withMyMembership, + 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 new file mode 100644 index 0000000000..399052167f --- /dev/null +++ b/pioneer/packages/joy-utils/src/react/hocs/guards.tsx @@ -0,0 +1,104 @@ +import React from 'react'; +import { Message } from 'semantic-ui-react'; +import { Link } from 'react-router-dom'; + +import { AccountId } from '@polkadot/types/interfaces'; +import { Vec, Option } from '@polkadot/types'; +import { withMulti } from '@polkadot/react-api/index'; +import { SubjectInfo } from '@polkadot/ui-keyring/observable/types'; + +import { MemberId, Membership } from '@joystream/types/members'; +import { LeadId } from '@joystream/types/content-working-group'; +import { useMyMembership } from '../hooks'; +import { componentName } from '../helpers'; +import { withMyAccount } from './accounts'; + +export type MyAddressProps = { + myAddress?: string; +}; + +export type MyAccountProps = MyAddressProps & { + myAccountId?: AccountId; + myMemberId?: MemberId; + memberIdsByRootAccountId?: Vec; + memberIdsByControllerAccountId?: Vec; + myMemberIdChecked?: boolean; + iAmMember?: boolean; + myMembership?: Membership | null; + + // Content Working Group + curatorEntries?: any; // entire linked_map: CuratorId => Curator + isLeadSet?: Option; + contentLeadId?: LeadId; + contentLeadEntry?: any; // linked_map value + + curationActor?: any; + allAccounts?: SubjectInfo; +}; + +export function MembershipRequired

> (Component: React.ComponentType

): React.ComponentType

{ + const ResultComponent: React.FunctionComponent

= (props: P) => { + const { myMemberIdChecked, iAmMember } = useMyMembership(); + + if (!myMemberIdChecked) { + return Loading...; + } else if (iAmMember) { + return ; + } + + return ( + + Only members can access this functionality. +

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

> (Component: React.ComponentType

): React.ComponentType

{ + const ResultComponent: React.FunctionComponent

= (props: P) => { + const { allAccounts } = useMyMembership(); + + if (allAccounts && !Object.keys(allAccounts).length) { + return ( + + Please create a key to get started. +

+ + Create key + +
+ + ); + } + + return ; + }; + + ResultComponent.displayName = `AccountRequired(${componentName(Component)})`; + + return ResultComponent; +} + +// TODO: We could probably use withAccountRequired, which wouldn't pass any addiotional props, just like withMembershipRequired. +// Just need to make sure those passed props are not used in the extended components (they probably aren't). +export const withOnlyAccounts =

(Component: React.ComponentType

): React.ComponentType

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

> (Component: React.ComponentType

): React.ComponentType

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

(Component: React.ComponentType

): React.ComponentType

=> + withMulti(Component, withMyAccount, withMembershipRequired); diff --git a/pioneer/packages/joy-utils/src/react/hooks/index.ts b/pioneer/packages/joy-utils/src/react/hooks/index.ts new file mode 100644 index 0000000000..f95a7d97e0 --- /dev/null +++ b/pioneer/packages/joy-utils/src/react/hooks/index.ts @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000000..26ad3a32ea --- /dev/null +++ b/pioneer/packages/joy-utils/src/react/hooks/useMyAccount.tsx @@ -0,0 +1,6 @@ +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 new file mode 100644 index 0000000000..bbf8959a66 --- /dev/null +++ b/pioneer/packages/joy-utils/src/react/hooks/useMyMembership.tsx @@ -0,0 +1,6 @@ +import { useContext } from 'react'; +import { MyMembershipContext } from '../context'; + +export default function useMyMembership () { + return useContext(MyMembershipContext); +} diff --git a/pioneer/packages/old-apps/apps-routing/src/joy-pages.ts b/pioneer/packages/old-apps/apps-routing/src/joy-pages.ts deleted file mode 100644 index 44905af757..0000000000 --- a/pioneer/packages/old-apps/apps-routing/src/joy-pages.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Routes } from './types'; - -import { ToS, Privacy } from '@polkadot/joy-pages/index'; - -export default ([ - { - Component: ToS, - display: { - isHidden: true - }, - i18n: { - defaultValue: 'Terms of Service' - }, - icon: 'file outline', - name: 'pages/tos' - }, - { - Component: Privacy, - display: { - isHidden: true - }, - i18n: { - defaultValue: 'Privacy Policy' - }, - icon: 'file outline', - name: 'pages/privacy' - } -] as Routes); diff --git a/pioneer/packages/old-apps/apps/src/TopBar.css b/pioneer/packages/old-apps/apps/src/TopBar.css deleted file mode 100644 index 1291368282..0000000000 --- a/pioneer/packages/old-apps/apps/src/TopBar.css +++ /dev/null @@ -1,17 +0,0 @@ -.JoyTopBar { - padding: .5rem .5rem; - background-color: #3f3f3f; - border-bottom: 1px solid #d4d4d5; - text-align: right; - margin: 0 -2rem; - - &.NoMyAddress { - background-color: #ffeb83; - color: #000; - text-align: center; - } - - .ui--InputAddress { - display: inline-block; - } -} \ No newline at end of file diff --git a/pioneer/packages/old-apps/apps/src/TopBar.tsx b/pioneer/packages/old-apps/apps/src/TopBar.tsx deleted file mode 100644 index 4f4c211d28..0000000000 --- a/pioneer/packages/old-apps/apps/src/TopBar.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -// import { Link } from 'react-router-dom'; -import { I18nProps } from '@polkadot/react-components/types'; -import { useMyAccount } from '@polkadot/joy-utils/MyAccountContext'; -import { InputAddress } from '@polkadot/react-components'; -import { Available } from '@polkadot/react-query'; -import translate from './translate'; -import './TopBar.css'; - -type Props = I18nProps & {}; - -function renderAddress (address: string) { - const balance = Balance: ; - - return ( -

- } - type="account" - /> -
- ); -} - -// function renderNoAddress() { -// return ( -//
-// -// You need to create a key if you want to use all features. -// -// Create key -// -//
-// ); -// } - -function Component (_props: Props) { - const { - state: { address } - } = useMyAccount(); - return address ? renderAddress(address) : null; -} - -export default translate(Component); diff --git a/pioneer/packages/old-apps/react-components/src/styles/old-theme.ts-unused b/pioneer/packages/old-apps/react-components/src/styles/old-theme.ts-unused deleted file mode 100644 index 98c4d8a7b8..0000000000 --- a/pioneer/packages/old-apps/react-components/src/styles/old-theme.ts-unused +++ /dev/null @@ -1,11 +0,0 @@ -/* Copyright 2017-2019 @polkadot/react-components authors & contributors -/* This software may be modified and distributed under the terms -/* of the Apache-2.0 license. See the LICENSE file for details. */ - -import theme from 'styled-theming'; - -export const primaryColor = theme('theme', { - substrate: '#DB2828', - polkadot: '#E6007A', - default: 'darkorange' -}); diff --git a/pioneer/packages/page-staking/src/Targets/Summary.tsx b/pioneer/packages/page-staking/src/Targets/Summary.tsx index 24ac4ff6ef..5fbf2fc97c 100644 --- a/pioneer/packages/page-staking/src/Targets/Summary.tsx +++ b/pioneer/packages/page-staking/src/Targets/Summary.tsx @@ -66,7 +66,7 @@ function Summary ({ lastReward, numNominators, numValidators, totalStaked }: Pro )} - {numValidators && numNominators && ( + {numValidators !== undefined && numNominators !== undefined && ( ('validators')} / ${t('nominators')}`}> {numValidators} / {numNominators} diff --git a/pioneer/packages/react-components/src/InputAddress/index.tsx b/pioneer/packages/react-components/src/InputAddress/index.tsx index e5f1f9d162..f458d76b8a 100644 --- a/pioneer/packages/react-components/src/InputAddress/index.tsx +++ b/pioneer/packages/react-components/src/InputAddress/index.tsx @@ -20,6 +20,8 @@ import Dropdown from '../Dropdown'; import createHeader from './createHeader'; import createItem from './createItem'; +import { ACCOUNT_CHANGED_EVENT_NAME } from '@polkadot/joy-utils/react/context/account'; + interface Props { className?: string; defaultValue?: Uint8Array | string | null; @@ -115,6 +117,12 @@ 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 + window.dispatchEvent(new CustomEvent(ACCOUNT_CHANGED_EVENT_NAME, { detail: value })); + } } class InputAddress extends React.PureComponent { diff --git a/pioneer/packages/react-components/src/Tabs/Tab.tsx b/pioneer/packages/react-components/src/Tabs/Tab.tsx index 9613fb9e1a..e58b8dee33 100644 --- a/pioneer/packages/react-components/src/Tabs/Tab.tsx +++ b/pioneer/packages/react-components/src/Tabs/Tab.tsx @@ -16,16 +16,19 @@ interface Props extends TabItem { index: number; isSequence?: boolean; num: number; + forceMatchParams?: boolean; } -function Tab ({ basePath, className = '', hasParams, index, isExact, isRoot, isSequence, name, num, text }: Props): React.ReactElement { +function Tab ({ basePath, className = '', hasParams, index, isExact, isRoot, isSequence, name, num, text, forceMatchParams }: Props): React.ReactElement { const to = isRoot ? basePath : `${basePath}/${name}`; // only do exact matching when not the fallback (first position tab), // params are problematic for dynamic hidden such as app-accounts - const tabIsExact = isExact || !hasParams || (!isSequence && index === 0); + const tabIsExact = forceMatchParams + ? false + : (isExact || !hasParams || (!isSequence && index === 0)); return ( (props.uiHighlight || defaultHighlight); @@ -281,4 +282,5 @@ export default createGlobalStyle` ${cssMedia} ${cssRx} ${cssComponents} + ${cssJoystream} `; diff --git a/pioneer/packages/old-apps/react-components/src/styles/joystream.ts b/pioneer/packages/react-components/src/styles/joystream.ts similarity index 90% rename from pioneer/packages/old-apps/react-components/src/styles/joystream.ts rename to pioneer/packages/react-components/src/styles/joystream.ts index 9564a602e0..4e5054789e 100644 --- a/pioneer/packages/old-apps/react-components/src/styles/joystream.ts +++ b/pioneer/packages/react-components/src/styles/joystream.ts @@ -94,14 +94,6 @@ export default css` } } - .apps--SideBar-logo { - max-height: 26px !important; - margin: 1rem 1.5rem 2.5rem 0.75rem !important; - } - .collapsed .apps--SideBar-logo { - margin: 1rem 0.75rem 2.5rem 0.5rem !important; - } - .JoyForm { margin-bottom: 1.5rem; @@ -192,4 +184,20 @@ export default css` .text-blue { color: #3b83c0; } + + /* Overrides */ + .ui--IdentityIcon { + border: none !important; + } + /* Normalize SideBar icons width */ + .apps--SideBar-Item-NavLink svg { + width: 20px !important; + } + /* Fix "collapsed" sidebar on mobile */ + .apps--Wrapper:not(.menu-open) .apps--SideBar-Scroll { + padding: 0 !important; + } + h1 { + text-transform: none; + } `; diff --git a/pioneer/packages/react-components/src/styles/theme.ts b/pioneer/packages/react-components/src/styles/theme.ts index 4a92f3fc15..39214afecd 100644 --- a/pioneer/packages/react-components/src/styles/theme.ts +++ b/pioneer/packages/react-components/src/styles/theme.ts @@ -10,7 +10,7 @@ export const colorBtnDefault = '#767778'; export const colorBtnShadow = '#98999a'; /* highlighted buttons, orange */ -export const colorBtnHighlight = '#f19135'; +export const colorBtnHighlight = '#4038FF'; /* primary buttons, blue */ export const colorBtnPrimary = colorBtnDefault; // '#2e86ab'; diff --git a/pioneer/tsconfig.json b/pioneer/tsconfig.json index 716cefadc1..2226b26297 100644 --- a/pioneer/tsconfig.json +++ b/pioneer/tsconfig.json @@ -4,16 +4,13 @@ "build/**/*", "**/build/**/*", "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/**/*" ], "compilerOptions": { @@ -23,6 +20,7 @@ "resolveJsonModule": true, "baseUrl": ".", "paths": { + "@polkadot/types/augment": [ "../types/src/definitions/augment-types.ts" ], // "@joystream/types/": [ "../types/src/" ], // "@joystream/types/*": [ "../types/src/*" ], // "@polkadot/joy-election/": [ "packages/joy-election/src/" ], @@ -33,18 +31,18 @@ // "@polkadot/joy-help/*": [ "packages/joy-help/src/*" ], // "@polkadot/joy-media/": [ "packages/joy-media/src/" ], // "@polkadot/joy-media/*": [ "packages/joy-media/src/*" ], - // "@polkadot/joy-members/": [ "packages/joy-members/src/" ], - // "@polkadot/joy-members/*": [ "packages/joy-members/src/*" ], - // "@polkadot/joy-pages/": [ "packages/joy-pages/src/" ], - // "@polkadot/joy-pages/*": [ "packages/joy-pages/src/*" ], + "@polkadot/joy-members/": [ "packages/joy-members/src/" ], + "@polkadot/joy-members/*": [ "packages/joy-members/src/*" ], + "@polkadot/joy-pages/": [ "packages/joy-pages/src/" ], + "@polkadot/joy-pages/*": [ "packages/joy-pages/src/*" ], // "@polkadot/joy-proposals/": [ "packages/joy-proposals/src/" ], // "@polkadot/joy-proposals/*": [ "packages/joy-proposals/src/*" ], // "@polkadot/joy-roles/": [ "packages/joy-roles/src/" ], // "@polkadot/joy-roles/*": [ "packages/joy-roles/src/*" ], // "@polkadot/joy-settings/": [ "packages/joy-settings/src/" ], // "@polkadot/joy-settings/*": [ "packages/joy-settings/src/*" ], - // "@polkadot/joy-utils/": [ "packages/joy-utils/src/" ], - // "@polkadot/joy-utils/*": [ "packages/joy-utils/src/*" ], + "@polkadot/joy-utils/": [ "packages/joy-utils/src/" ], + "@polkadot/joy-utils/*": [ "packages/joy-utils/src/*" ], "@polkadot/apps/*": ["packages/apps/src/*"], "@polkadot/apps": ["packages/apps/src"], "@polkadot/apps-config/*": [ "packages/apps-config/src/*" ], diff --git a/yarn.lock b/yarn.lock index aad44f4b07..6f75c9758d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1374,6 +1374,13 @@ pirates "^4.0.0" source-map-support "^0.5.16" +"@babel/runtime@7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c" + integrity sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA== + dependencies: + regenerator-runtime "^0.12.0" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.1", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2", "@babel/runtime@^7.9.6": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" @@ -4450,6 +4457,13 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== +"@types/query-string@^6.2.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@types/query-string/-/query-string-6.3.0.tgz#b6fa172a01405abcaedac681118e78429d62ea39" + integrity sha512-yuIv/WRffRzL7cBW+sla4HwBZrEXRNf1MKQ5SklPEadth+BKbDxiVG8A3iISN5B3yC4EeSCzMZP8llHTcUhOzQ== + dependencies: + query-string "*" + "@types/reach__router@^1.2.3": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/reach__router/-/reach__router-1.3.5.tgz#14e1e981cccd3a5e50dc9e969a72de0b9d472f6d" @@ -4648,16 +4662,37 @@ dependencies: source-map "^0.6.1" -"@types/unist@^2.0.0", "@types/unist@^2.0.2": +"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== +"@types/uuid@^3.4.4": + version "3.4.9" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.9.tgz#fcf01997bbc9f7c09ae5f91383af076d466594e1" + integrity sha512-XDwyIlt/47l2kWLTzw/mtrpLdB+GPSskR2n/PIcPn+VYhVO77rGhRncIR5GPU0KRzXuqkDO+J5qqrG0Y8P6jzQ== + "@types/uuid@^7.0.2": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-7.0.4.tgz#00a5749810b4ad80bff73a61f9cc9d0d521feb3c" integrity sha512-WGZCqBZZ0mXN2RxvLHL6/7RCu+OWs28jgQMP04LWfpyJlQUMTR6YU9CNJAKDgbw+EV/u687INXuLUc7FuML/4g== +"@types/vfile-message@*": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/vfile-message/-/vfile-message-2.0.0.tgz#690e46af0fdfc1f9faae00cd049cc888957927d5" + integrity sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw== + dependencies: + vfile-message "*" + +"@types/vfile@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/vfile/-/vfile-3.0.2.tgz#19c18cd232df11ce6fa6ad80259bc86c366b09b9" + integrity sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw== + dependencies: + "@types/node" "*" + "@types/unist" "*" + "@types/vfile-message" "*" + "@types/vfile@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/vfile/-/vfile-4.0.0.tgz#c32d13cbda319bc9f4ab3cacc0263b4ba1dd1ea3" @@ -4708,6 +4743,11 @@ resolved "https://registry.yarnpkg.com/@types/yoga-layout/-/yoga-layout-1.9.2.tgz#efaf9e991a7390dc081a0b679185979a83a9639a" integrity sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw== +"@types/yup@^0.26.10": + version "0.26.37" + resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.37.tgz#7a52854ac602ba0dc969bebc960559f7464a1686" + integrity sha512-cDqR/ez4+iAVQYOwadXjKX4Dq1frtnDGV2GNVKj3aUVKVCKRvsr8esFk66j+LgeeJGmrMcBkkfCf3zk13MjV7A== + "@typescript-eslint/eslint-plugin@3.8.0": version "3.8.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.8.0.tgz#f82947bcdd9a4e42be7ad80dfd61f1dc411dd1df" @@ -5895,7 +5935,7 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@^2.0.0: +asap@^2.0.0, asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -8508,6 +8548,11 @@ core-js-pure@^3.0.1: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.4.5.tgz#284474cb48d134e26e6e314cb89986c6c59480fb" integrity sha512-v3BoUOhmBvs4Z17jG/oM7qyv+tEEMvD1FYDDfxa6uD5W2rA/DpKvhvmyrBzxuMQTa/91UQKisaiqe0+0GuL2oA== +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= + core-js@^2.4.0, core-js@^2.6.5: version "2.6.10" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f" @@ -8661,6 +8706,14 @@ create-react-context@0.3.0, create-react-context@^0.3.0: gud "^1.0.0" warning "^4.0.3" +create-react-context@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.3.tgz#9ec140a6914a22ef04b8b09b7771de89567cb6f3" + integrity sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag== + dependencies: + fbjs "^0.8.0" + gud "^1.0.0" + cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -9223,6 +9276,11 @@ deepmerge@^1.5.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ== +deepmerge@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + deepmerge@^4.0.0, deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" @@ -11289,6 +11347,19 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" +fbjs@^0.8.0: + version "0.8.17" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -11494,7 +11565,7 @@ find-babel-config@^1.2.0: json5 "^0.5.1" path-exists "^3.0.0" -find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: +find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== @@ -11636,6 +11707,11 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: inherits "^2.0.3" readable-stream "^2.3.6" +fn-name@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7" + integrity sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc= + focus-lock@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.7.0.tgz#b2bfb0ca7beacc8710a1ff74275fe0dc60a1d88a" @@ -11737,6 +11813,21 @@ formidable@^1.2.0: resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== +formik@^1.5.0: + version "1.5.8" + resolved "https://registry.yarnpkg.com/formik/-/formik-1.5.8.tgz#eee8cd345effe46839bc748c7f920486f12f14b0" + integrity sha512-fNvPe+ddbh+7xiByT25vuso2p2hseG/Yvuj211fV1DbCjljUEG9OpgRpcb7g7O3kxHX/q31cbZDzMxJXPWSNwA== + dependencies: + create-react-context "^0.2.2" + deepmerge "^2.1.1" + hoist-non-react-statics "^3.3.0" + lodash "^4.17.14" + lodash-es "^4.17.14" + prop-types "^15.6.1" + react-fast-compare "^2.0.1" + tiny-warning "^1.0.2" + tslib "^1.9.3" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -14739,7 +14830,7 @@ isobject@^4.0.0: resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== -isomorphic-fetch@^2.2.1: +isomorphic-fetch@^2.1.1, isomorphic-fetch@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= @@ -16122,6 +16213,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash-es@^4.17.14: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" + integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -16582,6 +16678,11 @@ markdown-loader@^5.1.0: loader-utils "^1.2.3" marked "^0.7.0" +markdown-table@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60" + integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q== + markdown-table@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b" @@ -16645,6 +16746,13 @@ mdast-add-list-metadata@1.0.1: dependencies: unist-util-visit-parents "1.1.2" +mdast-util-compact@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz#d531bb7667b5123abf20859be086c4d06c894593" + integrity sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg== + dependencies: + unist-util-visit "^1.1.0" + mdast-util-compact@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz#cabc69a2f43103628326f35b1acf735d55c99490" @@ -18723,7 +18831,7 @@ parse-asn1@^5.0.0: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-entities@^1.1.0, parse-entities@^1.1.2: +parse-entities@^1.0.2, parse-entities@^1.1.0, parse-entities@^1.1.2: version "1.2.2" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== @@ -19056,7 +19164,7 @@ pirates@^3.0.2: dependencies: node-modules-regexp "^1.0.0" -pirates@^4.0.0, pirates@^4.0.1: +pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== @@ -19805,6 +19913,13 @@ promise.prototype.finally@^3.1.0: es-abstract "^1.17.0-next.0" function-bind "^1.1.1" +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + promise@~1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/promise/-/promise-1.3.0.tgz#e5cc9a4c8278e4664ffedc01c7da84842b040175" @@ -19850,6 +19965,11 @@ proper-lockfile@^4.0.0, proper-lockfile@^4.1.1: retry "^0.12.0" signal-exit "^3.0.2" +property-expr@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f" + integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g== + property-information@^5.0.0: version "5.5.0" resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.5.0.tgz#4dc075d493061a82e2b7d096f406e076ed859943" @@ -20119,6 +20239,15 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +query-string@*, query-string@^6.13.1, query-string@^6.2.0: + version "6.13.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.1.tgz#d913ccfce3b4b3a713989fe6d39466d92e71ccad" + integrity sha512-RfoButmcK+yCta1+FuU8REvisx1oEzhMKwhLUNcepQTPGcNMp1sIqjnfCtfnvGSQZQEhaBHvccujtWoUV3TTbA== + dependencies: + decode-uri-component "^0.2.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + query-string@^4.1.0: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" @@ -20136,15 +20265,6 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.13.1: - version "6.13.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.1.tgz#d913ccfce3b4b3a713989fe6d39466d92e71ccad" - integrity sha512-RfoButmcK+yCta1+FuU8REvisx1oEzhMKwhLUNcepQTPGcNMp1sIqjnfCtfnvGSQZQEhaBHvccujtWoUV3TTbA== - dependencies: - decode-uri-component "^0.2.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" - querystring-es3@^0.2.0, querystring-es3@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -20380,6 +20500,11 @@ react-error-overlay@^6.0.3: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== +react-fast-compare@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" + integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== + react-fast-compare@^3.0.1: version "3.2.0" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" @@ -20454,7 +20579,7 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-markdown@^4.3.1: +react-markdown@^4.0.6, react-markdown@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-4.3.1.tgz#39f0633b94a027445b86c9811142d05381300f2f" integrity sha512-HQlWFTbDxTtNY6bjgp3C3uv1h2xcjCSi1zAEzfBW9OwJJvENSYiLXWNXN5hHLsoqai7RnZiiHzcnWdXk2Splzw== @@ -20980,6 +21105,11 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regenerator-runtime@^0.13.2: version "0.13.3" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" @@ -21121,6 +21251,27 @@ remark-parse@^5.0.0: vfile-location "^2.0.0" xtend "^4.0.1" +remark-parse@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-6.0.3.tgz#c99131052809da482108413f87b0ee7f52180a3a" + integrity sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg== + dependencies: + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^1.1.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^1.0.0" + vfile-location "^2.0.0" + xtend "^4.0.1" + remark-parse@^8.0.0: version "8.0.3" resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-8.0.3.tgz#9c62aa3b35b79a486454c690472906075f40c7e1" @@ -21143,6 +21294,26 @@ remark-parse@^8.0.0: vfile-location "^3.0.0" xtend "^4.0.1" +remark-stringify@^6.0.0: + version "6.0.4" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-6.0.4.tgz#16ac229d4d1593249018663c7bddf28aafc4e088" + integrity sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg== + dependencies: + ccount "^1.0.0" + is-alphanumeric "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + longest-streak "^2.0.1" + markdown-escapes "^1.0.0" + markdown-table "^1.1.0" + mdast-util-compact "^1.0.0" + parse-entities "^1.0.2" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + stringify-entities "^1.0.1" + unherit "^1.0.4" + xtend "^4.0.1" + remark-stringify@^8.0.0: version "8.1.1" resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-8.1.1.tgz#e2a9dc7a7bf44e46a155ec78996db896780d8ce5" @@ -21163,6 +21334,15 @@ remark-stringify@^8.0.0: unherit "^1.0.4" xtend "^4.0.1" +remark@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/remark/-/remark-10.0.1.tgz#3058076dc41781bf505d8978c291485fe47667df" + integrity sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ== + dependencies: + remark-parse "^6.0.0" + remark-stringify "^6.0.0" + unified "^7.0.0" + remark@^12.0.0: version "12.0.1" resolved "https://registry.yarnpkg.com/remark/-/remark-12.0.1.tgz#f1ddf68db7be71ca2bad0a33cd3678b86b9c709f" @@ -21959,7 +22139,7 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -22858,6 +23038,16 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +stringify-entities@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-1.3.2.tgz#a98417e5471fd227b3e45d3db1861c11caf668f7" + integrity sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A== + dependencies: + character-entities-html4 "^1.0.0" + character-entities-legacy "^1.0.0" + is-alphanumerical "^1.0.0" + is-hexadecimal "^1.0.0" + stringify-entities@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-3.0.1.tgz#32154b91286ab0869ab2c07696223bd23b6dbfc0" @@ -22972,6 +23162,11 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-markdown@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/strip-markdown/-/strip-markdown-3.1.2.tgz#172f6f89f9a98896e65a65422e0507f2bbac1667" + integrity sha512-NjwW6CEefesmHQPs7lof/lgnSriqUnRNOWpnrNPq9A7/yOCdnhaB7DcxlhYuN7WiiRUe349aitAsTQ/ajM9Dmw== + strip-outer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" @@ -23277,6 +23472,11 @@ symbol.prototype.description@^1.0.0: es-abstract "^1.17.0-next.1" has-symbols "^1.0.1" +synchronous-promise@^2.0.5: + version "2.0.13" + resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.13.tgz#9d8c165ddee69c5a6542862b405bc50095926702" + integrity sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA== + table@^5.2.3, table@^5.4.6: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -23735,7 +23935,7 @@ tiny-invariant@^1.0.2, tiny-invariant@^1.0.6: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== -tiny-warning@^1.0.0, tiny-warning@^1.0.3: +tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== @@ -23863,6 +24063,11 @@ toposort@^1.0.0: resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk= +toposort@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" + integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA= + touch@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" @@ -24220,6 +24425,11 @@ typescript@^3.0.3, typescript@^3.7.2, typescript@^3.7.5, typescript@^3.8.3, type resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +ua-parser-js@^0.7.18: + version "0.7.21" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777" + integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" @@ -24324,6 +24534,20 @@ unified@^6.1.5: vfile "^2.0.0" x-is-string "^0.1.0" +unified@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-7.1.0.tgz#5032f1c1ee3364bd09da12e27fdd4a7553c7be13" + integrity sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw== + dependencies: + "@types/unist" "^2.0.0" + "@types/vfile" "^3.0.0" + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^1.1.0" + trough "^1.0.0" + vfile "^3.0.0" + x-is-string "^0.1.0" + unified@^9.0.0: version "9.1.0" resolved "https://registry.yarnpkg.com/unified/-/unified-9.1.0.tgz#7ba82e5db4740c47a04e688a9ca8335980547410" @@ -24842,6 +25066,14 @@ vfile-location@^3.0.0: resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.0.1.tgz#d78677c3546de0f7cd977544c367266764d31bb3" integrity sha512-yYBO06eeN/Ki6Kh1QAkgzYpWT1d3Qln+ZCtSbJqFExPl1S3y2qqotJQXoh6qEvl/jDlgpUJolBn3PItVnnZRqQ== +vfile-message@*: + version "2.0.4" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" + integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + vfile-message@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" @@ -24878,6 +25110,16 @@ vfile@^2.0.0: unist-util-stringify-position "^1.0.0" vfile-message "^1.0.0" +vfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-3.0.1.tgz#47331d2abe3282424f4a4bb6acd20a44c4121803" + integrity sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ== + dependencies: + is-buffer "^2.0.0" + replace-ext "1.0.0" + unist-util-stringify-position "^1.0.0" + vfile-message "^1.0.0" + vinyl-fs@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" @@ -25881,6 +26123,18 @@ yoga-layout-prebuilt@^1.9.3: dependencies: "@types/yoga-layout" "1.9.2" +yup@^0.26.10: + version "0.26.10" + resolved "https://registry.yarnpkg.com/yup/-/yup-0.26.10.tgz#3545839663289038faf25facfc07e11fd67c0cb1" + integrity sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw== + dependencies: + "@babel/runtime" "7.0.0" + fn-name "~2.0.1" + lodash "^4.17.10" + property-expr "^1.5.0" + synchronous-promise "^2.0.5" + toposort "^2.0.2" + zepto@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/zepto/-/zepto-1.2.0.tgz#e127bd9e66fd846be5eab48c1394882f7c0e4f98"