chore: 🔧 more bar types in channel view

This commit is contained in:
AP 2020-05-26 20:25:20 +02:00
parent bb90fbfe50
commit 9c657a416a
10 changed files with 165 additions and 63 deletions

View file

@ -1,12 +1,13 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { ChevronRight, X } from 'react-feather'; import { ChevronRight, ChevronUp, ChevronDown } from 'react-feather';
import { useAccountState } from 'src/context/AccountContext'; import { useAccountState } from 'src/context/AccountContext';
import { useChannelFeesQuery } from 'src/graphql/queries/__generated__/getChannelFees.generated'; import { useChannelFeesQuery } from 'src/graphql/queries/__generated__/getChannelFees.generated';
import { useUpdateFeesMutation } from 'src/graphql/mutations/__generated__/updateFees.generated'; import { useUpdateFeesMutation } from 'src/graphql/mutations/__generated__/updateFees.generated';
import { InputWithDeco } from 'src/components/input/InputWithDeco'; import { InputWithDeco } from 'src/components/input/InputWithDeco';
import { GridWrapper } from 'src/components/gridWrapper/GridWrapper'; import { GridWrapper } from 'src/components/gridWrapper/GridWrapper';
import { withApollo } from 'config/client'; import { withApollo } from 'config/client';
import styled from 'styled-components';
import { import {
Card, Card,
CardWithTitle, CardWithTitle,
@ -21,7 +22,10 @@ import { LoadingCard } from '../src/components/loading/LoadingCard';
import { FeeCard } from '../src/views/fees/FeeCard'; import { FeeCard } from '../src/views/fees/FeeCard';
import { SecureButton } from '../src/components/buttons/secureButton/SecureButton'; import { SecureButton } from '../src/components/buttons/secureButton/SecureButton';
import { AdminSwitch } from '../src/components/adminSwitch/AdminSwitch'; import { AdminSwitch } from '../src/components/adminSwitch/AdminSwitch';
import { ColorButton } from '../src/components/buttons/colorButton/ColorButton';
const WithPointer = styled.div`
cursor: pointer;
`;
const FeesView = () => { const FeesView = () => {
const [indexOpen, setIndexOpen] = useState(0); const [indexOpen, setIndexOpen] = useState(0);
@ -58,26 +62,28 @@ const FeesView = () => {
<CardWithTitle> <CardWithTitle>
<SubTitle>Update Channel Fees</SubTitle> <SubTitle>Update Channel Fees</SubTitle>
<Card> <Card>
<SingleLine> <WithPointer>
<SingleLine onClick={() => setIsEdit(prev => !prev)}>
<Sub4Title>Channel Fees</Sub4Title> <Sub4Title>Channel Fees</Sub4Title>
<ColorButton onClick={() => setIsEdit(prev => !prev)}> {isEdit ? <ChevronUp /> : <ChevronDown />}
{isEdit ? <X size={18} /> : 'Update'}
</ColorButton>
</SingleLine> </SingleLine>
</WithPointer>
{isEdit && ( {isEdit && (
<> <>
<Separation /> <Separation />
<InputWithDeco <InputWithDeco
title={'BaseFee'} title={'BaseFee'}
placeholder={'Sats'} placeholder={'sats'}
amount={baseFee} amount={baseFee}
override={'sat'}
inputType={'number'} inputType={'number'}
inputCallback={value => setBaseFee(Number(value))} inputCallback={value => setBaseFee(Number(value))}
/> />
<InputWithDeco <InputWithDeco
title={'Fee Rate'} title={'Fee Rate'}
placeholder={'MilliSats/Million'} placeholder={'msats/million'}
amount={feeRate / 1000} amount={feeRate / 1000}
override={'sat'}
inputType={'number'} inputType={'number'}
inputCallback={value => setFeeRate(Number(value))} inputCallback={value => setFeeRate(Number(value))}
/> />

View file

@ -29,6 +29,10 @@ export const ProgressBar = styled.div<ProgressBar>`
return chartColors.orange; return chartColors.orange;
case 4: case 4:
return progressBackground; return progressBackground;
case 5:
return chartColors.orange2;
case 6:
return chartColors.darkyellow;
default: default:
return chartColors.purple; return chartColors.purple;
} }

View file

@ -39,6 +39,7 @@ type InputWithDecoProps = {
title: string; title: string;
noInput?: boolean; noInput?: boolean;
amount?: number; amount?: number;
override?: string;
customAmount?: string; customAmount?: string;
color?: string; color?: string;
placeholder?: string; placeholder?: string;
@ -49,6 +50,7 @@ type InputWithDecoProps = {
export const InputWithDeco: React.FC<InputWithDecoProps> = ({ export const InputWithDeco: React.FC<InputWithDecoProps> = ({
title, title,
amount, amount,
override,
customAmount, customAmount,
children, children,
placeholder, placeholder,
@ -65,7 +67,11 @@ export const InputWithDeco: React.FC<InputWithDecoProps> = ({
<InputTitle>{title}</InputTitle> <InputTitle>{title}</InputTitle>
{showAmount && ( {showAmount && (
<AmountText> <AmountText>
{customAmount ? customAmount : <Price amount={amount} />} {customAmount ? (
customAmount
) : (
<Price amount={amount} override={override} />
)}
</AmountText> </AmountText>
)} )}
</InputTitleRow> </InputTitleRow>

View file

@ -12,10 +12,12 @@ type PriceProps = {
export const Price = ({ export const Price = ({
amount, amount,
breakNumber = false, breakNumber = false,
override,
}: { }: {
amount: number | string; amount: number | string;
breakNumber?: boolean; breakNumber?: boolean;
}) => { override?: string;
}): JSX.Element => {
const { currency, displayValues } = useConfigState(); const { currency, displayValues } = useConfigState();
const { prices, dontShow } = usePriceState(); const { prices, dontShow } = usePriceState();
@ -42,12 +44,13 @@ export const Price = ({
}; };
} }
return <>{getValue({ amount, ...priceProps, breakNumber })}</>; return <>{getValue({ amount, ...priceProps, breakNumber, override })}</>;
}; };
interface GetPriceProps { interface GetPriceProps {
amount: number | string; amount: number | string;
breakNumber?: boolean; breakNumber?: boolean;
override?: string;
} }
export const getPrice = ( export const getPrice = (
@ -57,7 +60,7 @@ export const getPrice = (
dontShow: boolean; dontShow: boolean;
prices?: { [key: string]: { last: number; symbol: string } }; prices?: { [key: string]: { last: number; symbol: string } };
} }
) => ({ amount, breakNumber = false }: GetPriceProps): string => { ) => ({ amount, breakNumber = false, override }: GetPriceProps): string => {
const { prices, dontShow } = priceContext; const { prices, dontShow } = priceContext;
if (!displayValues) { if (!displayValues) {
@ -83,5 +86,5 @@ export const getPrice = (
}; };
} }
return getValue({ amount, ...priceProps, breakNumber }); return getValue({ amount, ...priceProps, breakNumber, override });
}; };

View file

@ -6,8 +6,8 @@ const themeTypes = ['dark', 'light'];
const currencyTypes = ['sat', 'btc', 'EUR', 'USD']; const currencyTypes = ['sat', 'btc', 'EUR', 'USD'];
export type channelBarStyleTypes = 'normal' | 'compact' | 'ultracompact'; export type channelBarStyleTypes = 'normal' | 'compact' | 'ultracompact';
export type channelBarTypeTypes = 'balance' | 'details' | 'partner'; export type channelBarTypeTypes = 'balance' | 'fees' | 'size' | 'proportional';
export type channelSortTypes = 'none' | 'local' | 'balance'; export type channelSortTypes = 'none' | 'local' | 'balance' | 'feeRate';
export type sortDirectionTypes = 'increase' | 'decrease'; export type sortDirectionTypes = 'increase' | 'decrease';
type State = { type State = {

View file

@ -16,6 +16,7 @@ interface GetNumberProps {
symbol: string; symbol: string;
currency: string; currency: string;
breakNumber?: boolean; breakNumber?: boolean;
override?: string;
} }
export const getValue = ({ export const getValue = ({
@ -24,7 +25,9 @@ export const getValue = ({
symbol, symbol,
currency, currency,
breakNumber, breakNumber,
override,
}: GetNumberProps): string => { }: GetNumberProps): string => {
const correctCurrency = override || currency;
let value = 0; let value = 0;
if (typeof amount === 'string') { if (typeof amount === 'string') {
value = Number(amount); value = Number(amount);
@ -32,14 +35,14 @@ export const getValue = ({
value = amount; value = amount;
} }
if (currency === 'btc') { if (correctCurrency === 'btc') {
if (!value) return 'â‚¿0.0'; if (!value) return 'â‚¿0.0';
const amountInBtc = value / 100000000; const amountInBtc = value / 100000000;
const rounded = Math.round(amountInBtc * 10000) / 10000; const rounded = Math.round(amountInBtc * 10000) / 10000;
return `â‚¿${rounded}`; return `â‚¿${rounded}`;
} }
if (currency === 'sat') { if (correctCurrency === 'sat') {
const breakAmount = breakNumber const breakAmount = breakNumber
? getValueString(value) ? getValueString(value)
: numeral(value).format('0,0.[000]'); : numeral(value).format('0,0.[000]');

View file

@ -66,7 +66,7 @@ interface ChannelCardProps {
biggestRateFee: number; biggestRateFee: number;
} }
export const ChannelCard = ({ export const ChannelCard: React.FC<ChannelCardProps> = ({
channelInfo, channelInfo,
index, index,
setIndexOpen, setIndexOpen,
@ -76,7 +76,7 @@ export const ChannelCard = ({
mostChannels, mostChannels,
biggestBaseFee, biggestBaseFee,
biggestRateFee, biggestRateFee,
}: ChannelCardProps) => { }) => {
const { channelBarType, channelBarStyle } = useConfigState(); const { channelBarType, channelBarStyle } = useConfigState();
const [modalOpen, setModalOpen] = useState(false); const [modalOpen, setModalOpen] = useState(false);
@ -133,6 +133,9 @@ export const ChannelCard = ({
const remoteReserve = format({ amount: remote_reserve }); const remoteReserve = format({ amount: remote_reserve });
const nodeCapacity = format({ amount: partnerNodeCapacity }); const nodeCapacity = format({ amount: partnerNodeCapacity });
const baseFee = format({ amount: base_fee / 1000, override: 'sat' });
const feeRate = format({ amount: fee_rate, override: 'sat' });
const handleClick = () => { const handleClick = () => {
if (indexOpen === index) { if (indexOpen === index) {
setIndexOpen(0); setIndexOpen(0);
@ -150,8 +153,8 @@ export const ChannelCard = ({
'Last Update:', 'Last Update:',
`${getDateDif(updated_at)} ago (${getFormatDate(updated_at)})` `${getDateDif(updated_at)} ago (${getFormatDate(updated_at)})`
)} )}
{renderLine('Base Fee:', `${base_fee} msats`)} {renderLine('Base Fee:', baseFee)}
{renderLine('Fee Rate:', `${fee_rate} sats/Msats`)} {renderLine('Fee Rate:', `${feeRate}/million`)}
{renderLine('CTLV Delta:', cltv_delta)} {renderLine('CTLV Delta:', cltv_delta)}
</> </>
) : ( ) : (
@ -205,28 +208,79 @@ export const ChannelCard = ({
const renderBars = () => { const renderBars = () => {
switch (channelBarType) { switch (channelBarType) {
case 'partner': case 'fees':
return ( return (
<ChannelStatsColumn> <ChannelStatsColumn>
<ChannelStatsLine>
<ProgressBar
order={3}
percent={getBar(fee_rate, biggestRateFee)}
/>
<ProgressBar
order={4}
percent={getBar(biggestRateFee - fee_rate, biggestRateFee)}
/>
</ChannelStatsLine>
<ChannelStatsLine>
<ProgressBar
order={1}
percent={getBar(base_fee, biggestBaseFee)}
/>
<ProgressBar
order={4}
percent={getBar(biggestBaseFee - base_fee, biggestBaseFee)}
/>
</ChannelStatsLine>
</ChannelStatsColumn>
);
case 'size':
return (
<ChannelStatsColumn>
<ChannelStatsLine>
<ProgressBar <ProgressBar
order={0} order={0}
percent={getBar(Number(partnerNodeCapacity), biggestPartner)} percent={getBar(Number(partnerNodeCapacity), biggestPartner)}
/> />
<ProgressBar <ProgressBar
order={3} order={4}
percent={getBar(
biggestPartner - Number(partnerNodeCapacity),
biggestPartner
)}
/>
</ChannelStatsLine>
<ChannelStatsLine>
<ProgressBar
order={6}
percent={getBar(channel_count, mostChannels)} percent={getBar(channel_count, mostChannels)}
/> />
<ProgressBar order={1} percent={getBar(base_fee, biggestBaseFee)} /> <ProgressBar
<ProgressBar order={2} percent={getBar(fee_rate, biggestRateFee)} /> order={4}
percent={getBar(mostChannels - channel_count, mostChannels)}
/>
</ChannelStatsLine>
</ChannelStatsColumn> </ChannelStatsColumn>
); );
case 'details': case 'proportional':
return ( return (
<ChannelStatsColumn> <ChannelStatsColumn>
<ProgressBar order={0} percent={getBar(local_balance, biggest)} /> <ChannelStatsLine>
<ProgressBar order={1} percent={getBar(remote_balance, biggest)} /> <ProgressBar order={1} percent={getBar(local_balance, biggest)} />
<ProgressBar order={2} percent={getBar(received, biggest)} /> <ProgressBar
<ProgressBar order={3} percent={getBar(sent, biggest)} /> order={4}
percent={getBar(biggest - local_balance, biggest)}
/>
</ChannelStatsLine>
<ChannelStatsLine>
<ProgressBar
order={2}
percent={getBar(remote_balance, biggest)}
/>
<ProgressBar
order={4}
percent={getBar(biggest - remote_balance, biggest)}
/>
</ChannelStatsLine>
</ChannelStatsColumn> </ChannelStatsColumn>
); );
default: default:
@ -253,16 +307,27 @@ export const ChannelCard = ({
const renderBarsInfo = () => { const renderBarsInfo = () => {
switch (channelBarType) { switch (channelBarType) {
case 'partner': case 'fees':
return (
<>
<div>{`Partner Fee Rate: ${feeRate}/million`}</div>
<div>{`Partner Base Fee: ${baseFee}`}</div>
</>
);
case 'size':
return ( return (
<> <>
<div>{`Partner Capacity: ${nodeCapacity}`}</div> <div>{`Partner Capacity: ${nodeCapacity}`}</div>
<div>{`Partner Channels: ${channel_count}`}</div> <div>{`Partner Channels: ${channel_count}`}</div>
<div>{`Partner Base Fee: ${base_fee} msats`}</div>
<div>{`Partner Fee Rate: ${fee_rate} sats/Msats`}</div>
</> </>
); );
case 'details': case 'proportional':
return (
<>
<div>{`Local Balance: ${formatLocal}`}</div>
<div>{`Remote Balance: ${formatRemote}`}</div>
</>
);
default: default:
return ( return (
<> <>

View file

@ -71,16 +71,22 @@ export const ChannelManage = () => {
Balance Balance
</SingleButton> </SingleButton>
<SingleButton <SingleButton
selected={channelBarType === 'details'} selected={channelBarType === 'proportional'}
onClick={() => changeType('details')} onClick={() => changeType('proportional')}
> >
Proportional Proportional
</SingleButton> </SingleButton>
<SingleButton <SingleButton
selected={channelBarType === 'partner'} selected={channelBarType === 'size'}
onClick={() => changeType('partner')} onClick={() => changeType('size')}
> >
Partner Partner Size
</SingleButton>
<SingleButton
selected={channelBarType === 'fees'}
onClick={() => changeType('fees')}
>
Partner Fees
</SingleButton> </SingleButton>
</MultiButton> </MultiButton>
</MarginLine> </MarginLine>
@ -105,6 +111,12 @@ export const ChannelManage = () => {
> >
Balance Balance
</SingleButton> </SingleButton>
<SingleButton
selected={channelSort === 'feeRate'}
onClick={() => changeSort('feeRate')}
>
Fee Rate
</SingleButton>
</MultiButton> </MultiButton>
</MarginLine> </MarginLine>
{channelSort !== 'none' && ( {channelSort !== 'none' && (

View file

@ -10,7 +10,7 @@ import { getErrorContent } from '../../../utils/error';
import { LoadingCard } from '../../../components/loading/LoadingCard'; import { LoadingCard } from '../../../components/loading/LoadingCard';
import { ChannelCard } from './ChannelCard'; import { ChannelCard } from './ChannelCard';
export const Channels = () => { export const Channels: React.FC = () => {
const { sortDirection, channelSort } = useConfigState(); const { sortDirection, channelSort } = useConfigState();
const [indexOpen, setIndexOpen] = useState(0); const [indexOpen, setIndexOpen] = useState(0);
@ -35,19 +35,13 @@ export const Channels = () => {
for (let i = 0; i < data.getChannels.length; i++) { for (let i = 0; i < data.getChannels.length; i++) {
const channel = data.getChannels[i]; const channel = data.getChannels[i];
const { const { local_balance, remote_balance, partner_node_info = {} } = channel;
local_balance,
remote_balance,
sent,
received,
partner_node_info = {},
} = channel;
const { capacity, channel_count, base_fee, fee_rate } = partner_node_info; const { capacity, channel_count, base_fee, fee_rate } = partner_node_info;
const partner = Number(capacity) || 0; const partner = Number(capacity) || 0;
const channels = Number(channel_count) || 0; const channels = Number(channel_count) || 0;
const max = Math.max(local_balance, remote_balance, sent, received); const max = Math.max(local_balance, remote_balance);
if (max > biggest) { if (max > biggest) {
biggest = max; biggest = max;
@ -78,6 +72,13 @@ export const Channels = () => {
); );
return sortDirection === 'increase' ? newArray : newArray.reverse(); return sortDirection === 'increase' ? newArray : newArray.reverse();
} }
case 'feeRate': {
const newArray = sortBy(
data.getChannels,
channel => channel.partner_node_info.fee_rate
);
return sortDirection === 'increase' ? newArray : newArray.reverse();
}
default: default:
return data.getChannels; return data.getChannels;
} }
@ -95,8 +96,8 @@ export const Channels = () => {
biggest={biggest} biggest={biggest}
biggestPartner={biggestPartner} biggestPartner={biggestPartner}
mostChannels={mostChannels} mostChannels={mostChannels}
biggestBaseFee={biggestBaseFee} biggestBaseFee={Math.max(biggestBaseFee, 100000)}
biggestRateFee={biggestRateFee} biggestRateFee={Math.max(biggestRateFee, 2000)}
/> />
))} ))}
</Card> </Card>

View file

@ -28,12 +28,12 @@ interface FeeCardProps {
indexOpen: number; indexOpen: number;
} }
export const FeeCard = ({ export const FeeCard: React.FC<FeeCardProps> = ({
channelInfo, channelInfo,
index, index,
setIndexOpen, setIndexOpen,
indexOpen, indexOpen,
}: FeeCardProps) => { }) => {
const [newBaseFee, setBaseFee] = useState(0); const [newBaseFee, setBaseFee] = useState(0);
const [newFeeRate, setFeeRate] = useState(0); const [newFeeRate, setFeeRate] = useState(0);
@ -78,15 +78,17 @@ export const FeeCard = ({
<AdminSwitch> <AdminSwitch>
<InputWithDeco <InputWithDeco
title={'BaseFee'} title={'BaseFee'}
placeholder={'Sats'} placeholder={'sats'}
amount={newBaseFee} amount={newBaseFee}
override={'sat'}
inputType={'number'} inputType={'number'}
inputCallback={value => setBaseFee(Number(value))} inputCallback={value => setBaseFee(Number(value))}
/> />
<InputWithDeco <InputWithDeco
title={'Fee Rate'} title={'Fee Rate'}
placeholder={'MilliSats/Million'} placeholder={'msats/million'}
amount={newFeeRate / 1000} amount={newFeeRate / 1000}
override={'sat'}
inputType={'number'} inputType={'number'}
inputCallback={value => setFeeRate(Number(value))} inputCallback={value => setFeeRate(Number(value))}
/> />