Allow alliance retire (& display member-specific info) (#7916)
This commit is contained in:
parent
1d44d9a060
commit
ad27ddb80c
@ -3,9 +3,14 @@
|
||||
|
||||
import type { Member as MemberType } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback, useContext, useMemo } from 'react';
|
||||
|
||||
import { AddressSmall } from '@polkadot/react-components';
|
||||
import { AddressSmall, Badge, Menu, Popup, StatusContext } from '@polkadot/react-components';
|
||||
import { useAccounts, useApi } from '@polkadot/react-hooks';
|
||||
import { FormatBalance } from '@polkadot/react-query';
|
||||
|
||||
import { useTranslation } from './translate';
|
||||
import useMemberInfo from './useMemberInfo';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
@ -13,15 +18,62 @@ interface Props {
|
||||
}
|
||||
|
||||
function Member ({ className, info: { accountId, role } }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { allAccounts } = useAccounts();
|
||||
const info = useMemberInfo(accountId);
|
||||
const { queueExtrinsic } = useContext(StatusContext);
|
||||
|
||||
const hasActions = useMemo(
|
||||
() => allAccounts.includes(accountId),
|
||||
[allAccounts, accountId]
|
||||
);
|
||||
|
||||
const doRetire = useCallback(
|
||||
() => queueExtrinsic({
|
||||
accountId,
|
||||
extrinsic: api.tx.alliance.retire()
|
||||
}),
|
||||
[accountId, api, queueExtrinsic]
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className={className}>
|
||||
<td className='badge' />
|
||||
<td className='badge'>
|
||||
{info && info.isUpForKicking && (
|
||||
<Badge
|
||||
color='red'
|
||||
icon='ban'
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
<td className='address all'>
|
||||
<AddressSmall value={accountId} />
|
||||
</td>
|
||||
<td className='number'>
|
||||
{info && info.deposit && (
|
||||
<FormatBalance value={info.deposit} />
|
||||
)}
|
||||
</td>
|
||||
<td className='number'>
|
||||
{role}
|
||||
</td>
|
||||
<td className='button'>
|
||||
{hasActions && (
|
||||
<Popup
|
||||
key='settings'
|
||||
value={
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
isDisabled={info && info.isUpForKicking}
|
||||
label={t<string>('Retire')}
|
||||
onClick={doRetire}
|
||||
/>
|
||||
</Menu>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
@ -23,7 +23,9 @@ function Members ({ className }: Props): React.ReactElement<Props> {
|
||||
|
||||
const hdrRef = useRef([
|
||||
[t<string>('members'), 'start', 2],
|
||||
[t<string>('role'), 'number']
|
||||
[t<string>('deposit'), 'number'],
|
||||
[t<string>('role'), 'number'],
|
||||
[]
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
@ -2,8 +2,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { PalletAllianceMemberRole } from '@polkadot/types/lookup';
|
||||
import type { BN } from '@polkadot/util';
|
||||
|
||||
export interface Member {
|
||||
accountId: string;
|
||||
role: PalletAllianceMemberRole['type'];
|
||||
}
|
||||
|
||||
export interface MemberInfo {
|
||||
accountId: string;
|
||||
deposit?: BN | null;
|
||||
isUpForKicking: boolean;
|
||||
}
|
||||
|
||||
29
packages/page-alliance/src/useMemberInfo.ts
Normal file
29
packages/page-alliance/src/useMemberInfo.ts
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2017-2022 @polkadot/app-alliance authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { bool, Option, UInt } from '@polkadot/types';
|
||||
import type { MemberInfo } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
function useMemberInfoImpl (accountId: string): MemberInfo | undefined {
|
||||
const { api } = useApi();
|
||||
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]);
|
||||
}
|
||||
|
||||
export default createNamedHook('useMemberInfo', useMemberInfoImpl);
|
||||
@ -4,18 +4,28 @@
|
||||
import type { AccountId32 } from '@polkadot/types/interfaces';
|
||||
import type { Member } from './types';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { createNamedHook, useApi, useCallMulti } from '@polkadot/react-hooks';
|
||||
|
||||
const ROLES = <const> ['Founder', 'Fellow', 'Ally'];
|
||||
|
||||
function addMembers (all: Member[], role: Member['role'], accountIds: AccountId32[] = []): Member[] {
|
||||
for (let i = 0; i < accountIds.length; i++) {
|
||||
all.push({
|
||||
accountId: accountIds[i].toString(),
|
||||
role
|
||||
});
|
||||
function addMembers (prev: Member[] = [], query: AccountId32[][]): Member[] {
|
||||
const all: Member[] = [];
|
||||
|
||||
for (let i = 0; i < ROLES.length; i++) {
|
||||
const role = ROLES[i];
|
||||
const accountIds = query[i];
|
||||
|
||||
for (let j = 0; j < accountIds.length; j++) {
|
||||
const accountId = accountIds[j].toString();
|
||||
const existing = prev.find((p) => p.accountId === accountId && p.role === role);
|
||||
|
||||
all.push(existing || {
|
||||
accountId,
|
||||
role
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return all;
|
||||
@ -23,25 +33,19 @@ function addMembers (all: Member[], role: Member['role'], accountIds: AccountId3
|
||||
|
||||
function useMembersImpl (): Member[] | undefined {
|
||||
const { api } = useApi();
|
||||
const [state, setState] = useState<Member[] | undefined>();
|
||||
const query = useCallMulti<AccountId32[][]>([
|
||||
[api.query.alliance.members, ROLES[0]],
|
||||
[api.query.alliance.members, ROLES[1]],
|
||||
[api.query.alliance.members, ROLES[2]]
|
||||
]);
|
||||
|
||||
return useMemo((): Member[] | undefined => {
|
||||
if (query && query.length === ROLES.length) {
|
||||
const all: Member[] = [];
|
||||
|
||||
for (let i = 0; i < ROLES.length; i++) {
|
||||
addMembers(all, ROLES[i], query[i]);
|
||||
}
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
useEffect((): void => {
|
||||
query && query.length === ROLES.length &&
|
||||
setState((prev) => addMembers(prev, query));
|
||||
}, [query]);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export default createNamedHook('useMembersImpl', useMembersImpl);
|
||||
export default createNamedHook('useMembers', useMembersImpl);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user