Payout button for society (#4890)
* Add society payout button * Split kusama design modal * payout tag * Adjust design size
This commit is contained in:
parent
cdbb596656
commit
5a5ec76eb8
77
packages/page-society/src/Overview/DesignKusama.tsx
Normal file
77
packages/page-society/src/Overview/DesignKusama.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2017-2021 @polkadot/app-society authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { AccountId } from '@polkadot/types/interfaces';
|
||||
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { KUSAMA_GENESIS } from '@polkadot/apps-config';
|
||||
import { Button, Modal } from '@polkadot/react-components';
|
||||
import { useApi, useToggle } from '@polkadot/react-hooks';
|
||||
|
||||
import drawCanary, { PADD, SIZE } from '../draw/canary';
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
accountId: AccountId;
|
||||
}
|
||||
|
||||
const CANVAS_STYLE = {
|
||||
display: 'block',
|
||||
margin: '0 auto'
|
||||
};
|
||||
|
||||
const HEIGHT = (SIZE * 2) + (PADD * 1);
|
||||
const WIDTH = (SIZE * 3) + (PADD * 2);
|
||||
|
||||
function DesignKusama ({ accountId }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const [onKusama] = useState(() => api.genesisHash.eq(KUSAMA_GENESIS));
|
||||
const [isShowing, toggleDesign] = useToggle();
|
||||
|
||||
useEffect((): void => {
|
||||
if (canvasRef.current) {
|
||||
const ctx = canvasRef.current.getContext('2d');
|
||||
|
||||
if (ctx) {
|
||||
drawCanary(ctx, accountId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!onKusama) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
icon='pen-nib'
|
||||
onClick={toggleDesign}
|
||||
/>
|
||||
{isShowing && (
|
||||
<Modal
|
||||
header={t('design samples')}
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
<canvas
|
||||
height={HEIGHT}
|
||||
ref={canvasRef}
|
||||
style={CANVAS_STYLE}
|
||||
width={WIDTH}
|
||||
/>
|
||||
</Modal.Content>
|
||||
<Modal.Actions
|
||||
cancelLabel={t<string>('Close')}
|
||||
onCancel={toggleDesign}
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(DesignKusama);
|
||||
@ -5,17 +5,16 @@ import type BN from 'bn.js';
|
||||
import type { Balance, BlockNumber } from '@polkadot/types/interfaces';
|
||||
import type { MapMember } from '../types';
|
||||
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { KUSAMA_GENESIS } from '@polkadot/apps-config';
|
||||
import { AddressSmall, Columar, Expander, Icon, Modal, Tag } from '@polkadot/react-components';
|
||||
import { useApi, useToggle } from '@polkadot/react-hooks';
|
||||
import { AddressSmall, Columar, Expander, Tag, TxButton } from '@polkadot/react-components';
|
||||
import { useAccounts, useApi } from '@polkadot/react-hooks';
|
||||
import { BlockToTime, FormatBalance } from '@polkadot/react-query';
|
||||
import { formatNumber } from '@polkadot/util';
|
||||
|
||||
import drawCanary from '../draw/canary';
|
||||
import { useTranslation } from '../translate';
|
||||
import DesignKusama from './DesignKusama';
|
||||
|
||||
interface Props {
|
||||
bestNumber?: BN;
|
||||
@ -23,51 +22,53 @@ interface Props {
|
||||
value: MapMember;
|
||||
}
|
||||
|
||||
const CANVAS_STYLE = {
|
||||
display: 'block',
|
||||
margin: '0 auto'
|
||||
};
|
||||
|
||||
function renderJSXPayouts (bestNumber: BN, payouts: [BlockNumber, Balance][]): JSX.Element[] {
|
||||
return payouts.map(([bn, value], index) => (
|
||||
<p key={index}>
|
||||
<div
|
||||
className='payout'
|
||||
key={index}
|
||||
>
|
||||
<Columar>
|
||||
<Columar.Column>
|
||||
<FormatBalance value={value} />
|
||||
</Columar.Column>
|
||||
<Columar.Column>
|
||||
<div>#{formatNumber(bn)}</div>
|
||||
<BlockToTime
|
||||
key={index}
|
||||
value={bn.sub(bestNumber)}
|
||||
/>
|
||||
{bn.gt(bestNumber) && (
|
||||
<BlockToTime
|
||||
key={index}
|
||||
value={bn.sub(bestNumber)}
|
||||
/>
|
||||
)}
|
||||
</Columar.Column>
|
||||
</Columar>
|
||||
</p>
|
||||
</div>
|
||||
));
|
||||
}
|
||||
|
||||
function Member ({ bestNumber, className = '', value: { isCandidateVoter, isFounder, isHead, isSkeptic, isWarned, member: { accountId, isDefenderVoter, isSuspended, payouts, strikes } } }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const [canInk] = useState(() => api.genesisHash.eq(KUSAMA_GENESIS));
|
||||
const [isInkShowing, toggleInk] = useToggle();
|
||||
const { allAccounts } = useAccounts();
|
||||
|
||||
const renderPayouts = useCallback(
|
||||
() => bestNumber && payouts && renderJSXPayouts(bestNumber, payouts),
|
||||
[bestNumber, payouts]
|
||||
);
|
||||
|
||||
useEffect((): void => {
|
||||
if (canvasRef.current) {
|
||||
const ctx = canvasRef.current.getContext('2d');
|
||||
const isMember = useMemo(
|
||||
(): boolean => {
|
||||
const address = accountId.toString();
|
||||
|
||||
if (ctx) {
|
||||
drawCanary(ctx, accountId);
|
||||
}
|
||||
}
|
||||
});
|
||||
return allAccounts.some((accountId) => accountId === address);
|
||||
},
|
||||
[allAccounts, accountId]
|
||||
);
|
||||
|
||||
const availablePayout = useMemo(
|
||||
() => bestNumber && payouts.find(([bn]) => bestNumber.gt(bn)),
|
||||
[bestNumber, payouts]
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className={className}>
|
||||
@ -101,7 +102,7 @@ function Member ({ bestNumber, className = '', value: { isCandidateVoter, isFoun
|
||||
)}
|
||||
{isWarned && (
|
||||
<Tag
|
||||
color='grey'
|
||||
color='orange'
|
||||
label={t<string>('strikes')}
|
||||
/>
|
||||
)}
|
||||
@ -111,6 +112,12 @@ function Member ({ bestNumber, className = '', value: { isCandidateVoter, isFoun
|
||||
label={t<string>('suspended')}
|
||||
/>
|
||||
)}
|
||||
{availablePayout && (
|
||||
<Tag
|
||||
color='grey'
|
||||
label={t<string>('payout')}
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
<td className='number together'>
|
||||
{!!payouts?.length && (
|
||||
@ -123,33 +130,17 @@ function Member ({ bestNumber, className = '', value: { isCandidateVoter, isFoun
|
||||
<td>{isDefenderVoter && t<string>('defender')}</td>
|
||||
<td>{isCandidateVoter && t<string>('candidate')}</td>
|
||||
<td className='number'>{formatNumber(strikes)}</td>
|
||||
<td>
|
||||
{canInk && (
|
||||
<>
|
||||
<Icon
|
||||
icon='pen-nib'
|
||||
onClick={toggleInk}
|
||||
/>
|
||||
{isInkShowing && (
|
||||
<Modal
|
||||
header={t('design samples')}
|
||||
size='large'
|
||||
>
|
||||
<Modal.Content>
|
||||
<canvas
|
||||
height={525}
|
||||
ref={canvasRef}
|
||||
style={CANVAS_STYLE}
|
||||
width={800}
|
||||
/>
|
||||
</Modal.Content>
|
||||
<Modal.Actions
|
||||
cancelLabel={t<string>('Close')}
|
||||
onCancel={toggleInk}
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
<td className='button start'>
|
||||
<DesignKusama accountId={accountId} />
|
||||
{availablePayout && (
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
icon='ellipsis-h'
|
||||
isDisabled={!isMember}
|
||||
label='Payout'
|
||||
params={[]}
|
||||
tx={api.tx.society.payout}
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
@ -157,6 +148,10 @@ function Member ({ bestNumber, className = '', value: { isCandidateVoter, isFoun
|
||||
}
|
||||
|
||||
export default React.memo(styled(Member)`
|
||||
.payout+.payout {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.ui--Column {
|
||||
min-width: 14ch;
|
||||
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
import type { AccountId } from '@polkadot/types/interfaces';
|
||||
|
||||
// const DEFAULT_FN = (ctx: CanvasRenderingContext2D, path: Path2D) => ctx.fill(path);
|
||||
const PADD = 25;
|
||||
const SIZE = 250;
|
||||
export const PADD = 25;
|
||||
export const SIZE = 300; // 250
|
||||
|
||||
function canary (ctx: CanvasRenderingContext2D, w: number, h: number, s: number, f: (ctx: CanvasRenderingContext2D, path: Path2D) => void): void {
|
||||
const path = new Path2D('M373.1,126.9c-5.2-4.1-11.4-9.7-22.7-11.1c-10.6-1.4-21.4,5.7-28.7,10.4c-7.3,4.7-21.1,18.5-26.8,22.7 c-5.7,4.2-20.3,8.1-43.8,22.2s-115.7,73.3-115.7,73.3l24,0.3L52.4,299.8h10.7l-15.4,11.7c0,0,13.6,3.6,25-3.6l0,3.3 c0,0,127.4-50.2,152-37.2l-15,4.4c1.3,0,25.5,1.6,25.5,1.6s0.8,15.1,15.4,24.8c14.6,9.6,14.9,14.9,14.9,14.9s-7.6,3.1-7.6,7 c0,0,11.2-3.4,21.6-3.1c10.4,0.3,19.5,3.1,19.5,3.1s-0.8-4.2-10.9-7c-10.2-2.9-20.1-13.8-25-19.8c-4.9-6-8.3-16.7-4.1-27.4 c3.5-9.1,15.7-14.1,40.9-27.1c29.7-15.4,36.5-26.8,40.7-35.7c4.2-8.9,10.4-26.6,13.9-34.9c4.4-10.7,9.8-16.4,14.3-19.8 c4.4-3.4,24.5-10.9,24.5-10.9S378,130.8,373.1,126.9z');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user