Alliance unscrupelous accounts & websites (#7917)
This commit is contained in:
parent
c6167b66ec
commit
aee78ca152
@ -1,22 +1,23 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Member } from './types';
|
||||
import type { Member, Unscrupelous } from '../types';
|
||||
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
import { InputAddress, InputBalance, Modal, TxButton } from '@polkadot/react-components';
|
||||
import { useAccounts, useApi } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from './translate';
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
members: Member[];
|
||||
onClose: () => void;
|
||||
unscrupelous: Unscrupelous;
|
||||
}
|
||||
|
||||
function Join ({ className, members, onClose }: Props): React.ReactElement<Props> {
|
||||
function Join ({ className, members, onClose, unscrupelous: { accounts } }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { allAccounts } = useAccounts();
|
||||
@ -27,9 +28,12 @@ function Join ({ className, members, onClose }: Props): React.ReactElement<Props
|
||||
allAccounts.filter((a) =>
|
||||
!members.some(({ accountId }) =>
|
||||
accountId === a
|
||||
) &&
|
||||
!accounts.some((accountId) =>
|
||||
accountId === a
|
||||
)
|
||||
),
|
||||
[allAccounts, members]
|
||||
[accounts, allAccounts, members]
|
||||
);
|
||||
|
||||
return (
|
||||
@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Member as MemberType } from './types';
|
||||
import type { Member as MemberType } from '../types';
|
||||
|
||||
import React, { useCallback, useContext, useMemo } from 'react';
|
||||
|
||||
@ -9,8 +9,8 @@ import { AddressSmall, Badge, Menu, Popup, StatusContext } from '@polkadot/react
|
||||
import { useAccounts, useApi } from '@polkadot/react-hooks';
|
||||
import { FormatBalance } from '@polkadot/react-query';
|
||||
|
||||
import { useTranslation } from './translate';
|
||||
import useMemberInfo from './useMemberInfo';
|
||||
import { useTranslation } from '../translate';
|
||||
import useMemberInfo from '../useMemberInfo';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
@ -1,25 +1,22 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Member as MemberType } from '../types';
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
|
||||
import { Button, Table } from '@polkadot/react-components';
|
||||
import { useToggle } from '@polkadot/react-hooks';
|
||||
import { Table } from '@polkadot/react-components';
|
||||
|
||||
import Join from './Join';
|
||||
import { useTranslation } from '../translate';
|
||||
import Member from './Member';
|
||||
import Summary from './Summary';
|
||||
import { useTranslation } from './translate';
|
||||
import useMembers from './useMembers';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
members?: MemberType[];
|
||||
}
|
||||
|
||||
function Members ({ className }: Props): React.ReactElement<Props> {
|
||||
function Members ({ className, members }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const [isJoinOpen, toggleJoin] = useToggle();
|
||||
const members = useMembers();
|
||||
|
||||
const hdrRef = useRef([
|
||||
[t<string>('members'), 'start', 2],
|
||||
@ -30,21 +27,6 @@ function Members ({ className }: Props): React.ReactElement<Props> {
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Summary />
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon='add'
|
||||
isDisabled={!members}
|
||||
label={t<string>('Join')}
|
||||
onClick={toggleJoin}
|
||||
/>
|
||||
{members && isJoinOpen && (
|
||||
<Join
|
||||
members={members}
|
||||
onClose={toggleJoin}
|
||||
/>
|
||||
)}
|
||||
</Button.Group>
|
||||
<Table
|
||||
empty={members && t<string>('No members')}
|
||||
header={hdrRef.current}
|
||||
50
packages/page-alliance/src/Overview/index.tsx
Normal file
50
packages/page-alliance/src/Overview/index.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Unscrupelous } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Button } from '@polkadot/react-components';
|
||||
import { useToggle } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import useMembers from '../useMembers';
|
||||
import Join from './Join';
|
||||
import Members from './Members';
|
||||
import Summary from './Summary';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
unscrupelous?: Unscrupelous;
|
||||
}
|
||||
|
||||
function Overview ({ className, unscrupelous }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const [isJoinOpen, toggleJoin] = useToggle();
|
||||
const members = useMembers();
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Summary />
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon='add'
|
||||
isDisabled={!members || !unscrupelous}
|
||||
label={t<string>('Join')}
|
||||
onClick={toggleJoin}
|
||||
/>
|
||||
{members && unscrupelous && isJoinOpen && (
|
||||
<Join
|
||||
members={members}
|
||||
onClose={toggleJoin}
|
||||
unscrupelous={unscrupelous}
|
||||
/>
|
||||
)}
|
||||
</Button.Group>
|
||||
<Members members={members} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Overview);
|
||||
23
packages/page-alliance/src/Unscrupelous/Account.tsx
Normal file
23
packages/page-alliance/src/Unscrupelous/Account.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { AddressSmall } from '@polkadot/react-components';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
function Account ({ className, value }: Props): React.ReactElement<Props> {
|
||||
return (
|
||||
<tr className={className}>
|
||||
<td className='address all'>
|
||||
<AddressSmall value={value} />
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Account);
|
||||
21
packages/page-alliance/src/Unscrupelous/Website.tsx
Normal file
21
packages/page-alliance/src/Unscrupelous/Website.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
function Website ({ className, value }: Props): React.ReactElement<Props> {
|
||||
return (
|
||||
<tr className={className}>
|
||||
<td className='start all'>
|
||||
{value}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Website);
|
||||
58
packages/page-alliance/src/Unscrupelous/index.tsx
Normal file
58
packages/page-alliance/src/Unscrupelous/index.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Unscrupelous as UnscrupelousType } from '../types';
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
|
||||
import { Table } from '@polkadot/react-components';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import Account from './Account';
|
||||
import Website from './Website';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
unscrupelous?: UnscrupelousType;
|
||||
}
|
||||
|
||||
function Unscrupelous ({ className, unscrupelous }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const accRef = useRef([
|
||||
[t<string>('accounts'), 'start']
|
||||
]);
|
||||
|
||||
const webRef = useRef([
|
||||
[t<string>('websites'), 'start']
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Table
|
||||
empty={unscrupelous && unscrupelous.accounts && t<string>('No accounts')}
|
||||
header={accRef.current}
|
||||
>
|
||||
{unscrupelous && unscrupelous.accounts.map((m) => (
|
||||
<Account
|
||||
key={m}
|
||||
value={m}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
<Table
|
||||
empty={unscrupelous && unscrupelous.websites && t<string>('No websites')}
|
||||
header={webRef.current}
|
||||
>
|
||||
{unscrupelous && unscrupelous.websites.map((m) => (
|
||||
<Website
|
||||
key={m}
|
||||
value={m}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Unscrupelous);
|
||||
@ -2,11 +2,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
|
||||
import { Tabs } from '@polkadot/react-components';
|
||||
|
||||
import Members from './Members';
|
||||
import Overview from './Overview';
|
||||
import { useTranslation } from './translate';
|
||||
import Unscrupelous from './Unscrupelous';
|
||||
import useUnscrupelous from './useUnscrupelous';
|
||||
|
||||
interface Props {
|
||||
basePath: string;
|
||||
@ -15,12 +18,17 @@ interface Props {
|
||||
|
||||
function AllianceApp ({ basePath, className }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const unscrupelous = useUnscrupelous();
|
||||
|
||||
const itemsRef = useRef([
|
||||
{
|
||||
isRoot: true,
|
||||
name: 'index',
|
||||
name: 'overview',
|
||||
text: t<string>('Overview')
|
||||
},
|
||||
{
|
||||
name: 'unscrupelous',
|
||||
text: t<string>('Unscrupelous')
|
||||
}
|
||||
]);
|
||||
|
||||
@ -30,7 +38,14 @@ function AllianceApp ({ basePath, className }: Props): React.ReactElement<Props>
|
||||
basePath={basePath}
|
||||
items={itemsRef.current}
|
||||
/>
|
||||
<Members />
|
||||
<Switch>
|
||||
<Route path={`${basePath}/unscrupelous`}>
|
||||
<Unscrupelous unscrupelous={unscrupelous} />
|
||||
</Route>
|
||||
<Route>
|
||||
<Overview unscrupelous={unscrupelous} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@ -14,3 +14,8 @@ export interface MemberInfo {
|
||||
deposit?: BN | null;
|
||||
isUpForKicking: boolean;
|
||||
}
|
||||
|
||||
export interface Unscrupelous {
|
||||
accounts: string[];
|
||||
websites: string[];
|
||||
}
|
||||
|
||||
@ -13,17 +13,17 @@ function useMemberInfoImpl (accountId: string): MemberInfo | undefined {
|
||||
const upForKicking = useCall<bool>(api.query.alliance.upForKicking, [accountId]);
|
||||
const depositOf = useCall<Option<UInt>>(api.query.alliance.depositOf, [accountId]);
|
||||
|
||||
return useMemo((): MemberInfo | undefined => {
|
||||
if (upForKicking && depositOf) {
|
||||
return {
|
||||
accountId,
|
||||
deposit: depositOf.unwrapOr(null),
|
||||
isUpForKicking: upForKicking.isTrue
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}, [accountId, upForKicking, depositOf]);
|
||||
return useMemo(
|
||||
(): MemberInfo | undefined =>
|
||||
upForKicking && depositOf
|
||||
? {
|
||||
accountId,
|
||||
deposit: depositOf.unwrapOr(null),
|
||||
isUpForKicking: upForKicking.isTrue
|
||||
}
|
||||
: undefined,
|
||||
[accountId, upForKicking, depositOf]
|
||||
);
|
||||
}
|
||||
|
||||
export default createNamedHook('useMemberInfo', useMemberInfoImpl);
|
||||
|
||||
@ -10,7 +10,7 @@ import { createNamedHook, useApi, useCallMulti } from '@polkadot/react-hooks';
|
||||
|
||||
const ROLES = <const> ['Founder', 'Fellow', 'Ally'];
|
||||
|
||||
function addMembers (prev: Member[] = [], query: AccountId32[][]): Member[] {
|
||||
function addMembers (prev: Member[], query: AccountId32[][]): Member[] {
|
||||
const all: Member[] = [];
|
||||
|
||||
for (let i = 0; i < ROLES.length; i++) {
|
||||
@ -19,7 +19,10 @@ function addMembers (prev: Member[] = [], query: AccountId32[][]): Member[] {
|
||||
|
||||
for (let j = 0; j < accountIds.length; j++) {
|
||||
const accountId = accountIds[j].toString();
|
||||
const existing = prev.find((p) => p.accountId === accountId && p.role === role);
|
||||
const existing = prev.find((p) =>
|
||||
p.accountId === accountId &&
|
||||
p.role === role
|
||||
);
|
||||
|
||||
all.push(existing || {
|
||||
accountId,
|
||||
@ -42,7 +45,7 @@ function useMembersImpl (): Member[] | undefined {
|
||||
|
||||
useEffect((): void => {
|
||||
query && query.length === ROLES.length &&
|
||||
setState((prev) => addMembers(prev, query));
|
||||
setState((prev = []) => addMembers(prev, query));
|
||||
}, [query]);
|
||||
|
||||
return state;
|
||||
|
||||
32
packages/page-alliance/src/useUnscrupelous.ts
Normal file
32
packages/page-alliance/src/useUnscrupelous.ts
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Bytes } from '@polkadot/types';
|
||||
import type { AccountId32 } from '@polkadot/types/interfaces';
|
||||
import type { Unscrupelous } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
function getUnscrupelous (accounts: AccountId32[], websites: Bytes[]): Unscrupelous {
|
||||
return {
|
||||
accounts: accounts.map((a) => a.toString()),
|
||||
websites: websites.filter((b) => b.isAscii).map((b) => b.toString())
|
||||
};
|
||||
}
|
||||
|
||||
function useUnscrupelousImpl (): Unscrupelous | undefined {
|
||||
const { api } = useApi();
|
||||
const accounts = useCall<AccountId32[]>(api.query.alliance.unscrupulousAccounts, []);
|
||||
const websites = useCall<Bytes[]>(api.query.alliance.unscrupulousWebsites, []);
|
||||
|
||||
return useMemo(
|
||||
(): Unscrupelous | undefined =>
|
||||
accounts && websites &&
|
||||
getUnscrupelous(accounts, websites),
|
||||
[accounts, websites]
|
||||
);
|
||||
}
|
||||
|
||||
export default createNamedHook('useUnscrupelous', useUnscrupelousImpl);
|
||||
Loading…
Reference in New Issue
Block a user