Split society candidates (#4857)
* Split society candidates * trigger * head * Head to top * loading * Unneeded ?.
This commit is contained in:
parent
1245eb2118
commit
5437017736
@ -1,3 +1,3 @@
|
||||
18
|
||||
19
|
||||
0.45.2
|
||||
0.71.2
|
||||
|
||||
@ -12,8 +12,8 @@ import { AddressSmall } from '@polkadot/react-components';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { FormatBalance } from '@polkadot/react-query';
|
||||
|
||||
import Votes from '../Overview/Votes';
|
||||
import CandidateVoting from './CandidateVoting';
|
||||
import Votes from './Votes';
|
||||
|
||||
interface Props {
|
||||
allMembers: string[];
|
||||
47
packages/page-society/src/Candidates/index.tsx
Normal file
47
packages/page-society/src/Candidates/index.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2017-2021 @polkadot/app-society authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Button } from '@polkadot/react-components';
|
||||
import { useToggle } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import BidNew from './BidNew';
|
||||
import Bids from './Bids';
|
||||
import AllCandidates from './Candidates';
|
||||
|
||||
interface Props {
|
||||
allMembers: string[];
|
||||
className?: string;
|
||||
isMember: boolean;
|
||||
ownMembers: string[];
|
||||
}
|
||||
|
||||
function Candidates ({ allMembers, className = '', isMember, ownMembers }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const [isBidOpen, toggleBidOpen] = useToggle();
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon='plus'
|
||||
label={t<string>('Submit bid')}
|
||||
onClick={toggleBidOpen}
|
||||
/>
|
||||
{isBidOpen && (
|
||||
<BidNew onClose={toggleBidOpen} />
|
||||
)}
|
||||
</Button.Group>
|
||||
<AllCandidates
|
||||
allMembers={allMembers}
|
||||
isMember={isMember}
|
||||
ownMembers={ownMembers}
|
||||
/>
|
||||
<Bids />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Candidates);
|
||||
@ -28,19 +28,29 @@ function Members ({ className = '', info }: Props): React.ReactElement<Props> {
|
||||
]);
|
||||
|
||||
const filtered = useMemo(
|
||||
() => (members || []).filter((member) => !info || !info.hasDefender || !member.accountId.eq(info.defender)),
|
||||
() => members && info
|
||||
? members
|
||||
.filter((member) => !info.hasDefender || !member.accountId.eq(info.defender))
|
||||
.sort((a, b) =>
|
||||
!info.head?.eq(a.accountId)
|
||||
? 1
|
||||
: !info.head?.eq(b.accountId)
|
||||
? -1
|
||||
: 0
|
||||
)
|
||||
: undefined,
|
||||
[info, members]
|
||||
);
|
||||
|
||||
return (
|
||||
<Table
|
||||
className={className}
|
||||
empty={info && t<string>('No active members')}
|
||||
empty={info && filtered && t<string>('No active members')}
|
||||
header={headerRef.current}
|
||||
>
|
||||
{filtered.map((member): React.ReactNode => (
|
||||
{info && filtered && filtered.map((member): React.ReactNode => (
|
||||
<Member
|
||||
isHead={info?.head?.eq(member.accountId)}
|
||||
isHead={info.head?.eq(member.accountId)}
|
||||
key={member.accountId.toString()}
|
||||
value={member}
|
||||
/>
|
||||
|
||||
@ -6,54 +6,31 @@ import type { DeriveSociety } from '@polkadot/api-derive/types';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Button } from '@polkadot/react-components';
|
||||
import { useApi, useCall, useToggle } from '@polkadot/react-hooks';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import useMembers from '../useMembers';
|
||||
import BidNew from './BidNew';
|
||||
import Bids from './Bids';
|
||||
import Candidates from './Candidates';
|
||||
import Defender from './Defender';
|
||||
import Members from './Members';
|
||||
import Summary from './Summary';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
isMember: boolean;
|
||||
ownMembers: string[];
|
||||
}
|
||||
|
||||
function Overview ({ className }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
function Overview ({ className, isMember, ownMembers }: Props): React.ReactElement<Props> {
|
||||
const { api } = useApi();
|
||||
const info = useCall<DeriveSociety>(api.derive.society.info);
|
||||
const { allMembers, isMember, ownMembers } = useMembers();
|
||||
const [isBidOpen, toggleBidOpen] = useToggle();
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Summary info={info} />
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon='plus'
|
||||
label={t<string>('Submit bid')}
|
||||
onClick={toggleBidOpen}
|
||||
/>
|
||||
{isBidOpen && (
|
||||
<BidNew onClose={toggleBidOpen} />
|
||||
)}
|
||||
</Button.Group>
|
||||
<Defender
|
||||
info={info}
|
||||
isMember={isMember}
|
||||
ownMembers={ownMembers}
|
||||
/>
|
||||
<Members info={info} />
|
||||
<Candidates
|
||||
allMembers={allMembers}
|
||||
isMember={isMember}
|
||||
ownMembers={ownMembers}
|
||||
/>
|
||||
<Bids />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
// Copyright 2017-2021 @polkadot/app-society authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
|
||||
import { Tabs } from '@polkadot/react-components';
|
||||
|
||||
import Candidates from './Candidates';
|
||||
import Overview from './Overview';
|
||||
import { useTranslation } from './translate';
|
||||
import useCounter from './useCounter';
|
||||
import useMembers from './useMembers';
|
||||
|
||||
interface Props {
|
||||
basePath: string;
|
||||
@ -19,25 +21,44 @@ export { useCounter };
|
||||
|
||||
function SocietyApp ({ basePath, className }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const candidateCount = useCounter();
|
||||
const { allMembers, isMember, ownMembers } = useMembers();
|
||||
|
||||
const itemsRef = useRef([
|
||||
const items = useMemo(() => [
|
||||
{
|
||||
isRoot: true,
|
||||
name: 'overview',
|
||||
text: t<string>('Society overview')
|
||||
},
|
||||
{
|
||||
count: candidateCount,
|
||||
name: 'candidates',
|
||||
text: t<string>('Candidates')
|
||||
}
|
||||
]);
|
||||
], [candidateCount, t]);
|
||||
|
||||
return (
|
||||
<main className={className}>
|
||||
<header>
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
items={itemsRef.current}
|
||||
items={items}
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
<Route component={Overview} />
|
||||
<Route path={`${basePath}/candidates`}>
|
||||
<Candidates
|
||||
allMembers={allMembers}
|
||||
isMember={isMember}
|
||||
ownMembers={ownMembers}
|
||||
/>
|
||||
</Route>
|
||||
<Route>
|
||||
<Overview
|
||||
isMember={isMember}
|
||||
ownMembers={ownMembers}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
</main>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user