Turn SideBar transfer into modal link (#1217)
* Turn SideBar transfer into modal link * ui--RecentlyOffline badge location
This commit is contained in:
parent
1bb275fb15
commit
5b5ab129d3
@ -20,7 +20,7 @@ import { ZERO_FEES } from '@polkadot/ui-signer/Checks/constants';
|
||||
import translate from '../translate';
|
||||
|
||||
type Props = ApiProps & I18nProps & {
|
||||
address: string,
|
||||
address?: string,
|
||||
balances_fees?: DerivedFees,
|
||||
balances_votingBalance?: DerivedBalances,
|
||||
onClose: () => void,
|
||||
@ -32,8 +32,8 @@ type State = {
|
||||
extrinsic: SubmittableExtrinsic | null,
|
||||
hasAvailable: boolean,
|
||||
maxBalance?: BN,
|
||||
recipientId: string | null,
|
||||
senderId: string
|
||||
recipientId?: string | null,
|
||||
senderId?: string | null
|
||||
};
|
||||
|
||||
const ZERO = new BN(0);
|
||||
@ -77,7 +77,7 @@ class Transfer extends React.PureComponent<Props> {
|
||||
hasAvailable: true,
|
||||
maxBalance: ZERO,
|
||||
recipientId: null,
|
||||
senderId: props.address
|
||||
senderId: props.address || null
|
||||
};
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ class Transfer extends React.PureComponent<Props> {
|
||||
this.setState((prevState: State): State => {
|
||||
const { api } = this.props;
|
||||
const { amount = prevState.amount, recipientId = prevState.recipientId, hasAvailable = prevState.hasAvailable, maxBalance = prevState.maxBalance, senderId = prevState.senderId } = newState;
|
||||
const extrinsic = recipientId
|
||||
const extrinsic = recipientId && senderId
|
||||
? api.tx.balances.transfer(recipientId, amount)
|
||||
: null;
|
||||
|
||||
@ -131,8 +131,8 @@ class Transfer extends React.PureComponent<Props> {
|
||||
}
|
||||
|
||||
private renderButtons () {
|
||||
const { address, onClose, t } = this.props;
|
||||
const { extrinsic, hasAvailable } = this.state;
|
||||
const { onClose, t } = this.props;
|
||||
const { extrinsic, hasAvailable, senderId } = this.state;
|
||||
|
||||
return (
|
||||
<Modal.Actions>
|
||||
@ -144,7 +144,7 @@ class Transfer extends React.PureComponent<Props> {
|
||||
/>
|
||||
<Button.Or />
|
||||
<TxButton
|
||||
accountId={address}
|
||||
accountId={senderId}
|
||||
extrinsic={extrinsic}
|
||||
isDisabled={!hasAvailable}
|
||||
isPrimary
|
||||
@ -168,8 +168,9 @@ class Transfer extends React.PureComponent<Props> {
|
||||
<InputAddress
|
||||
defaultValue={address}
|
||||
help={t('The account you will send funds from.')}
|
||||
isDisabled
|
||||
isDisabled={!!address}
|
||||
label={t('send from account')}
|
||||
onChange={this.onChangeFrom}
|
||||
type='account'
|
||||
/>
|
||||
<div className='balance'><Available label={available} params={senderId} /></div>
|
||||
@ -189,7 +190,7 @@ class Transfer extends React.PureComponent<Props> {
|
||||
withMax
|
||||
/>
|
||||
<Checks
|
||||
accountId={address}
|
||||
accountId={senderId}
|
||||
extrinsic={extrinsic}
|
||||
isSendable
|
||||
onChange={this.onChangeFees}
|
||||
@ -203,6 +204,10 @@ class Transfer extends React.PureComponent<Props> {
|
||||
this.nextState({ amount });
|
||||
}
|
||||
|
||||
private onChangeFrom = (senderId: string) => {
|
||||
this.nextState({ senderId });
|
||||
}
|
||||
|
||||
private onChangeTo = (recipientId: string) => {
|
||||
this.nextState({ recipientId });
|
||||
}
|
||||
@ -212,10 +217,10 @@ class Transfer extends React.PureComponent<Props> {
|
||||
}
|
||||
|
||||
private setMaxBalance = async () => {
|
||||
const { address, api, balances_fees = ZERO_FEES } = this.props;
|
||||
const { recipientId } = this.state;
|
||||
const { api, balances_fees = ZERO_FEES } = this.props;
|
||||
const { senderId, recipientId } = this.state;
|
||||
|
||||
if (!address || !recipientId) {
|
||||
if (!senderId || !recipientId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -224,8 +229,8 @@ class Transfer extends React.PureComponent<Props> {
|
||||
// FIXME The any casts here are irritating, but they are basically caused by the derive
|
||||
// not really returning an actual `class implements Codec`
|
||||
// (if casting to DerivedBalance it would be `as any as DerivedBalance`)
|
||||
const accountNonce = await api.query.system.accountNonce(address) as Index;
|
||||
const senderBalance = (await api.derive.balances.all(address) as any).availableBalance;
|
||||
const accountNonce = await api.query.system.accountNonce(senderId) as Index;
|
||||
const senderBalance = (await api.derive.balances.all(senderId) as any).availableBalance;
|
||||
const recipientBalance = (await api.derive.balances.all(recipientId) as any).availableBalance;
|
||||
|
||||
let prevMax = new BN(0);
|
||||
|
||||
@ -1,243 +0,0 @@
|
||||
// Copyright 2017-2019 @polkadot/app-transfer 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 { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { ApiProps } from '@polkadot/ui-api/types';
|
||||
import { DerivedFees, DerivedBalances } from '@polkadot/api-derive/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
|
||||
import { Index } from '@polkadot/types';
|
||||
import { AddressRow, Button, InputAddress, InputBalance, TxButton, TxComponent } from '@polkadot/ui-app';
|
||||
import { withApi, withCalls, withMulti } from '@polkadot/ui-api';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import Checks, { calcSignatureLength } from '@polkadot/ui-signer/Checks';
|
||||
import { ZERO_FEES } from '@polkadot/ui-signer/Checks/constants';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & ApiProps & {
|
||||
balances_fees?: DerivedFees,
|
||||
balances_votingBalance?: DerivedBalances
|
||||
};
|
||||
|
||||
type State = {
|
||||
accountId: string | null,
|
||||
amount: BN,
|
||||
extrinsic: SubmittableExtrinsic | null,
|
||||
hasAvailable: boolean,
|
||||
maxBalance?: BN,
|
||||
recipientId: string | null
|
||||
};
|
||||
|
||||
const ZERO = new BN(0);
|
||||
|
||||
const Wrapper = styled.div`
|
||||
.transfer--Transfer-address {
|
||||
flex: 0 1;
|
||||
padding: 1.5rem 0;
|
||||
|
||||
.ui--AddressSummary {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.transfer--Transfer-data {
|
||||
flex: 1 1;
|
||||
min-width: 0;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.transfer--Transfer-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
`;
|
||||
|
||||
class Transfer extends TxComponent<Props, State> {
|
||||
state: State = {
|
||||
accountId: null,
|
||||
amount: ZERO,
|
||||
extrinsic: null,
|
||||
hasAvailable: true,
|
||||
maxBalance: ZERO,
|
||||
recipientId: null
|
||||
};
|
||||
|
||||
componentDidUpdate (prevProps: Props, prevState: State) {
|
||||
const { balances_fees } = this.props;
|
||||
const { accountId, extrinsic, recipientId } = this.state;
|
||||
|
||||
const hasLengthChanged = ((extrinsic && extrinsic.encodedLength) || 0) !== ((prevState.extrinsic && prevState.extrinsic.encodedLength) || 0);
|
||||
|
||||
if ((accountId && prevState.accountId !== accountId) ||
|
||||
(recipientId && prevState.recipientId !== recipientId) ||
|
||||
(balances_fees !== prevProps.balances_fees) ||
|
||||
hasLengthChanged
|
||||
) {
|
||||
this.setMaxBalance().catch(console.error);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { t } = this.props;
|
||||
const { accountId, extrinsic, recipientId, hasAvailable, maxBalance } = this.state;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<div className='transfer--Transfer-info'>
|
||||
{this.renderAddress(accountId, 'medium')}
|
||||
<div className='transfer--Transfer-data'>
|
||||
<InputAddress
|
||||
help={t('Select the account you want to send funds from.')}
|
||||
label={t('from')}
|
||||
onChange={this.onChangeFrom}
|
||||
type='account'
|
||||
/>
|
||||
<InputAddress
|
||||
help={t('Select a contact or paste the address you want to send funds to.')}
|
||||
label={t('to')}
|
||||
onChange={this.onChangeTo}
|
||||
type='all'
|
||||
/>
|
||||
<InputBalance
|
||||
autoFocus
|
||||
help={t('Type the amount you want to transfer. Note that you can select the unit on the right e.g sending 1 mili is equivalent to sending 0.001.')}
|
||||
isError={!hasAvailable}
|
||||
label={t('amount')}
|
||||
maxValue={maxBalance}
|
||||
onChange={this.onChangeAmount}
|
||||
onEnter={this.sendTx}
|
||||
withMax
|
||||
/>
|
||||
<Checks
|
||||
accountId={accountId}
|
||||
extrinsic={extrinsic}
|
||||
isSendable
|
||||
onChange={this.onChangeFees}
|
||||
/>
|
||||
<Button.Group>
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
isDisabled={!hasAvailable}
|
||||
isPrimary
|
||||
label={t('Make Transfer')}
|
||||
extrinsic={extrinsic}
|
||||
ref={this.button}
|
||||
/>
|
||||
</Button.Group>
|
||||
</div>
|
||||
{this.renderAddress(recipientId, 'large')}
|
||||
</div>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
private renderAddress (accountId: string | null, media: 'large' | 'medium') {
|
||||
if (!accountId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
keyring.decodeAddress(accountId);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`transfer--Transfer-address ui--media-${media}`}>
|
||||
<AddressRow
|
||||
value={accountId}
|
||||
withAvailable
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private nextState (newState: Partial<State>): void {
|
||||
this.setState((prevState: State): State => {
|
||||
const { api } = this.props;
|
||||
const { accountId = prevState.accountId, amount = prevState.amount, recipientId = prevState.recipientId, hasAvailable = prevState.hasAvailable, maxBalance = prevState.maxBalance } = newState;
|
||||
const extrinsic = accountId && recipientId
|
||||
? api.tx.balances.transfer(recipientId, amount)
|
||||
: null;
|
||||
|
||||
return {
|
||||
accountId,
|
||||
amount,
|
||||
extrinsic,
|
||||
hasAvailable,
|
||||
maxBalance,
|
||||
recipientId
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private setMaxBalance = async () => {
|
||||
const { api, balances_fees = ZERO_FEES } = this.props;
|
||||
const { accountId, recipientId } = this.state;
|
||||
|
||||
if (!accountId || !recipientId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { transferFee, transactionBaseFee, transactionByteFee, creationFee } = balances_fees;
|
||||
|
||||
// FIXME The any casts here are irritating, but they are basically caused by the derive
|
||||
// not really returning an actual `class implements Codec`
|
||||
// (if casting to DerivedBalance it would be `as any as DerivedBalance`)
|
||||
const accountNonce = await api.query.system.accountNonce(accountId) as Index;
|
||||
const senderBalance = (await api.derive.balances.all(accountId) as any).availableBalance;
|
||||
const recipientBalance = (await api.derive.balances.all(recipientId) as any).availableBalance;
|
||||
|
||||
let prevMax = new BN(0);
|
||||
let maxBalance = new BN(1);
|
||||
let extrinsic;
|
||||
|
||||
while (!prevMax.eq(maxBalance)) {
|
||||
prevMax = maxBalance;
|
||||
extrinsic = api.tx.balances.transfer(recipientId, prevMax);
|
||||
|
||||
const txLength = calcSignatureLength(extrinsic, accountNonce);
|
||||
const fees = transactionBaseFee
|
||||
.add(transactionByteFee.muln(txLength))
|
||||
.add(transferFee)
|
||||
.add(recipientBalance.isZero() ? creationFee : ZERO);
|
||||
|
||||
maxBalance = senderBalance.sub(fees);
|
||||
}
|
||||
|
||||
this.nextState({
|
||||
extrinsic,
|
||||
maxBalance
|
||||
});
|
||||
}
|
||||
|
||||
private onChangeFrom = (accountId: string) => {
|
||||
this.nextState({ accountId });
|
||||
}
|
||||
|
||||
private onChangeAmount = (amount: BN = new BN(0)) => {
|
||||
this.nextState({ amount });
|
||||
}
|
||||
|
||||
private onChangeTo = (recipientId: string) => {
|
||||
this.nextState({ recipientId });
|
||||
}
|
||||
|
||||
private onChangeFees = (hasAvailable: boolean) => {
|
||||
this.setState({ hasAvailable });
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Transfer,
|
||||
translate,
|
||||
withApi,
|
||||
withCalls<Props>(
|
||||
'derive.balances.fees'
|
||||
)
|
||||
);
|
||||
@ -2,37 +2,14 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AppProps, I18nProps } from '@polkadot/ui-app/types';
|
||||
import { AppProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import React from 'react';
|
||||
import { HelpOverlay,Tabs } from '@polkadot/ui-app';
|
||||
|
||||
import basicMd from './md/basic.md';
|
||||
import Transfer from './Transfer';
|
||||
import translate from './translate';
|
||||
type Props = AppProps;
|
||||
|
||||
type Props = AppProps & I18nProps;
|
||||
|
||||
class App extends React.PureComponent<Props> {
|
||||
export default class App extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { basePath, t } = this.props;
|
||||
|
||||
return (
|
||||
<main className='transfer--App'>
|
||||
<HelpOverlay md={basicMd} />
|
||||
<header>
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
items={[{
|
||||
name: 'create',
|
||||
text: t('Balance transfer')
|
||||
}]}
|
||||
/>
|
||||
</header>
|
||||
<Transfer />
|
||||
</main>
|
||||
);
|
||||
return 'Deprecated, now operates via modal';
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(App);
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
# Transfer
|
||||
|
||||
This tab allows you to send funds from one account you own to another account.
|
||||
|
||||
# Minimum allowed balance
|
||||
|
||||
Accounts with a balance lower than the minimal amount, 100 miliUnits (miliDOTs for Polkadot) as of writing, are considered as inexistent for the network. If an account's balance ever drops below this amount, it is removed from the network. In this application, it will still be visible, but with a balance of 0.
|
||||
|
||||
For a fund transfer to a **new account** (read an account with a balance of 0), if the amount transferred is less than the minimum allowed balance, then the transfer will "succeed" but the destination account will not be created (read its balance will remain 0); this essentially burns the transfer balance from the sender, because the receiver's balance never exceed the minimum allowed balance.
|
||||
|
||||
If the receiver already exists (read it has a balance greater than 0), it is perfectly possible to transfer very low amounts.
|
||||
|
||||
# Fees
|
||||
|
||||
Fees will be added to the transfer amount on top of the amount you wish to send.
|
||||
An information box will show you the amount of fees that you will need to pay for the transfer and the total amount that will be deducted from the sender.
|
||||
|
||||
- transfer:
|
||||
You need to pay fees to transfer funds from one account to the other in order to pay for the security of the network.
|
||||
|
||||
- account creation
|
||||
In addition to the transfer fees, if you are sending funds to an account with a 0 balance, not only do you need to make sure to send enough funds (see the "minimum allowed balance" section) but you will need to pay a creation fee. This is to prevent the generation of unused account.
|
||||
@ -1,7 +0,0 @@
|
||||
// Copyright 2017-2019 @polkadot/app-transfer 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 { withTranslation } from 'react-i18next';
|
||||
|
||||
export default withTranslation(['transfer', 'ui']);
|
||||
@ -5,10 +5,12 @@
|
||||
import { Routes } from './types';
|
||||
|
||||
import Transfer from '@polkadot/app-transfer';
|
||||
import TransferModal from '@polkadot/app-accounts/modals/Transfer';
|
||||
|
||||
export default ([
|
||||
{
|
||||
Component: Transfer,
|
||||
Modal: TransferModal,
|
||||
display: {
|
||||
isHidden: false,
|
||||
needsAccounts: true,
|
||||
|
||||
@ -9,8 +9,10 @@ export type RouteProps = AppProps & BareProps;
|
||||
|
||||
export type Route = {
|
||||
Component: React.ComponentType<RouteProps>,
|
||||
Modal?: React.ComponentType<any>,
|
||||
display: {
|
||||
isHidden?: boolean,
|
||||
isModal?: boolean,
|
||||
needsAccounts?: boolean,
|
||||
needsApi?: Array<string | Array<string>>,
|
||||
needsSudo?: boolean
|
||||
|
||||
@ -14,6 +14,8 @@ import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
import { withApi,withCalls, withMulti, withObservable } from '@polkadot/ui-api';
|
||||
import { isFunction } from '@polkadot/util';
|
||||
|
||||
import translate from '../translate';
|
||||
|
||||
type Props = I18nProps & ApiProps & {
|
||||
isCollapsed: boolean,
|
||||
onClick: () => void,
|
||||
@ -24,32 +26,54 @@ type Props = I18nProps & ApiProps & {
|
||||
|
||||
class Item extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { route: { i18n, icon, name }, t, isCollapsed } = this.props;
|
||||
const { route: { Modal, i18n, icon, name }, t, isCollapsed, onClick } = this.props;
|
||||
|
||||
if (!this.isVisible()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const body = (
|
||||
<>
|
||||
<Icon name={icon} />
|
||||
<span className='text'>{t(`sidebar.${name}`, i18n)}</span>
|
||||
<Tooltip
|
||||
offset={{ right: -4 }}
|
||||
place='right'
|
||||
text={t(`sidebar.${name}`, i18n)}
|
||||
trigger={`nav-${name}`}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Menu.Item className='apps--SideBar-Item'>
|
||||
<NavLink
|
||||
activeClassName='apps--SideBar-Item-NavLink-active'
|
||||
className='apps--SideBar-Item-NavLink'
|
||||
data-for={`nav-${name}`}
|
||||
data-tip
|
||||
data-tip-disable={!isCollapsed}
|
||||
onClick={this.props.onClick}
|
||||
to={`/${name}`}
|
||||
>
|
||||
<Icon name={icon} />
|
||||
<span className='text'>{t(`sidebar.${name}`, i18n)}</span>
|
||||
<Tooltip
|
||||
offset={{ right: -4 }}
|
||||
place='right'
|
||||
text={t(`sidebar.${name}`, i18n)}
|
||||
trigger={`nav-${name}`}
|
||||
/>
|
||||
</NavLink>
|
||||
{
|
||||
Modal
|
||||
? (
|
||||
<a
|
||||
className='apps--SideBar-Item-NavLink'
|
||||
data-for={`nav-${name}`}
|
||||
data-tip
|
||||
data-tip-disable={!isCollapsed}
|
||||
onClick={onClick}
|
||||
>
|
||||
{body}
|
||||
</a>
|
||||
)
|
||||
: (
|
||||
<NavLink
|
||||
activeClassName='apps--SideBar-Item-NavLink-active'
|
||||
className='apps--SideBar-Item-NavLink'
|
||||
data-for={`nav-${name}`}
|
||||
data-tip
|
||||
data-tip-disable={!isCollapsed}
|
||||
onClick={onClick}
|
||||
to={`/${name}`}
|
||||
>
|
||||
{body}
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
@ -103,6 +127,7 @@ class Item extends React.PureComponent<Props> {
|
||||
|
||||
export default withMulti(
|
||||
Item,
|
||||
translate,
|
||||
withApi,
|
||||
withCalls<Props>(
|
||||
['query.sudo.key', { transform: key => key.toString() }]
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Route } from '@polkadot/apps-routing/types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { SIDEBAR_MENU_THRESHOLD } from '../constants';
|
||||
|
||||
@ -28,6 +29,12 @@ type Props = I18nProps & {
|
||||
toggleMenu: () => void
|
||||
};
|
||||
|
||||
type State = {
|
||||
modals: {
|
||||
[index: string]: boolean
|
||||
}
|
||||
};
|
||||
|
||||
const Toggle = styled.img`
|
||||
background: ${logoBackground};
|
||||
padding: ${logoPadding};
|
||||
@ -54,21 +61,40 @@ const Toggle = styled.img`
|
||||
`}
|
||||
`;
|
||||
|
||||
class SideBar extends React.PureComponent<Props> {
|
||||
class SideBar extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
// setup modals for each of the actual modal routes
|
||||
this.state = {
|
||||
modals: routing.routes.reduce((result, route) => {
|
||||
if (route && route.Modal) {
|
||||
result[route.name] = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {} as { [index: string]: boolean })
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { isCollapsed } = this.props;
|
||||
const { handleResize, isCollapsed, toggleMenu, menuOpen } = this.props;
|
||||
const logo = getLogo(true);
|
||||
|
||||
return (
|
||||
<Responsive
|
||||
onUpdate={this.props.handleResize}
|
||||
className={
|
||||
classes(
|
||||
'apps-SideBar-Wrapper',
|
||||
isCollapsed ? 'collapsed' : 'expanded'
|
||||
)
|
||||
}
|
||||
onUpdate={handleResize}
|
||||
className={classes('apps-SideBar-Wrapper', isCollapsed ? 'collapsed' : 'expanded')}
|
||||
>
|
||||
{this.renderMenuToggle()}
|
||||
<Toggle
|
||||
alt='logo'
|
||||
className={menuOpen ? 'closed' : 'open delayed'}
|
||||
onClick={toggleMenu}
|
||||
src={logo}
|
||||
/>
|
||||
{this.renderModals()}
|
||||
<div className='apps--SideBar'>
|
||||
<Menu
|
||||
secondary
|
||||
@ -83,13 +109,18 @@ class SideBar extends React.PureComponent<Props> {
|
||||
<Menu.Divider hidden />
|
||||
{
|
||||
isCollapsed
|
||||
? null
|
||||
? undefined
|
||||
: <NodeInfo />
|
||||
}
|
||||
</div>
|
||||
{this.renderCollapse()}
|
||||
</Menu>
|
||||
{this.renderToggleBar()}
|
||||
<Responsive minWidth={SIDEBAR_MENU_THRESHOLD}>
|
||||
<div
|
||||
className='apps--SideBar-toggle'
|
||||
onClick={this.props.collapse}
|
||||
/>
|
||||
</Responsive>
|
||||
</div>
|
||||
</Responsive>
|
||||
);
|
||||
@ -126,9 +157,24 @@ class SideBar extends React.PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderModals () {
|
||||
const { modals } = this.state;
|
||||
const filtered = routing.routes.filter((route) => route && route.Modal) as Array<Route>;
|
||||
|
||||
return filtered.map(({ name, Modal }) => (
|
||||
Modal && modals[name]
|
||||
? (
|
||||
<Modal
|
||||
key={name}
|
||||
onClose={this.closeModal(name)}
|
||||
/>
|
||||
)
|
||||
: <div key={name} />
|
||||
));
|
||||
}
|
||||
|
||||
private renderRoutes () {
|
||||
const { isCollapsed } = this.props;
|
||||
const { t } = this.props;
|
||||
const { handleResize, isCollapsed } = this.props;
|
||||
|
||||
return routing.routes.map((route, index) => (
|
||||
route
|
||||
@ -137,8 +183,11 @@ class SideBar extends React.PureComponent<Props> {
|
||||
isCollapsed={isCollapsed}
|
||||
key={route.name}
|
||||
route={route}
|
||||
onClick={this.props.handleResize}
|
||||
t={t}
|
||||
onClick={
|
||||
route.Modal
|
||||
? this.openModal(route.name)
|
||||
: handleResize
|
||||
}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
@ -164,32 +213,6 @@ class SideBar extends React.PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderToggleBar () {
|
||||
return (
|
||||
<Responsive minWidth={SIDEBAR_MENU_THRESHOLD}>
|
||||
<div
|
||||
className='apps--SideBar-toggle'
|
||||
onClick={this.props.collapse}
|
||||
>
|
||||
</div>
|
||||
</Responsive>
|
||||
);
|
||||
}
|
||||
|
||||
private renderMenuToggle () {
|
||||
const logo = getLogo(true);
|
||||
const { toggleMenu, menuOpen } = this.props;
|
||||
|
||||
return (
|
||||
<Toggle
|
||||
alt='logo'
|
||||
className={menuOpen ? 'closed' : 'open delayed'}
|
||||
onClick={toggleMenu}
|
||||
src={logo}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderWiki () {
|
||||
return (
|
||||
<Menu.Item className='apps--SideBar-Item'>
|
||||
@ -203,6 +226,28 @@ class SideBar extends React.PureComponent<Props> {
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
|
||||
private closeModal = (name: string) => {
|
||||
return () => {
|
||||
this.setState(({ modals }) => ({
|
||||
modals: {
|
||||
...modals,
|
||||
[name]: false
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
private openModal = (name: string) => {
|
||||
return () => {
|
||||
this.setState(({ modals }) => ({
|
||||
modals: {
|
||||
...modals,
|
||||
[name]: true
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(SideBar);
|
||||
|
||||
@ -17,6 +17,10 @@ body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
color: rgba(0, 0, 0, .6);
|
||||
font-family: sans-serif;
|
||||
|
||||
@ -437,12 +437,12 @@ button.ui.icon.iconButton {
|
||||
|
||||
.ui--RecentlyOffline {
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
top: -0.5rem;
|
||||
font-size: 12px;
|
||||
cursor: help;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
left: 0.75rem;
|
||||
left: -0.5rem;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
padding: 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user