mirror of
https://github.com/apotdevin/thunderhub.git
synced 2025-02-22 14:22:33 +01:00
feat: ✨ channel ui manager
This commit is contained in:
parent
8099a3919e
commit
35cf8db27f
12 changed files with 344 additions and 112 deletions
|
@ -41,7 +41,7 @@ const Wrapper: React.FC = ({ children }) => {
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
if (hasAccount === 'false') {
|
if (hasAccount === 'false') {
|
||||||
return <LoadingCard noCard={true} />;
|
return <LoadingCard loadingHeight={'50vh'} noCard={true} />;
|
||||||
}
|
}
|
||||||
return <GridWrapper>{children}</GridWrapper>;
|
return <GridWrapper>{children}</GridWrapper>;
|
||||||
};
|
};
|
||||||
|
@ -100,19 +100,18 @@ const App = ({
|
||||||
App.getInitialProps = async props => {
|
App.getInitialProps = async props => {
|
||||||
const cookieParam = getUrlParam(props.router?.query?.token);
|
const cookieParam = getUrlParam(props.router?.query?.token);
|
||||||
const cookies = parseCookies(props.ctx.req);
|
const cookies = parseCookies(props.ctx.req);
|
||||||
const defaultState = {};
|
|
||||||
|
|
||||||
if (!cookies?.config) {
|
if (!cookies?.config) {
|
||||||
return { initialConfig: {}, ...defaultState };
|
return { initialConfig: {} };
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const config = JSON.parse(cookies.config);
|
const config = JSON.parse(cookies.config);
|
||||||
return {
|
return {
|
||||||
initialConfig: { ...config, ...defaultState },
|
initialConfig: config,
|
||||||
cookieParam,
|
cookieParam,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { initialConfig: {}, cookieParam, ...defaultState };
|
return { initialConfig: {}, cookieParam };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,9 @@ const BalanceView = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderChannels = (isOutgoing?: boolean) => {
|
const renderChannels = (isOutgoing?: boolean) => {
|
||||||
const channels = sortBy(data.getChannels, [
|
const channels = sortBy(data.getChannels, channel =>
|
||||||
(channel: any) =>
|
getPercent(channel.remote_balance, channel.local_balance)
|
||||||
getPercent(channel.remote_balance, channel.local_balance),
|
);
|
||||||
]);
|
|
||||||
|
|
||||||
const finalChannels = isOutgoing ? channels : channels.reverse();
|
const finalChannels = isOutgoing ? channels : channels.reverse();
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ import React, { useState, useEffect } from 'react';
|
||||||
import { useAccountState } from 'src/context/AccountContext';
|
import { useAccountState } from 'src/context/AccountContext';
|
||||||
import { useGetChannelAmountInfoQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated';
|
import { useGetChannelAmountInfoQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { Settings } from 'react-feather';
|
||||||
|
import { IconCursor } from 'src/views/channels/channels/Channel.style';
|
||||||
|
import { ChannelManage } from 'src/views/channels/channels/ChannelManage';
|
||||||
import { Channels } from '../src/views/channels/channels/Channels';
|
import { Channels } from '../src/views/channels/channels/Channels';
|
||||||
import { PendingChannels } from '../src/views/channels/pendingChannels/PendingChannels';
|
import { PendingChannels } from '../src/views/channels/pendingChannels/PendingChannels';
|
||||||
import { ClosedChannels } from '../src/views/channels/closedChannels/ClosedChannels';
|
import { ClosedChannels } from '../src/views/channels/closedChannels/ClosedChannels';
|
||||||
|
@ -28,6 +31,7 @@ const ButtonRow = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ChannelView = () => {
|
const ChannelView = () => {
|
||||||
|
const [isOpen, isOpenSet] = useState<boolean>(false);
|
||||||
const [view, setView] = useState<number>(1);
|
const [view, setView] = useState<number>(1);
|
||||||
const [amounts, setAmounts] = useState({
|
const [amounts, setAmounts] = useState({
|
||||||
active: 0,
|
active: 0,
|
||||||
|
@ -94,8 +98,14 @@ const ChannelView = () => {
|
||||||
<SmallButton onClick={() => setView(3)}>
|
<SmallButton onClick={() => setView(3)}>
|
||||||
{`Closed (${amounts.closed})`}
|
{`Closed (${amounts.closed})`}
|
||||||
</SmallButton>
|
</SmallButton>
|
||||||
|
{view === 1 && (
|
||||||
|
<IconCursor>
|
||||||
|
<Settings size={16} onClick={() => isOpenSet(p => !p)} />
|
||||||
|
</IconCursor>
|
||||||
|
)}
|
||||||
</ButtonRow>
|
</ButtonRow>
|
||||||
</ChannelsCardTitle>
|
</ChannelsCardTitle>
|
||||||
|
{view === 1 && isOpen && <ChannelManage />}
|
||||||
{getView()}
|
{getView()}
|
||||||
</CardWithTitle>
|
</CardWithTitle>
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,6 +27,8 @@ export const ProgressBar = styled.div<ProgressBar>`
|
||||||
return chartColors.green;
|
return chartColors.green;
|
||||||
case 3:
|
case 3:
|
||||||
return chartColors.orange;
|
return chartColors.orange;
|
||||||
|
case 4:
|
||||||
|
return progressBackground;
|
||||||
default:
|
default:
|
||||||
return chartColors.purple;
|
return chartColors.purple;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,13 +81,18 @@ interface SubCardProps {
|
||||||
padding?: string;
|
padding?: string;
|
||||||
withMargin?: string;
|
withMargin?: string;
|
||||||
noCard?: boolean;
|
noCard?: boolean;
|
||||||
|
noBackground?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SubCard = styled.div<SubCardProps>`
|
export const SubCard = styled.div<SubCardProps>`
|
||||||
margin: ${({ withMargin }) => (withMargin ? withMargin : '0 0 10px 0')};
|
margin: ${({ withMargin }) => (withMargin ? withMargin : '0 0 10px 0')};
|
||||||
padding: ${({ padding }) => (padding ? padding : '16px')};
|
padding: ${({ padding }) => (padding ? padding : '16px')};
|
||||||
background: ${subCardColor};
|
${({ noBackground }) =>
|
||||||
border: 1px solid ${cardBorderColor};
|
!noBackground &&
|
||||||
|
css`
|
||||||
|
background: ${subCardColor};
|
||||||
|
border: 1px solid ${cardBorderColor};
|
||||||
|
`}
|
||||||
border-left: ${({ color }) => (color ? `2px solid ${color}` : '')};
|
border-left: ${({ color }) => (color ? `2px solid ${color}` : '')};
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -5,6 +5,11 @@ import Cookies from 'js-cookie';
|
||||||
const themeTypes = ['dark', 'light'];
|
const themeTypes = ['dark', 'light'];
|
||||||
const currencyTypes = ['sat', 'btc', 'EUR', 'USD'];
|
const currencyTypes = ['sat', 'btc', 'EUR', 'USD'];
|
||||||
|
|
||||||
|
export type channelBarStyleTypes = 'normal' | 'compact' | 'ultracompact';
|
||||||
|
export type channelBarTypeTypes = 'balance' | 'details' | 'partner';
|
||||||
|
export type channelSortTypes = 'none' | 'local' | 'balance';
|
||||||
|
export type sortDirectionTypes = 'increase' | 'decrease';
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
currency: string;
|
currency: string;
|
||||||
theme: string;
|
theme: string;
|
||||||
|
@ -17,7 +22,10 @@ type State = {
|
||||||
hideNonVerified: boolean;
|
hideNonVerified: boolean;
|
||||||
maxFee: number;
|
maxFee: number;
|
||||||
chatPollingSpeed: number;
|
chatPollingSpeed: number;
|
||||||
channelBarType: 'normal' | 'partner';
|
channelBarStyle: channelBarStyleTypes;
|
||||||
|
channelBarType: channelBarTypeTypes;
|
||||||
|
channelSort: channelSortTypes;
|
||||||
|
sortDirection: sortDirectionTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ConfigInitProps = {
|
type ConfigInitProps = {
|
||||||
|
@ -37,7 +45,10 @@ type ActionType = {
|
||||||
hideNonVerified?: boolean;
|
hideNonVerified?: boolean;
|
||||||
maxFee?: number;
|
maxFee?: number;
|
||||||
chatPollingSpeed?: number;
|
chatPollingSpeed?: number;
|
||||||
channelBarType?: 'normal' | 'partner';
|
channelBarStyle?: channelBarStyleTypes;
|
||||||
|
channelBarType?: channelBarTypeTypes;
|
||||||
|
channelSort?: channelSortTypes;
|
||||||
|
sortDirection?: sortDirectionTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Dispatch = (action: ActionType) => void;
|
type Dispatch = (action: ActionType) => void;
|
||||||
|
@ -65,7 +76,10 @@ const initialState: State = {
|
||||||
hideNonVerified: false,
|
hideNonVerified: false,
|
||||||
maxFee: 20,
|
maxFee: 20,
|
||||||
chatPollingSpeed: 1000,
|
chatPollingSpeed: 1000,
|
||||||
channelBarType: 'normal',
|
channelBarStyle: 'normal',
|
||||||
|
channelBarType: 'balance',
|
||||||
|
channelSort: 'none',
|
||||||
|
sortDirection: 'decrease',
|
||||||
};
|
};
|
||||||
|
|
||||||
const stateReducer = (state: State, action: ActionType): State => {
|
const stateReducer = (state: State, action: ActionType): State => {
|
||||||
|
|
|
@ -34,10 +34,11 @@ export const ChannelColumnSection = styled.div`
|
||||||
|
|
||||||
export const ChannelLineSection = styled.div`
|
export const ChannelLineSection = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
max-width: 300px;
|
width: 180px;
|
||||||
|
|
||||||
@media (${mediaWidths.mobile}) {
|
@media (${mediaWidths.mobile}) {
|
||||||
|
align-items: center;
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -62,7 +62,7 @@ export const BalanceCard = ({
|
||||||
} = channel;
|
} = channel;
|
||||||
const { alias } = partner_node_info;
|
const { alias } = partner_node_info;
|
||||||
|
|
||||||
const balancedness = getPercent(remote_balance, local_balance) / 100;
|
const balancedness = getPercent(local_balance, remote_balance) / 100;
|
||||||
const formatBalance = numeral(balancedness).format('0,0.00');
|
const formatBalance = numeral(balancedness).format('0,0.00');
|
||||||
|
|
||||||
const props = withColor ? { color: themeColors.blue3 } : {};
|
const props = withColor ? { color: themeColors.blue3 } : {};
|
||||||
|
@ -72,9 +72,12 @@ export const BalanceCard = ({
|
||||||
<MainInfo onClick={() => callback && callback()}>
|
<MainInfo onClick={() => callback && callback()}>
|
||||||
<ResponsiveLine withWrap={true}>
|
<ResponsiveLine withWrap={true}>
|
||||||
<ChannelLineSection>
|
<ChannelLineSection>
|
||||||
{alias && alias !== ''
|
<div>
|
||||||
? `${alias} - ${id}`
|
{alias && alias !== ''
|
||||||
: `${partner_public_key?.substring(0, 6)} - ${id}`}
|
? alias
|
||||||
|
: partner_public_key?.substring(0, 6)}
|
||||||
|
</div>
|
||||||
|
<DarkSubTitle>{id}</DarkSubTitle>
|
||||||
</ChannelLineSection>
|
</ChannelLineSection>
|
||||||
<ChannelColumnSection>
|
<ChannelColumnSection>
|
||||||
<SingleLine>
|
<SingleLine>
|
||||||
|
|
55
src/views/channels/channels/Channel.style.ts
Normal file
55
src/views/channels/channels/Channel.style.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { mediaWidths } from 'src/styles/Themes';
|
||||||
|
|
||||||
|
export const ChannelIconPadding = styled.div`
|
||||||
|
display: flex;
|
||||||
|
margin-left: 8px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ChannelStatsColumn = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ChannelStatsLine = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ChannelBarSide = styled.div`
|
||||||
|
width: 50%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
@media (${mediaWidths.mobile}) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ChannelNodeTitle = styled.div`
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
@media (${mediaWidths.mobile}) {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ChannelSingleLine = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const IconCursor = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 8px;
|
||||||
|
`;
|
|
@ -1,8 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ReactTooltip from 'react-tooltip';
|
import ReactTooltip from 'react-tooltip';
|
||||||
import styled from 'styled-components';
|
|
||||||
import { ArrowDown, ArrowUp, EyeOff } from 'react-feather';
|
import { ArrowDown, ArrowUp, EyeOff } from 'react-feather';
|
||||||
import { mediaWidths } from 'src/styles/Themes';
|
|
||||||
import { ChannelType } from 'src/graphql/types';
|
import { ChannelType } from 'src/graphql/types';
|
||||||
import { getPercent, formatSeconds } from '../../../utils/helpers';
|
import { getPercent, formatSeconds } from '../../../utils/helpers';
|
||||||
import {
|
import {
|
||||||
|
@ -18,10 +16,7 @@ import {
|
||||||
ResponsiveLine,
|
ResponsiveLine,
|
||||||
DarkSubTitle,
|
DarkSubTitle,
|
||||||
} from '../../../components/generic/Styled';
|
} from '../../../components/generic/Styled';
|
||||||
import {
|
import { useConfigState } from '../../../context/ConfigContext';
|
||||||
useConfigState,
|
|
||||||
useConfigDispatch,
|
|
||||||
} from '../../../context/ConfigContext';
|
|
||||||
import {
|
import {
|
||||||
getStatusDot,
|
getStatusDot,
|
||||||
getTooltipType,
|
getTooltipType,
|
||||||
|
@ -37,47 +32,14 @@ import { AdminSwitch } from '../../../components/adminSwitch/AdminSwitch';
|
||||||
import { ColorButton } from '../../../components/buttons/colorButton/ColorButton';
|
import { ColorButton } from '../../../components/buttons/colorButton/ColorButton';
|
||||||
import { getPrice } from '../../../components/price/Price';
|
import { getPrice } from '../../../components/price/Price';
|
||||||
import { usePriceState } from '../../../context/PriceContext';
|
import { usePriceState } from '../../../context/PriceContext';
|
||||||
|
import {
|
||||||
const IconPadding = styled.div`
|
ChannelNodeTitle,
|
||||||
display: flex;
|
ChannelBarSide,
|
||||||
flex-direction: column;
|
ChannelIconPadding,
|
||||||
margin-left: 8px;
|
ChannelStatsColumn,
|
||||||
|
ChannelSingleLine,
|
||||||
@media (${mediaWidths.mobile}) {
|
ChannelStatsLine,
|
||||||
display: none;
|
} from './Channel.style';
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StatsColumn = styled.div`
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-end;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const BarSide = styled.div`
|
|
||||||
width: 50%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
@media (${mediaWidths.mobile}) {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const NodeTitle = styled.div`
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 700;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
@media (${mediaWidths.mobile}) {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const getSymbol = (status: boolean) => {
|
const getSymbol = (status: boolean) => {
|
||||||
return status ? <ArrowDown size={14} /> : <ArrowUp size={14} />;
|
return status ? <ArrowDown size={14} /> : <ArrowUp size={14} />;
|
||||||
|
@ -115,8 +77,7 @@ export const ChannelCard = ({
|
||||||
biggestBaseFee,
|
biggestBaseFee,
|
||||||
biggestRateFee,
|
biggestRateFee,
|
||||||
}: ChannelCardProps) => {
|
}: ChannelCardProps) => {
|
||||||
const { channelBarType } = useConfigState();
|
const { channelBarType, channelBarStyle } = useConfigState();
|
||||||
const dispatch = useConfigDispatch();
|
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
|
||||||
const { theme, currency, displayValues } = useConfigState();
|
const { theme, currency, displayValues } = useConfigState();
|
||||||
|
@ -180,13 +141,6 @@ export const ChannelCard = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBarClick = () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'change',
|
|
||||||
channelBarType: channelBarType === 'normal' ? 'partner' : 'normal',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderPartner = () =>
|
const renderPartner = () =>
|
||||||
alias ? (
|
alias ? (
|
||||||
<>
|
<>
|
||||||
|
@ -196,8 +150,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:', `${base_fee} msats`)}
|
||||||
{renderLine('Fee Rate:', `${fee_rate} sats/MSats`)}
|
{renderLine('Fee Rate:', `${fee_rate} sats/Msats`)}
|
||||||
{renderLine('CTLV Delta:', cltv_delta)}
|
{renderLine('CTLV Delta:', cltv_delta)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
@ -253,7 +207,7 @@ export const ChannelCard = ({
|
||||||
switch (channelBarType) {
|
switch (channelBarType) {
|
||||||
case 'partner':
|
case 'partner':
|
||||||
return (
|
return (
|
||||||
<>
|
<ChannelStatsColumn>
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
order={0}
|
order={0}
|
||||||
percent={getBar(Number(partnerNodeCapacity), biggestPartner)}
|
percent={getBar(Number(partnerNodeCapacity), biggestPartner)}
|
||||||
|
@ -264,16 +218,35 @@ export const ChannelCard = ({
|
||||||
/>
|
/>
|
||||||
<ProgressBar order={1} percent={getBar(base_fee, biggestBaseFee)} />
|
<ProgressBar order={1} percent={getBar(base_fee, biggestBaseFee)} />
|
||||||
<ProgressBar order={2} percent={getBar(fee_rate, biggestRateFee)} />
|
<ProgressBar order={2} percent={getBar(fee_rate, biggestRateFee)} />
|
||||||
</>
|
</ChannelStatsColumn>
|
||||||
);
|
);
|
||||||
default:
|
case 'details':
|
||||||
return (
|
return (
|
||||||
<>
|
<ChannelStatsColumn>
|
||||||
<ProgressBar order={0} percent={getBar(local_balance, biggest)} />
|
<ProgressBar order={0} percent={getBar(local_balance, biggest)} />
|
||||||
<ProgressBar order={1} percent={getBar(remote_balance, biggest)} />
|
<ProgressBar order={1} percent={getBar(remote_balance, biggest)} />
|
||||||
<ProgressBar order={2} percent={getBar(received, biggest)} />
|
<ProgressBar order={2} percent={getBar(received, biggest)} />
|
||||||
<ProgressBar order={3} percent={getBar(sent, biggest)} />
|
<ProgressBar order={3} percent={getBar(sent, biggest)} />
|
||||||
</>
|
</ChannelStatsColumn>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<ChannelStatsColumn>
|
||||||
|
<ChannelStatsLine>
|
||||||
|
<ProgressBar
|
||||||
|
order={1}
|
||||||
|
percent={getPercent(local_balance, remote_balance)}
|
||||||
|
/>
|
||||||
|
<ProgressBar
|
||||||
|
order={4}
|
||||||
|
percent={getPercent(remote_balance, local_balance)}
|
||||||
|
/>
|
||||||
|
</ChannelStatsLine>
|
||||||
|
<ChannelStatsLine>
|
||||||
|
<ProgressBar order={2} percent={getPercent(received, sent)} />
|
||||||
|
<ProgressBar order={4} percent={getPercent(sent, received)} />
|
||||||
|
</ChannelStatsLine>
|
||||||
|
</ChannelStatsColumn>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -285,10 +258,11 @@ export const ChannelCard = ({
|
||||||
<>
|
<>
|
||||||
<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 Base Fee: ${base_fee} msats`}</div>
|
||||||
<div>{`Partner Fee Rate: ${fee_rate} sats/MSats`}</div>
|
<div>{`Partner Fee Rate: ${fee_rate} sats/Msats`}</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
case 'details':
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -301,34 +275,52 @@ export const ChannelCard = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getSubCardProps = () => {
|
||||||
|
switch (channelBarStyle) {
|
||||||
|
case 'ultracompact':
|
||||||
|
return {
|
||||||
|
withMargin: '0 0 4px 0',
|
||||||
|
padding: index === indexOpen ? '0 0 16px' : '2px 0',
|
||||||
|
noBackground: true,
|
||||||
|
};
|
||||||
|
case 'compact':
|
||||||
|
return {
|
||||||
|
withMargin: '0 0 4px 0',
|
||||||
|
padding: index === indexOpen ? '4px 8px 16px' : '4px 8px',
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubCard key={`${index}-${id}`} noCard={true}>
|
<SubCard key={`${index}-${id}`} noCard={true} {...getSubCardProps()}>
|
||||||
<StatusLine>
|
<MainInfo onClick={() => handleClick()}>
|
||||||
{getStatusDot(is_active, 'active')}
|
{channelBarStyle === 'normal' && (
|
||||||
{getStatusDot(is_opening, 'opening')}
|
<StatusLine>
|
||||||
{getStatusDot(is_closing, 'closing')}
|
{getStatusDot(is_active, 'active')}
|
||||||
</StatusLine>
|
{getStatusDot(is_opening, 'opening')}
|
||||||
<ResponsiveLine>
|
{getStatusDot(is_closing, 'closing')}
|
||||||
<NodeTitle style={{ flexGrow: 2 }}>
|
</StatusLine>
|
||||||
<MainInfo onClick={() => handleClick()}>
|
)}
|
||||||
|
<ResponsiveLine>
|
||||||
|
<ChannelNodeTitle style={{ flexGrow: 2 }}>
|
||||||
{alias || partner_public_key?.substring(0, 6)}
|
{alias || partner_public_key?.substring(0, 6)}
|
||||||
<DarkSubTitle>{formatBalance}</DarkSubTitle>
|
{channelBarStyle !== 'ultracompact' && (
|
||||||
</MainInfo>
|
<ChannelSingleLine>
|
||||||
</NodeTitle>
|
<DarkSubTitle>{formatBalance}</DarkSubTitle>
|
||||||
<BarSide>
|
<ChannelIconPadding>
|
||||||
<StatsColumn
|
{getPrivate(is_private)}
|
||||||
data-tip
|
{getSymbol(is_partner_initiated)}
|
||||||
data-for={`node_balance_tip_${index}`}
|
</ChannelIconPadding>
|
||||||
onClick={handleBarClick}
|
</ChannelSingleLine>
|
||||||
>
|
)}
|
||||||
|
</ChannelNodeTitle>
|
||||||
|
<ChannelBarSide data-tip data-for={`node_balance_tip_${index}`}>
|
||||||
{renderBars()}
|
{renderBars()}
|
||||||
</StatsColumn>
|
</ChannelBarSide>
|
||||||
</BarSide>
|
</ResponsiveLine>
|
||||||
<IconPadding>
|
</MainInfo>
|
||||||
{getPrivate(is_private)}
|
|
||||||
{getSymbol(is_partner_initiated)}
|
|
||||||
</IconPadding>
|
|
||||||
</ResponsiveLine>
|
|
||||||
{index === indexOpen && renderDetails()}
|
{index === indexOpen && renderDetails()}
|
||||||
<ReactTooltip
|
<ReactTooltip
|
||||||
id={`node_balance_tip_${index}`}
|
id={`node_balance_tip_${index}`}
|
||||||
|
|
131
src/views/channels/channels/ChannelManage.tsx
Normal file
131
src/views/channels/channels/ChannelManage.tsx
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import {
|
||||||
|
SingleButton,
|
||||||
|
MultiButton,
|
||||||
|
} from 'src/components/buttons/multiButton/MultiButton';
|
||||||
|
import {
|
||||||
|
useConfigState,
|
||||||
|
useConfigDispatch,
|
||||||
|
channelBarStyleTypes,
|
||||||
|
channelBarTypeTypes,
|
||||||
|
channelSortTypes,
|
||||||
|
sortDirectionTypes,
|
||||||
|
} from 'src/context/ConfigContext';
|
||||||
|
import { Card, SingleLine, Sub4Title } from 'src/components/generic/Styled';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const MarginLine = styled(SingleLine)`
|
||||||
|
margin: 8px 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ChannelManage = () => {
|
||||||
|
const {
|
||||||
|
channelBarType,
|
||||||
|
channelBarStyle,
|
||||||
|
channelSort,
|
||||||
|
sortDirection,
|
||||||
|
} = useConfigState();
|
||||||
|
const dispatch = useConfigDispatch();
|
||||||
|
|
||||||
|
const changeStyle = (style: channelBarStyleTypes) =>
|
||||||
|
dispatch({ type: 'change', channelBarStyle: style });
|
||||||
|
const changeType = (type: channelBarTypeTypes) =>
|
||||||
|
dispatch({ type: 'change', channelBarType: type });
|
||||||
|
const changeSort = (type: channelSortTypes) =>
|
||||||
|
dispatch({ type: 'change', channelSort: type });
|
||||||
|
const changeDirection = (type: sortDirectionTypes) =>
|
||||||
|
dispatch({ type: 'change', sortDirection: type });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<MarginLine>
|
||||||
|
<Sub4Title>Card Type</Sub4Title>
|
||||||
|
<MultiButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelBarStyle === 'normal'}
|
||||||
|
onClick={() => changeStyle('normal')}
|
||||||
|
>
|
||||||
|
Normal
|
||||||
|
</SingleButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelBarStyle === 'compact'}
|
||||||
|
onClick={() => changeStyle('compact')}
|
||||||
|
>
|
||||||
|
Compact
|
||||||
|
</SingleButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelBarStyle === 'ultracompact'}
|
||||||
|
onClick={() => changeStyle('ultracompact')}
|
||||||
|
>
|
||||||
|
Ultra-Compact
|
||||||
|
</SingleButton>
|
||||||
|
</MultiButton>
|
||||||
|
</MarginLine>
|
||||||
|
<MarginLine>
|
||||||
|
<Sub4Title>Bar Types</Sub4Title>
|
||||||
|
<MultiButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelBarType === 'balance'}
|
||||||
|
onClick={() => changeType('balance')}
|
||||||
|
>
|
||||||
|
Balance
|
||||||
|
</SingleButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelBarType === 'details'}
|
||||||
|
onClick={() => changeType('details')}
|
||||||
|
>
|
||||||
|
Proportional
|
||||||
|
</SingleButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelBarType === 'partner'}
|
||||||
|
onClick={() => changeType('partner')}
|
||||||
|
>
|
||||||
|
Partner
|
||||||
|
</SingleButton>
|
||||||
|
</MultiButton>
|
||||||
|
</MarginLine>
|
||||||
|
<MarginLine>
|
||||||
|
<Sub4Title>Sort</Sub4Title>
|
||||||
|
<MultiButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelSort === 'none'}
|
||||||
|
onClick={() => changeSort('none')}
|
||||||
|
>
|
||||||
|
None
|
||||||
|
</SingleButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelSort === 'local'}
|
||||||
|
onClick={() => changeSort('local')}
|
||||||
|
>
|
||||||
|
Local
|
||||||
|
</SingleButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={channelSort === 'balance'}
|
||||||
|
onClick={() => changeSort('balance')}
|
||||||
|
>
|
||||||
|
Balance
|
||||||
|
</SingleButton>
|
||||||
|
</MultiButton>
|
||||||
|
</MarginLine>
|
||||||
|
{channelSort !== 'none' && (
|
||||||
|
<MarginLine>
|
||||||
|
<Sub4Title>Direction</Sub4Title>
|
||||||
|
<MultiButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={sortDirection === 'increase'}
|
||||||
|
onClick={() => changeDirection('increase')}
|
||||||
|
>
|
||||||
|
Increasing
|
||||||
|
</SingleButton>
|
||||||
|
<SingleButton
|
||||||
|
selected={sortDirection === 'decrease'}
|
||||||
|
onClick={() => changeDirection('decrease')}
|
||||||
|
>
|
||||||
|
Decreasing
|
||||||
|
</SingleButton>
|
||||||
|
</MultiButton>
|
||||||
|
</MarginLine>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
|
@ -2,12 +2,16 @@ import React, { useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { useAccountState } from 'src/context/AccountContext';
|
import { useAccountState } from 'src/context/AccountContext';
|
||||||
import { useGetChannelsQuery } from 'src/graphql/queries/__generated__/getChannels.generated';
|
import { useGetChannelsQuery } from 'src/graphql/queries/__generated__/getChannels.generated';
|
||||||
|
import { useConfigState } from 'src/context/ConfigContext';
|
||||||
|
import { sortBy } from 'underscore';
|
||||||
|
import { getPercent } from 'src/utils/helpers';
|
||||||
import { Card } from '../../../components/generic/Styled';
|
import { Card } from '../../../components/generic/Styled';
|
||||||
import { getErrorContent } from '../../../utils/error';
|
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 = () => {
|
||||||
|
const { sortDirection, channelSort } = useConfigState();
|
||||||
const [indexOpen, setIndexOpen] = useState(0);
|
const [indexOpen, setIndexOpen] = useState(0);
|
||||||
|
|
||||||
const { auth } = useAccountState();
|
const { auth } = useAccountState();
|
||||||
|
@ -62,9 +66,26 @@ export const Channels = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getChannels = () => {
|
||||||
|
switch (channelSort) {
|
||||||
|
case 'local': {
|
||||||
|
const newArray = sortBy(data.getChannels, 'local_balance');
|
||||||
|
return sortDirection === 'increase' ? newArray : newArray.reverse();
|
||||||
|
}
|
||||||
|
case 'balance': {
|
||||||
|
const newArray = sortBy(data.getChannels, channel =>
|
||||||
|
getPercent(channel.local_balance, channel.remote_balance)
|
||||||
|
);
|
||||||
|
return sortDirection === 'increase' ? newArray : newArray.reverse();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return data.getChannels;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||||
{data.getChannels.map((channel, index: number) => (
|
{getChannels().map((channel, index: number) => (
|
||||||
<ChannelCard
|
<ChannelCard
|
||||||
channelInfo={channel}
|
channelInfo={channel}
|
||||||
index={index + 1}
|
index={index + 1}
|
||||||
|
@ -74,7 +95,7 @@ export const Channels = () => {
|
||||||
biggest={biggest}
|
biggest={biggest}
|
||||||
biggestPartner={biggestPartner}
|
biggestPartner={biggestPartner}
|
||||||
mostChannels={mostChannels}
|
mostChannels={mostChannels}
|
||||||
biggestBaseFee={biggestBaseFee * 2}
|
biggestBaseFee={biggestBaseFee}
|
||||||
biggestRateFee={biggestRateFee}
|
biggestRateFee={biggestRateFee}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
Loading…
Add table
Reference in a new issue