mirror of
https://github.com/apotdevin/thunderhub.git
synced 2025-02-21 22:11:37 +01:00
feat: ✨ style changes (#48)
* feat: ✨ style changes * chore: 🔧 number format * fix: 🐛 partner capacity * fix: 🐛 small change * chore: 🔧 add channel status * refactor: ♻️ bar width
This commit is contained in:
parent
414c20f053
commit
c2d2dc8e36
47 changed files with 508 additions and 371 deletions
|
@ -39,8 +39,10 @@ module.exports = {
|
|||
],
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'import/no-unresolved': 'off',
|
||||
'import/order': 2,
|
||||
'no-unused-vars': 2,
|
||||
camelcase: 'off',
|
||||
'@typescript-eslint/camelcase': 'off',
|
||||
'react/prop-types': 'off',
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { GraphQLList, GraphQLBoolean } from 'graphql';
|
||||
import { getChannels as getLnChannels, getNode } from 'ln-service';
|
||||
import {
|
||||
getChannels as getLnChannels,
|
||||
getNode,
|
||||
getChannel,
|
||||
getWalletInfo,
|
||||
} from 'ln-service';
|
||||
import { ContextType } from 'api/types/apiTypes';
|
||||
import { toWithError } from 'api/helpers/async';
|
||||
import { logger } from '../../../helpers/logger';
|
||||
import { requestLimiter } from '../../../helpers/rateLimiter';
|
||||
import {
|
||||
|
@ -11,36 +17,6 @@ import {
|
|||
import { defaultParams } from '../../../helpers/defaultProps';
|
||||
import { ChannelType } from '../../types/QueryType';
|
||||
|
||||
interface ChannelListProps {
|
||||
channels: ChannelProps[];
|
||||
}
|
||||
|
||||
interface ChannelProps {
|
||||
capacity: number;
|
||||
commit_transaction_fee: number;
|
||||
commit_transaction_weight: number;
|
||||
id: string;
|
||||
is_active: boolean;
|
||||
is_closing: boolean;
|
||||
is_opening: boolean;
|
||||
is_partner_initiated: boolean;
|
||||
is_private: boolean;
|
||||
is_static_remote_key: boolean;
|
||||
local_balance: number;
|
||||
local_reserve: number;
|
||||
partner_public_key: string;
|
||||
pending_payments: [];
|
||||
received: number;
|
||||
remote_balance: number;
|
||||
remote_reserve: number;
|
||||
sent: number;
|
||||
time_offline: number;
|
||||
time_online: number;
|
||||
transaction_id: string;
|
||||
transaction_vout: number;
|
||||
unsettled_balance: number;
|
||||
}
|
||||
|
||||
export const getChannels = {
|
||||
type: new GraphQLList(ChannelType),
|
||||
args: {
|
||||
|
@ -53,37 +29,83 @@ export const getChannels = {
|
|||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
try {
|
||||
const channelList: ChannelListProps = await getLnChannels({
|
||||
const [walletInfo, walletError] = await toWithError(getWalletInfo({ lnd }));
|
||||
const publicKey = walletInfo?.public_key;
|
||||
|
||||
walletError &&
|
||||
logger.debug('Error getting wallet info in getChannels: %o', walletError);
|
||||
|
||||
const [channelList, channelListError] = await toWithError(
|
||||
getLnChannels({
|
||||
lnd,
|
||||
is_active: params.active,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
const getChannelList = () =>
|
||||
Promise.all(
|
||||
channelList.channels.map(async channel => {
|
||||
const nodeInfo = await getNode({
|
||||
if (channelListError) {
|
||||
logger.error('Error getting channels: %o', channelListError);
|
||||
throw new Error(getErrorMsg(channelListError));
|
||||
}
|
||||
|
||||
const getChannelList = () =>
|
||||
Promise.all(
|
||||
channelList.channels.map(async channel => {
|
||||
const [nodeInfo, nodeError] = await toWithError(
|
||||
getNode({
|
||||
lnd,
|
||||
is_omitting_channels: true,
|
||||
public_key: channel.partner_public_key,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
...channel,
|
||||
time_offline: Math.round((channel.time_offline || 0) / 1000),
|
||||
time_online: Math.round((channel.time_online || 0) / 1000),
|
||||
partner_node_info: {
|
||||
...nodeInfo,
|
||||
},
|
||||
};
|
||||
})
|
||||
);
|
||||
const [channelInfo, channelError] = await toWithError(
|
||||
getChannel({
|
||||
lnd,
|
||||
id: channel.id,
|
||||
})
|
||||
);
|
||||
|
||||
const channels = await getChannelList();
|
||||
return channels;
|
||||
} catch (error) {
|
||||
logger.error('Error getting channels: %o', error);
|
||||
throw new Error(getErrorMsg(error));
|
||||
}
|
||||
nodeError &&
|
||||
logger.debug(
|
||||
`Error getting node with public key ${channel.partner_public_key}: %o`,
|
||||
nodeError
|
||||
);
|
||||
|
||||
channelError &&
|
||||
logger.debug(
|
||||
`Error getting channel with id ${channel.id}: %o`,
|
||||
channelError
|
||||
);
|
||||
|
||||
let partnerFees = {};
|
||||
if (!channelError && publicKey) {
|
||||
const partnerPolicy = channelInfo.policies.filter(
|
||||
policy => policy.public_key !== publicKey
|
||||
);
|
||||
if (partnerPolicy && partnerPolicy.length >= 1) {
|
||||
partnerFees = {
|
||||
base_fee: partnerPolicy[0].base_fee_mtokens || 0,
|
||||
fee_rate: partnerPolicy[0].fee_rate || 0,
|
||||
cltv_delta: partnerPolicy[0].cltv_delta || 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const partner_node_info = {
|
||||
...(!nodeError && nodeInfo),
|
||||
...partnerFees,
|
||||
};
|
||||
|
||||
return {
|
||||
...channel,
|
||||
time_offline: Math.round((channel.time_offline || 0) / 1000),
|
||||
time_online: Math.round((channel.time_online || 0) / 1000),
|
||||
partner_node_info,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const channels = await getChannelList();
|
||||
return channels;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -84,6 +84,9 @@ export const PartnerNodeType = new GraphQLObjectType({
|
|||
channel_count: { type: GraphQLInt },
|
||||
color: { type: GraphQLString },
|
||||
updated_at: { type: GraphQLString },
|
||||
base_fee: { type: GraphQLInt },
|
||||
fee_rate: { type: GraphQLInt },
|
||||
cltv_delta: { type: GraphQLInt },
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"start:two": "cross-env NODE_OPTIONS='--insecure-http-parser' next start -p 3001",
|
||||
"start:compatible": "next start",
|
||||
"start:compatible:two": "next start -p 3001",
|
||||
"lint": "eslint */**/*.{js,ts,tsx} --quiet --fix",
|
||||
"lint": "eslint */**/*.{js,ts,tsx} --fix",
|
||||
"prettier": "prettier --write **/*.{ts,tsx,js,css,html}",
|
||||
"release": "standard-version",
|
||||
"release:push": "standard-version && git push --follow-tags origin master",
|
||||
|
|
|
@ -161,7 +161,7 @@ const BalanceView = () => {
|
|||
<SingleLine>
|
||||
<SubTitle>Channel Balancing</SubTitle>
|
||||
</SingleLine>
|
||||
<Card>
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{renderOutgoing()}
|
||||
{renderIncoming()}
|
||||
<ResponsiveLine>
|
||||
|
|
|
@ -1,18 +1,31 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { useAccountState } from 'src/context/AccountContext';
|
||||
import { useGetChannelAmountInfoQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated';
|
||||
import styled from 'styled-components';
|
||||
import { Channels } from '../src/views/channels/channels/Channels';
|
||||
import { PendingChannels } from '../src/views/channels/pendingChannels/PendingChannels';
|
||||
import { ClosedChannels } from '../src/views/channels/closedChannels/ClosedChannels';
|
||||
import {
|
||||
CardWithTitle,
|
||||
SubTitle,
|
||||
CardTitle,
|
||||
SingleLine,
|
||||
ColorButton,
|
||||
SmallButton,
|
||||
} from '../src/components/generic/Styled';
|
||||
import { useConfigState } from '../src/context/ConfigContext';
|
||||
import { textColorMap } from '../src/styles/Themes';
|
||||
import { mediaWidths } from '../src/styles/Themes';
|
||||
|
||||
const ChannelsCardTitle = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
`;
|
||||
|
||||
const ButtonRow = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
`;
|
||||
|
||||
const ChannelView = () => {
|
||||
const [view, setView] = useState<number>(1);
|
||||
|
@ -22,7 +35,6 @@ const ChannelView = () => {
|
|||
closed: 0,
|
||||
});
|
||||
|
||||
const { theme } = useConfigState();
|
||||
const { auth } = useAccountState();
|
||||
|
||||
const { data } = useGetChannelAmountInfoQuery({
|
||||
|
@ -31,7 +43,7 @@ const ChannelView = () => {
|
|||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.getNodeInfo) {
|
||||
if (data && data.getNodeInfo) {
|
||||
const {
|
||||
active_channels_count,
|
||||
closed_channels_count,
|
||||
|
@ -70,20 +82,20 @@ const ChannelView = () => {
|
|||
|
||||
return (
|
||||
<CardWithTitle>
|
||||
<CardTitle>
|
||||
<ChannelsCardTitle>
|
||||
<SubTitle>{getTitle()}</SubTitle>
|
||||
<SingleLine>
|
||||
<ColorButton color={textColorMap[theme]} onClick={() => setView(1)}>
|
||||
<ButtonRow>
|
||||
<SmallButton onClick={() => setView(1)}>
|
||||
{`Open (${amounts.active})`}
|
||||
</ColorButton>
|
||||
<ColorButton color={textColorMap[theme]} onClick={() => setView(2)}>
|
||||
</SmallButton>
|
||||
<SmallButton onClick={() => setView(2)}>
|
||||
{`Pending (${amounts.pending})`}
|
||||
</ColorButton>
|
||||
<ColorButton color={textColorMap[theme]} onClick={() => setView(3)}>
|
||||
</SmallButton>
|
||||
<SmallButton onClick={() => setView(3)}>
|
||||
{`Closed (${amounts.closed})`}
|
||||
</ColorButton>
|
||||
</SingleLine>
|
||||
</CardTitle>
|
||||
</SmallButton>
|
||||
</ButtonRow>
|
||||
</ChannelsCardTitle>
|
||||
{getView()}
|
||||
</CardWithTitle>
|
||||
);
|
||||
|
|
|
@ -110,7 +110,7 @@ const FeesView = () => {
|
|||
</AdminSwitch>
|
||||
<CardWithTitle>
|
||||
<SubTitle>Channel Fees</SubTitle>
|
||||
<Card>
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getChannelFees.map((channel: any, index: number) => (
|
||||
<FeeCard
|
||||
channelInfo={channel}
|
||||
|
|
|
@ -7,14 +7,12 @@ import {
|
|||
Card,
|
||||
CardWithTitle,
|
||||
CardTitle,
|
||||
ColorButton,
|
||||
SmallButton,
|
||||
SingleLine,
|
||||
} from '../src/components/generic/Styled';
|
||||
import { getErrorContent } from '../src/utils/error';
|
||||
import { LoadingCard } from '../src/components/loading/LoadingCard';
|
||||
import { ForwardCard } from '../src/views/forwards/ForwardsCard';
|
||||
import { textColorMap } from '../src/styles/Themes';
|
||||
import { useConfigState } from '../src/context/ConfigContext';
|
||||
import { ForwardBox } from '../src/views/home/reports/forwardReport';
|
||||
|
||||
const timeMap: { [key: string]: string } = {
|
||||
|
@ -28,7 +26,6 @@ const ForwardsView = () => {
|
|||
const [time, setTime] = useState('week');
|
||||
const [indexOpen, setIndexOpen] = useState(0);
|
||||
|
||||
const { theme } = useConfigState();
|
||||
const { auth } = useAccountState();
|
||||
|
||||
const { loading, data } = useGetForwardsQuery({
|
||||
|
@ -42,17 +39,13 @@ const ForwardsView = () => {
|
|||
}
|
||||
|
||||
const renderButton = (selectedTime: string, title: string) => (
|
||||
<ColorButton
|
||||
color={textColorMap[theme]}
|
||||
onClick={() => setTime(selectedTime)}
|
||||
selected={time === selectedTime}
|
||||
>
|
||||
{title}
|
||||
</ColorButton>
|
||||
<SmallButton onClick={() => setTime(selectedTime)}>{title}</SmallButton>
|
||||
);
|
||||
|
||||
const renderNoForwards = () => (
|
||||
<p>{`Your node has not forwarded any payments ${timeMap[time]}.`}</p>
|
||||
<Card>
|
||||
<p>{`Your node has not forwarded any payments ${timeMap[time]}.`}</p>
|
||||
</Card>
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -68,8 +61,8 @@ const ForwardsView = () => {
|
|||
{renderButton('threeMonths', '3M')}
|
||||
</SingleLine>
|
||||
</CardTitle>
|
||||
<Card>
|
||||
{data.getForwards.forwards.length <= 0 && renderNoForwards()}
|
||||
{data.getForwards.forwards.length <= 0 && renderNoForwards()}
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getForwards.forwards.map((forward: any, index: number) => (
|
||||
<ForwardCard
|
||||
forward={forward}
|
||||
|
|
|
@ -28,7 +28,7 @@ const PeersView = () => {
|
|||
<AddPeer />
|
||||
<CardWithTitle>
|
||||
<SubTitle>Peers</SubTitle>
|
||||
<Card>
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getPeers.map((peer: any, index: number) => (
|
||||
<PeersCard
|
||||
peer={peer}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { SingleLine, SimpleButton } from '../src/components/generic/Styled';
|
||||
import { SingleLine } from '../src/components/generic/Styled';
|
||||
import { InterfaceSettings } from '../src/views/settings/Interface';
|
||||
import { textColor } from '../src/styles/Themes';
|
||||
import { AccountSettings } from '../src/views/settings/Account';
|
||||
import { DangerView } from '../src/views/settings/Danger';
|
||||
import { CurrentSettings } from '../src/views/settings/Current';
|
||||
|
@ -19,14 +18,6 @@ export const SettingsLine = styled(SingleLine)`
|
|||
margin: 8px 0;
|
||||
`;
|
||||
|
||||
export const SettingsButton = styled(SimpleButton)`
|
||||
padding: 8px;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${textColor};
|
||||
}
|
||||
`;
|
||||
|
||||
const SettingsView = () => {
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -99,7 +99,7 @@ const TradingView = () => {
|
|||
<Card bottom={'16px'}>
|
||||
<OfferFilters offerFilters={queryObject} />
|
||||
</Card>
|
||||
<Card bottom={'8px'}>
|
||||
<Card bottom={'8px'} mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{amountOfOffers <= 0 && <DarkSubTitle>No Offers Found</DarkSubTitle>}
|
||||
{data.getOffers.map((offer: any, index: number) => (
|
||||
<OfferCard
|
||||
|
|
|
@ -47,7 +47,7 @@ const TransactionsView = () => {
|
|||
<FlowBox />
|
||||
<CardWithTitle>
|
||||
<SubTitle>Transactions</SubTitle>
|
||||
<Card bottom={'8px'}>
|
||||
<Card bottom={'8px'} mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{resumeList.map((entry: any, index: number) => {
|
||||
if (entry.type === 'invoice') {
|
||||
return (
|
||||
|
|
|
@ -25,7 +25,7 @@ export const AuthSSOCheck = ({ cookieParam }: AuthCheckProps) => {
|
|||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (cookieParam && !loading && data?.getAuthToken && !ssoSaved) {
|
||||
if (cookieParam && !loading && data && data.getAuthToken && !ssoSaved) {
|
||||
Cookies.set('SSOAuth', data.getAuthToken, {
|
||||
sameSite: 'strict',
|
||||
});
|
||||
|
|
|
@ -40,7 +40,7 @@ export const ServerAccounts = () => {
|
|||
}, [dispatch]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!loading && data?.getServerAccounts) {
|
||||
if (!loading && data && data.getServerAccounts) {
|
||||
const accountsToAdd = data.getServerAccounts.map(a => {
|
||||
const type = a?.id === SSO_ACCOUNT ? SSO_ACCOUNT : SERVER_ACCOUNT;
|
||||
return {
|
||||
|
|
|
@ -42,7 +42,7 @@ export const ChatInit = () => {
|
|||
}, [dispatch, getMessages, account]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!initLoading && !initError && initData?.getMessages) {
|
||||
if (!initLoading && !initError && initData && initData.getMessages) {
|
||||
const { messages } = initData.getMessages;
|
||||
|
||||
if (messages.length <= 0) {
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import styled from 'styled-components';
|
||||
import {
|
||||
progressBackground,
|
||||
progressFirst,
|
||||
progressSecond,
|
||||
mediaWidths,
|
||||
cardColor,
|
||||
cardBorderColor,
|
||||
chartColors,
|
||||
} from '../../styles/Themes';
|
||||
|
||||
export const Progress = styled.div`
|
||||
|
@ -20,13 +19,18 @@ interface ProgressBar {
|
|||
|
||||
export const ProgressBar = styled.div<ProgressBar>`
|
||||
height: 10px;
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
rgba(255, 255, 255, 0.3),
|
||||
rgba(0, 0, 0, 0.05)
|
||||
);
|
||||
background-color: ${({ order }) =>
|
||||
order === 2 ? progressFirst : progressSecond};
|
||||
background-color: ${({ order }) => {
|
||||
switch (order) {
|
||||
case 1:
|
||||
return chartColors.lightblue;
|
||||
case 2:
|
||||
return chartColors.green;
|
||||
case 3:
|
||||
return chartColors.orange;
|
||||
default:
|
||||
return chartColors.purple;
|
||||
}
|
||||
}};
|
||||
width: ${({ percent }) => `${percent}%`};
|
||||
`;
|
||||
|
||||
|
@ -47,8 +51,8 @@ export const NodeTitle = styled.div`
|
|||
export const StatusLine = styled.div`
|
||||
width: 100%;
|
||||
position: relative;
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
right: -12px;
|
||||
top: -12px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin: 0 0 -8px 0;
|
||||
|
|
|
@ -7,11 +7,13 @@ import {
|
|||
smallLinkColor,
|
||||
unSelectedNavButton,
|
||||
textColor,
|
||||
buttonBorderColor,
|
||||
chartLinkColor,
|
||||
inverseTextColor,
|
||||
separationColor,
|
||||
mediaWidths,
|
||||
colorButtonBackground,
|
||||
colorButtonBorder,
|
||||
hoverTextColor,
|
||||
} from '../../styles/Themes';
|
||||
|
||||
export const CardWithTitle = styled.div`
|
||||
|
@ -29,6 +31,7 @@ export interface CardProps {
|
|||
bottom?: string;
|
||||
cardPadding?: string;
|
||||
mobileCardPadding?: string;
|
||||
mobileNoBackground?: boolean;
|
||||
}
|
||||
|
||||
export const Card = styled.div<CardProps>`
|
||||
|
@ -41,6 +44,13 @@ export const Card = styled.div<CardProps>`
|
|||
width: 100%;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
${({ mobileNoBackground }) =>
|
||||
mobileNoBackground &&
|
||||
css`
|
||||
background: unset;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
`}
|
||||
${({ cardPadding, mobileCardPadding }) =>
|
||||
mobileCardPadding
|
||||
? css`
|
||||
|
@ -70,6 +80,7 @@ interface SubCardProps {
|
|||
color?: string;
|
||||
padding?: string;
|
||||
withMargin?: string;
|
||||
noCard?: boolean;
|
||||
}
|
||||
|
||||
export const SubCard = styled.div<SubCardProps>`
|
||||
|
@ -146,27 +157,6 @@ export const ColumnLine = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
export const SimpleButton = styled.button<{ enabled?: boolean }>`
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
color: ${({ enabled = true }) => (enabled ? textColor : unSelectedNavButton)};
|
||||
border: 1px solid ${buttonBorderColor};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 5px;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
export const SimpleInverseButton = styled(SimpleButton)`
|
||||
color: ${({ enabled = true }: { enabled?: boolean }) =>
|
||||
enabled ? inverseTextColor : unSelectedNavButton};
|
||||
`;
|
||||
|
||||
interface DarkProps {
|
||||
fontSize?: string;
|
||||
withMargin?: string;
|
||||
|
@ -178,17 +168,24 @@ export const DarkSubTitle = styled.div<DarkProps>`
|
|||
margin: ${({ withMargin }) => (withMargin ? withMargin : '0')};
|
||||
`;
|
||||
|
||||
interface ColorProps {
|
||||
color: string;
|
||||
selected?: boolean;
|
||||
}
|
||||
export const ColorButton = styled(SimpleButton)<ColorProps>`
|
||||
color: ${({ selected }) => (selected ? textColor : chartLinkColor)};
|
||||
border: ${({ selected, color }) => (selected ? `1px solid ${color}` : '')};
|
||||
export const SmallButton = styled.button`
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 5px;
|
||||
white-space: nowrap;
|
||||
color: ${chartLinkColor};
|
||||
background-color: ${colorButtonBackground};
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${({ color }: ColorProps) => color};
|
||||
color: ${textColor};
|
||||
color: ${hoverTextColor};
|
||||
background-color: ${colorButtonBorder};
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
|
@ -9,11 +9,19 @@ import { X } from 'react-feather';
|
|||
import { SmallLink, DarkSubTitle, OverflowText, SingleLine } from './Styled';
|
||||
import { StatusDot, DetailLine } from './CardGeneric';
|
||||
|
||||
const shorten = (text: string): string => {
|
||||
const amount = 6;
|
||||
const beginning = text.slice(0, amount);
|
||||
const end = text.slice(text.length - amount);
|
||||
|
||||
return `${beginning}...${end}`;
|
||||
};
|
||||
|
||||
export const getTransactionLink = (transaction: string) => {
|
||||
const link = `https://www.blockchain.com/btc/tx/${transaction}`;
|
||||
return (
|
||||
<SmallLink href={link} target="_blank">
|
||||
{transaction}
|
||||
{shorten(transaction)}
|
||||
</SmallLink>
|
||||
);
|
||||
};
|
||||
|
@ -22,7 +30,7 @@ export const getNodeLink = (publicKey: string) => {
|
|||
const link = `https://1ml.com/node/${publicKey}`;
|
||||
return (
|
||||
<SmallLink href={link} target="_blank">
|
||||
{publicKey}
|
||||
{shorten(publicKey)}
|
||||
</SmallLink>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -27,7 +27,7 @@ export const RemovePeerModal = ({
|
|||
peerAlias,
|
||||
}: RemovePeerProps) => {
|
||||
const [removePeer, { loading }] = useRemovePeerMutation({
|
||||
onCompleted: data => {
|
||||
onCompleted: () => {
|
||||
toast.success('Peer Removed');
|
||||
},
|
||||
onError: error => {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useRouter } from 'next/router';
|
|||
import { toast } from 'react-toastify';
|
||||
import { useAccountState } from 'src/context/AccountContext';
|
||||
import { useGetNodeInfoQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated';
|
||||
import { useStatusDispatch, useStatusState } from '../../context/StatusContext';
|
||||
import { useStatusDispatch } from '../../context/StatusContext';
|
||||
import { appendBasePath } from '../../utils/basePath';
|
||||
|
||||
export const StatusCheck = () => {
|
||||
|
@ -11,10 +11,8 @@ export const StatusCheck = () => {
|
|||
const { push } = useRouter();
|
||||
|
||||
const { account, auth } = useAccountState();
|
||||
const { connected } = useStatusState();
|
||||
|
||||
const { data, loading, error, stopPolling } = useGetNodeInfoQuery({
|
||||
skip: !auth || !connected,
|
||||
skip: !auth,
|
||||
fetchPolicy: 'network-only',
|
||||
variables: { auth },
|
||||
pollInterval: 10000,
|
||||
|
|
|
@ -17,6 +17,7 @@ type State = {
|
|||
hideNonVerified: boolean;
|
||||
maxFee: number;
|
||||
chatPollingSpeed: number;
|
||||
channelBarType: 'normal' | 'partner';
|
||||
};
|
||||
|
||||
type ConfigInitProps = {
|
||||
|
@ -36,6 +37,7 @@ type ActionType = {
|
|||
hideNonVerified?: boolean;
|
||||
maxFee?: number;
|
||||
chatPollingSpeed?: number;
|
||||
channelBarType?: 'normal' | 'partner';
|
||||
};
|
||||
|
||||
type Dispatch = (action: ActionType) => void;
|
||||
|
@ -63,6 +65,7 @@ const initialState: State = {
|
|||
hideNonVerified: false,
|
||||
maxFee: 20,
|
||||
chatPollingSpeed: 1000,
|
||||
channelBarType: 'normal',
|
||||
};
|
||||
|
||||
const stateReducer = (state: State, action: ActionType): State => {
|
||||
|
|
|
@ -40,7 +40,14 @@ export type GetChannelsQuery = { __typename?: 'Query' } & {
|
|||
partner_node_info?: Types.Maybe<
|
||||
{ __typename?: 'partnerNodeType' } & Pick<
|
||||
Types.PartnerNodeType,
|
||||
'alias' | 'capacity' | 'channel_count' | 'color' | 'updated_at'
|
||||
| 'alias'
|
||||
| 'capacity'
|
||||
| 'channel_count'
|
||||
| 'color'
|
||||
| 'updated_at'
|
||||
| 'base_fee'
|
||||
| 'fee_rate'
|
||||
| 'cltv_delta'
|
||||
>
|
||||
>;
|
||||
}
|
||||
|
@ -80,6 +87,9 @@ export const GetChannelsDocument = gql`
|
|||
channel_count
|
||||
color
|
||||
updated_at
|
||||
base_fee
|
||||
fee_rate
|
||||
cltv_delta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ export const GET_CHANNELS = gql`
|
|||
channel_count
|
||||
color
|
||||
updated_at
|
||||
base_fee
|
||||
fee_rate
|
||||
cltv_delta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,6 +261,9 @@ export type PartnerNodeType = {
|
|||
channel_count?: Maybe<Scalars['Int']>;
|
||||
color?: Maybe<Scalars['String']>;
|
||||
updated_at?: Maybe<Scalars['String']>;
|
||||
base_fee?: Maybe<Scalars['Int']>;
|
||||
fee_rate?: Maybe<Scalars['Int']>;
|
||||
cltv_delta?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type ClosedChannelType = {
|
||||
|
|
|
@ -61,7 +61,7 @@ export const Header = () => {
|
|||
<Link to={connected ? '/home' : '/'} underline={'transparent'}>
|
||||
<HeaderTitle withPadding={!connected}>
|
||||
<IconPadding>
|
||||
<Cpu color={'white'} />
|
||||
<Cpu color={'white'} size={18} />
|
||||
</IconPadding>
|
||||
ThunderHub
|
||||
</HeaderTitle>
|
||||
|
|
|
@ -35,7 +35,9 @@ export const getValue = ({
|
|||
if (currency === 'btc') {
|
||||
if (!value) return '₿0.0';
|
||||
const amountInBtc = value / 100000000;
|
||||
return `₿${amountInBtc}`;
|
||||
const rounded = Math.round(amountInBtc * 10000) / 10000;
|
||||
|
||||
return `₿${rounded}`;
|
||||
}
|
||||
if (currency === 'sat') {
|
||||
const breakAmount = breakNumber
|
||||
|
@ -107,9 +109,9 @@ export const formatSeconds = (seconds: number): string | null => {
|
|||
const m = Math.floor((seconds % 3600) / 60);
|
||||
const s = Math.floor(seconds % 60);
|
||||
|
||||
const dDisplay = d > 0 ? d + (d == 1 ? ' day, ' : ' days, ') : '';
|
||||
const hDisplay = h > 0 ? h + (h == 1 ? ' hour, ' : ' hours, ') : '';
|
||||
const mDisplay = m > 0 ? m + (m == 1 ? ' minute, ' : ' minutes, ') : '';
|
||||
const sDisplay = s > 0 ? s + (s == 1 ? ' second' : ' seconds') : '';
|
||||
const dDisplay = d > 0 ? `${d}d ` : '';
|
||||
const hDisplay = h > 0 ? `${h}h ` : '';
|
||||
const mDisplay = m > 0 ? `${m}m ` : '';
|
||||
const sDisplay = s > 0 ? `${s}s` : '';
|
||||
return dDisplay + hDisplay + mDisplay + sDisplay;
|
||||
};
|
||||
|
|
|
@ -28,7 +28,7 @@ export const ChainTransactions = () => {
|
|||
return (
|
||||
<CardWithTitle>
|
||||
<SubTitle>Chain Transactions</SubTitle>
|
||||
<Card>
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getChainTransactions.map((transaction: any, index: number) => (
|
||||
<TransactionsCard
|
||||
transaction={transaction}
|
||||
|
|
|
@ -28,7 +28,7 @@ export const ChainUtxos = () => {
|
|||
return (
|
||||
<CardWithTitle>
|
||||
<SubTitle>Unspent Utxos</SubTitle>
|
||||
<Card>
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getUtxos.map((utxo: any, index: number) => (
|
||||
<UtxoCard
|
||||
utxo={utxo}
|
||||
|
|
|
@ -2,11 +2,11 @@ import React, { useState } from 'react';
|
|||
import ReactTooltip from 'react-tooltip';
|
||||
import styled from 'styled-components';
|
||||
import { ArrowDown, ArrowUp, EyeOff } from 'react-feather';
|
||||
import { mediaWidths } from 'src/styles/Themes';
|
||||
import { ChannelType } from 'src/graphql/types';
|
||||
import { getPercent, formatSeconds } from '../../../utils/helpers';
|
||||
import {
|
||||
Progress,
|
||||
ProgressBar,
|
||||
NodeTitle,
|
||||
StatusLine,
|
||||
MainInfo,
|
||||
} from '../../../components/generic/CardGeneric';
|
||||
|
@ -16,10 +16,12 @@ import {
|
|||
Sub4Title,
|
||||
RightAlign,
|
||||
ResponsiveLine,
|
||||
ResponsiveSingle,
|
||||
ResponsiveCol,
|
||||
DarkSubTitle,
|
||||
} from '../../../components/generic/Styled';
|
||||
import { useConfigState } from '../../../context/ConfigContext';
|
||||
import {
|
||||
useConfigState,
|
||||
useConfigDispatch,
|
||||
} from '../../../context/ConfigContext';
|
||||
import {
|
||||
getStatusDot,
|
||||
getTooltipType,
|
||||
|
@ -37,23 +39,69 @@ import { getPrice } from '../../../components/price/Price';
|
|||
import { usePriceState } from '../../../context/PriceContext';
|
||||
|
||||
const IconPadding = styled.div`
|
||||
margin-left: 16px;
|
||||
margin-right: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 8px;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
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) => {
|
||||
return status ? <ArrowDown size={18} /> : <ArrowUp size={18} />;
|
||||
return status ? <ArrowDown size={14} /> : <ArrowUp size={14} />;
|
||||
};
|
||||
|
||||
const getPrivate = (status: boolean) => {
|
||||
return status && <EyeOff />;
|
||||
return status && <EyeOff size={14} />;
|
||||
};
|
||||
|
||||
const getBar = (top: number, bottom: number) => {
|
||||
const percent = (top / bottom) * 100;
|
||||
return Math.min(percent, 100);
|
||||
};
|
||||
|
||||
interface ChannelCardProps {
|
||||
channelInfo: any;
|
||||
channelInfo: ChannelType;
|
||||
index: number;
|
||||
setIndexOpen: (index: number) => void;
|
||||
indexOpen: number;
|
||||
biggest: number;
|
||||
biggestPartner: number;
|
||||
mostChannels: number;
|
||||
biggestBaseFee: number;
|
||||
biggestRateFee: number;
|
||||
}
|
||||
|
||||
export const ChannelCard = ({
|
||||
|
@ -61,7 +109,14 @@ export const ChannelCard = ({
|
|||
index,
|
||||
setIndexOpen,
|
||||
indexOpen,
|
||||
biggest,
|
||||
biggestPartner,
|
||||
mostChannels,
|
||||
biggestBaseFee,
|
||||
biggestRateFee,
|
||||
}: ChannelCardProps) => {
|
||||
const { channelBarType } = useConfigState();
|
||||
const dispatch = useConfigDispatch();
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
const { theme, currency, displayValues } = useConfigState();
|
||||
|
@ -98,10 +153,12 @@ export const ChannelCard = ({
|
|||
|
||||
const {
|
||||
alias,
|
||||
capacity: partnerNodeCapacity,
|
||||
capacity: partnerNodeCapacity = 0,
|
||||
channel_count,
|
||||
color: nodeColor,
|
||||
updated_at,
|
||||
base_fee,
|
||||
fee_rate,
|
||||
cltv_delta,
|
||||
} = partner_node_info;
|
||||
|
||||
const formatBalance = format({ amount: capacity });
|
||||
|
@ -123,10 +180,20 @@ export const ChannelCard = ({
|
|||
}
|
||||
};
|
||||
|
||||
const handleBarClick = () => {
|
||||
dispatch({
|
||||
type: 'change',
|
||||
channelBarType: channelBarType === 'normal' ? 'partner' : 'normal',
|
||||
});
|
||||
};
|
||||
|
||||
const renderDetails = () => {
|
||||
return (
|
||||
<>
|
||||
<Separation />
|
||||
{renderLine('Status:', is_active ? 'Active' : 'Not Active')}
|
||||
{renderLine('Is Opening:', is_opening ? 'True' : 'False')}
|
||||
{renderLine('Is Closing:', is_closing ? 'True' : 'False')}
|
||||
{renderLine(
|
||||
'Balancedness:',
|
||||
getPercent(local_balance, remote_balance) / 100
|
||||
|
@ -154,6 +221,9 @@ export const ChannelCard = ({
|
|||
'Last Update:',
|
||||
`${getDateDif(updated_at)} ago (${getFormatDate(updated_at)})`
|
||||
)}
|
||||
{renderLine('Base Fee:', `${base_fee} mSats`)}
|
||||
{renderLine('Fee Rate:', `${fee_rate} sats/MSats`)}
|
||||
{renderLine('CTLV Delta:', cltv_delta)}
|
||||
<AdminSwitch>
|
||||
<Separation />
|
||||
<RightAlign>
|
||||
|
@ -170,37 +240,86 @@ export const ChannelCard = ({
|
|||
);
|
||||
};
|
||||
|
||||
const renderBars = () => {
|
||||
switch (channelBarType) {
|
||||
case 'partner':
|
||||
return (
|
||||
<>
|
||||
<ProgressBar
|
||||
order={0}
|
||||
percent={getBar(Number(partnerNodeCapacity), biggestPartner)}
|
||||
/>
|
||||
<ProgressBar
|
||||
order={3}
|
||||
percent={getBar(channel_count, mostChannels)}
|
||||
/>
|
||||
<ProgressBar order={1} percent={getBar(base_fee, biggestBaseFee)} />
|
||||
<ProgressBar order={2} percent={getBar(fee_rate, biggestRateFee)} />
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
<ProgressBar order={0} percent={getBar(local_balance, biggest)} />
|
||||
<ProgressBar order={1} percent={getBar(remote_balance, biggest)} />
|
||||
<ProgressBar order={2} percent={getBar(received, biggest)} />
|
||||
<ProgressBar order={3} percent={getBar(sent, biggest)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const renderBarsInfo = () => {
|
||||
switch (channelBarType) {
|
||||
case 'partner':
|
||||
return (
|
||||
<>
|
||||
<div>{`Partner Capacity: ${nodeCapacity}`}</div>
|
||||
<div>{`Partner Channels: ${channel_count}`}</div>
|
||||
<div>{`Partner Base Fee: ${base_fee} mSats`}</div>
|
||||
<div>{`Partner Fee Rate: ${fee_rate} sats/MSats`}</div>
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
<div>{`Local Balance: ${formatLocal}`}</div>
|
||||
<div>{`Remote Balance: ${formatRemote}`}</div>
|
||||
<div>{`Received: ${formatReceived}`}</div>
|
||||
<div>{`Sent: ${formatSent}`}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SubCard color={nodeColor} key={`${index}-${id}`}>
|
||||
<MainInfo onClick={() => handleClick()}>
|
||||
<StatusLine>
|
||||
{getStatusDot(is_active, 'active')}
|
||||
{getStatusDot(is_opening, 'opening')}
|
||||
{getStatusDot(is_closing, 'closing')}
|
||||
</StatusLine>
|
||||
<ResponsiveLine>
|
||||
<NodeTitle style={{ flexGrow: 2 }}>
|
||||
<SubCard key={`${index}-${id}`} noCard={true}>
|
||||
<StatusLine>
|
||||
{getStatusDot(is_active, 'active')}
|
||||
{getStatusDot(is_opening, 'opening')}
|
||||
{getStatusDot(is_closing, 'closing')}
|
||||
</StatusLine>
|
||||
<ResponsiveLine>
|
||||
<NodeTitle style={{ flexGrow: 2 }}>
|
||||
<MainInfo onClick={() => handleClick()}>
|
||||
{alias || partner_public_key?.substring(0, 6)}
|
||||
</NodeTitle>
|
||||
<ResponsiveSingle>
|
||||
{formatBalance}
|
||||
<IconPadding>
|
||||
{getPrivate(is_private)}
|
||||
{getSymbol(is_partner_initiated)}
|
||||
</IconPadding>
|
||||
<ResponsiveCol>
|
||||
<Progress data-tip data-for={`node_balance_tip_${index}`}>
|
||||
<ProgressBar
|
||||
percent={getPercent(local_balance, remote_balance)}
|
||||
/>
|
||||
</Progress>
|
||||
<Progress data-tip data-for={`node_activity_tip_${index}`}>
|
||||
<ProgressBar order={2} percent={getPercent(received, sent)} />
|
||||
</Progress>
|
||||
</ResponsiveCol>
|
||||
</ResponsiveSingle>
|
||||
</ResponsiveLine>
|
||||
</MainInfo>
|
||||
<DarkSubTitle>{formatBalance}</DarkSubTitle>
|
||||
</MainInfo>
|
||||
</NodeTitle>
|
||||
<BarSide>
|
||||
<StatsColumn
|
||||
data-tip
|
||||
data-for={`node_balance_tip_${index}`}
|
||||
onClick={handleBarClick}
|
||||
>
|
||||
{renderBars()}
|
||||
</StatsColumn>
|
||||
</BarSide>
|
||||
<IconPadding>
|
||||
{getPrivate(is_private)}
|
||||
{getSymbol(is_partner_initiated)}
|
||||
</IconPadding>
|
||||
</ResponsiveLine>
|
||||
{index === indexOpen && renderDetails()}
|
||||
<ReactTooltip
|
||||
id={`node_balance_tip_${index}`}
|
||||
|
@ -208,17 +327,7 @@ export const ChannelCard = ({
|
|||
place={'bottom'}
|
||||
type={tooltipType}
|
||||
>
|
||||
<div>{`Local Balance: ${formatLocal}`}</div>
|
||||
<div>{`Remote Balance: ${formatRemote}`}</div>
|
||||
</ReactTooltip>
|
||||
<ReactTooltip
|
||||
id={`node_activity_tip_${index}`}
|
||||
effect={'solid'}
|
||||
place={'bottom'}
|
||||
type={tooltipType}
|
||||
>
|
||||
<div>{`Received: ${formatReceived}`}</div>
|
||||
<div>{`Sent: ${formatSent}`}</div>
|
||||
{renderBarsInfo()}
|
||||
</ReactTooltip>
|
||||
<Modal isOpen={modalOpen} closeCallback={() => setModalOpen(false)}>
|
||||
<CloseChannel
|
||||
|
|
|
@ -23,15 +23,59 @@ export const Channels = () => {
|
|||
return <LoadingCard noTitle={true} />;
|
||||
}
|
||||
|
||||
let biggest = 0;
|
||||
let biggestPartner = 0;
|
||||
let mostChannels = 0;
|
||||
let biggestBaseFee = 0;
|
||||
let biggestRateFee = 0;
|
||||
|
||||
for (let i = 0; i < data.getChannels.length; i++) {
|
||||
const channel = data.getChannels[i];
|
||||
const {
|
||||
local_balance,
|
||||
remote_balance,
|
||||
sent,
|
||||
received,
|
||||
partner_node_info = {},
|
||||
} = channel;
|
||||
|
||||
const { capacity, channel_count, base_fee, fee_rate } = partner_node_info;
|
||||
const partner = Number(capacity) || 0;
|
||||
const channels = Number(channel_count) || 0;
|
||||
|
||||
const max = Math.max(local_balance, remote_balance, sent, received);
|
||||
|
||||
if (max > biggest) {
|
||||
biggest = max;
|
||||
}
|
||||
if (partner > biggestPartner) {
|
||||
biggestPartner = partner;
|
||||
}
|
||||
if (channels > mostChannels) {
|
||||
mostChannels = channels;
|
||||
}
|
||||
if (base_fee > biggestBaseFee) {
|
||||
biggestBaseFee = base_fee;
|
||||
}
|
||||
if (fee_rate > biggestRateFee) {
|
||||
biggestRateFee = fee_rate;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
{data.getChannels.map((channel: any, index: number) => (
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getChannels.map((channel, index: number) => (
|
||||
<ChannelCard
|
||||
channelInfo={channel}
|
||||
index={index + 1}
|
||||
setIndexOpen={setIndexOpen}
|
||||
indexOpen={indexOpen}
|
||||
key={`${index}-${channel.id}`}
|
||||
biggest={biggest}
|
||||
biggestPartner={biggestPartner}
|
||||
mostChannels={mostChannels}
|
||||
biggestBaseFee={biggestBaseFee * 2}
|
||||
biggestRateFee={biggestRateFee}
|
||||
/>
|
||||
))}
|
||||
</Card>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { ClosedChannelType } from 'src/graphql/types';
|
||||
import { NodeTitle, MainInfo } from '../../../components/generic/CardGeneric';
|
||||
import {
|
||||
SubCard,
|
||||
|
@ -20,7 +21,7 @@ const Padding = styled.div`
|
|||
`;
|
||||
|
||||
interface PendingCardProps {
|
||||
channelInfo: any;
|
||||
channelInfo: ClosedChannelType;
|
||||
index: number;
|
||||
setIndexOpen: (index: number) => void;
|
||||
indexOpen: number;
|
||||
|
|
|
@ -23,8 +23,8 @@ export const ClosedChannels = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
{data.getClosedChannels.map((channel: any, index: number) => (
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getClosedChannels.map((channel, index: number) => (
|
||||
<ClosedCard
|
||||
channelInfo={channel}
|
||||
key={index}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
import { PendingChannelType } from 'src/graphql/types';
|
||||
import { getPercent } from '../../../utils/helpers';
|
||||
import {
|
||||
Progress,
|
||||
|
@ -29,32 +30,8 @@ import {
|
|||
import { getPrice } from '../../../components/price/Price';
|
||||
import { usePriceState } from '../../../context/PriceContext';
|
||||
|
||||
interface ChannelProps {
|
||||
close_transaction_id: string;
|
||||
is_active: boolean;
|
||||
is_closing: boolean;
|
||||
is_opening: boolean;
|
||||
local_balance: number;
|
||||
local_reserve: number;
|
||||
partner_public_key: string;
|
||||
received: number;
|
||||
remote_balance: number;
|
||||
remote_reserve: number;
|
||||
sent: number;
|
||||
transaction_fee: number;
|
||||
transaction_id: string;
|
||||
transaction_vout: number;
|
||||
partner_node_info: {
|
||||
alias: string;
|
||||
capacity: string;
|
||||
channelCount: string;
|
||||
color: string;
|
||||
updated_at: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface PendingCardProps {
|
||||
channelInfo: ChannelProps;
|
||||
channelInfo: PendingChannelType;
|
||||
index: number;
|
||||
setIndexOpen: (index: number) => void;
|
||||
indexOpen: number;
|
||||
|
@ -93,7 +70,7 @@ export const PendingCard = ({
|
|||
const {
|
||||
alias,
|
||||
capacity,
|
||||
channelCount,
|
||||
channel_count,
|
||||
color: nodeColor,
|
||||
updated_at,
|
||||
} = partner_node_info;
|
||||
|
@ -132,7 +109,7 @@ export const PendingCard = ({
|
|||
{renderLine('Remote Reserve:', remote_reserve)}
|
||||
<Sub4Title>Partner Node Info</Sub4Title>
|
||||
{renderLine('Node Capacity:', capacity)}
|
||||
{renderLine('Channels:', channelCount)}
|
||||
{renderLine('Channels:', channel_count)}
|
||||
{renderLine(
|
||||
'Last Update:',
|
||||
`${getDateDif(updated_at)} ago (${getFormatDate(updated_at)})`
|
||||
|
|
|
@ -23,8 +23,8 @@ export const PendingChannels = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
{data.getPendingChannels.map((channel: any, index: number) => (
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getPendingChannels.map((channel, index: number) => (
|
||||
<PendingCard
|
||||
channelInfo={channel}
|
||||
key={index}
|
||||
|
|
|
@ -39,7 +39,7 @@ const SendButton = ({ amount }: SendButtonProps) => {
|
|||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!loading && data?.sendMessage >= 0) {
|
||||
if (!loading && data && data.sendMessage >= 0) {
|
||||
dispatch({
|
||||
type: 'newChat',
|
||||
newChat: {
|
||||
|
|
|
@ -35,7 +35,7 @@ export const ChatInput = ({
|
|||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!loading && data?.sendMessage >= 0) {
|
||||
if (!loading && data && data.sendMessage >= 0) {
|
||||
setMessage('');
|
||||
dispatch({
|
||||
type: 'newChat',
|
||||
|
|
|
@ -52,7 +52,7 @@ export const ContactCard = ({
|
|||
}, [contact, sender, alias, contactSender, getInfo, setUser, user]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!loading && data?.getNode) {
|
||||
if (!loading && data && data.getNode) {
|
||||
const { alias } = data.getNode;
|
||||
const name =
|
||||
alias && alias !== '' ? alias : contactSender.substring(0, 6);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React, { useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { ArrowUp, Zap, Anchor, Pocket, ArrowDown, X } from 'react-feather';
|
||||
import { Zap, Anchor, Pocket } from 'react-feather';
|
||||
import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
|
||||
import {
|
||||
Card,
|
||||
CardWithTitle,
|
||||
SubTitle,
|
||||
Separation,
|
||||
DarkSubTitle,
|
||||
ColorButton,
|
||||
ResponsiveLine,
|
||||
} from '../../../components/generic/Styled';
|
||||
import { LoadingCard } from '../../../components/loading/LoadingCard';
|
||||
|
@ -35,8 +35,14 @@ const Tile = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
const ButtonRow = styled.div`
|
||||
const AccountButtonWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const sectionColor = '#FFD300';
|
||||
|
@ -118,14 +124,24 @@ export const AccountInfo = () => {
|
|||
);
|
||||
|
||||
const renderButtons = (send: string, receive: string) => (
|
||||
<>
|
||||
<ColorButton color={sectionColor} onClick={() => setState(send)}>
|
||||
<ArrowUp size={18} />
|
||||
<AccountButtonWrapper>
|
||||
<ColorButton
|
||||
fullWidth={true}
|
||||
withMargin={'0 0 2px'}
|
||||
mobileMargin={'8px 4px 0 0'}
|
||||
onClick={() => setState(send)}
|
||||
>
|
||||
Send
|
||||
</ColorButton>
|
||||
<ColorButton color={sectionColor} onClick={() => setState(receive)}>
|
||||
<ArrowDown size={18} />
|
||||
<ColorButton
|
||||
fullWidth={true}
|
||||
withMargin={'2px 0 0'}
|
||||
mobileMargin={'8px 0 0 4px'}
|
||||
onClick={() => setState(receive)}
|
||||
>
|
||||
Receive
|
||||
</ColorButton>
|
||||
</>
|
||||
</AccountButtonWrapper>
|
||||
);
|
||||
|
||||
const renderLnAccount = () => (
|
||||
|
@ -137,14 +153,10 @@ export const AccountInfo = () => {
|
|||
</Tile>
|
||||
{renderBalances(formatCCB, formatPCB)}
|
||||
<AdminSwitch>
|
||||
<ButtonRow>
|
||||
{showLn && showChain && renderButtons('send_ln', 'receive_ln')}
|
||||
{showLn && !showChain && (
|
||||
<ColorButton color={sectionColor} onClick={() => setState('none')}>
|
||||
<X size={18} />
|
||||
</ColorButton>
|
||||
)}
|
||||
</ButtonRow>
|
||||
{showLn && showChain && renderButtons('send_ln', 'receive_ln')}
|
||||
{showLn && !showChain && (
|
||||
<ColorButton onClick={() => setState('none')}>Cancel</ColorButton>
|
||||
)}
|
||||
</AdminSwitch>
|
||||
</ResponsiveLine>
|
||||
);
|
||||
|
@ -158,14 +170,10 @@ export const AccountInfo = () => {
|
|||
</Tile>
|
||||
{renderBalances(formatCB, formatPB)}
|
||||
<AdminSwitch>
|
||||
<ButtonRow>
|
||||
{showLn && showChain && renderButtons('send_chain', 'receive_chain')}
|
||||
{!showLn && showChain && (
|
||||
<ColorButton color={sectionColor} onClick={() => setState('none')}>
|
||||
<X size={18} />
|
||||
</ColorButton>
|
||||
)}
|
||||
</ButtonRow>
|
||||
{showLn && showChain && renderButtons('send_chain', 'receive_chain')}
|
||||
{!showLn && showChain && (
|
||||
<ColorButton onClick={() => setState('none')}>Cancel</ColorButton>
|
||||
)}
|
||||
</AdminSwitch>
|
||||
</ResponsiveLine>
|
||||
);
|
||||
|
|
|
@ -5,6 +5,7 @@ import styled from 'styled-components';
|
|||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { useAccountState } from 'src/context/AccountContext';
|
||||
import { useGetCanConnectInfoQuery } from 'src/graphql/queries/__generated__/getNodeInfo.generated';
|
||||
import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
|
||||
import { getErrorContent } from '../../../utils/error';
|
||||
import { LoadingCard } from '../../../components/loading/LoadingCard';
|
||||
import {
|
||||
|
@ -14,7 +15,6 @@ import {
|
|||
Card,
|
||||
SingleLine,
|
||||
DarkSubTitle,
|
||||
ColorButton,
|
||||
} from '../../../components/generic/Styled';
|
||||
import { mediaWidths } from '../../../styles/Themes';
|
||||
|
||||
|
@ -52,6 +52,14 @@ const TextPadding = styled.span`
|
|||
margin-left: 5px;
|
||||
`;
|
||||
|
||||
const ButtonRow = styled.div`
|
||||
display: flex;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const sectionColor = '#fa541c';
|
||||
|
||||
export const ConnectCard = () => {
|
||||
|
@ -84,13 +92,13 @@ export const ConnectCard = () => {
|
|||
<DarkSubTitle>Public Key</DarkSubTitle>
|
||||
<Key>{public_key}</Key>
|
||||
</Tile>
|
||||
<SingleLine>
|
||||
<ButtonRow>
|
||||
{onionAddress ? (
|
||||
<CopyToClipboard
|
||||
text={onionAddress}
|
||||
onCopy={() => toast.success('Onion Address Copied')}
|
||||
>
|
||||
<ColorButton color={sectionColor}>
|
||||
<ColorButton fullWidth={true} withMargin={'0 4px 0 0'}>
|
||||
<Copy size={18} />
|
||||
<TextPadding>Onion</TextPadding>
|
||||
</ColorButton>
|
||||
|
@ -101,12 +109,12 @@ export const ConnectCard = () => {
|
|||
text={normalAddress}
|
||||
onCopy={() => toast.success('Public Address Copied')}
|
||||
>
|
||||
<ColorButton color={sectionColor}>
|
||||
<ColorButton fullWidth={true} withMargin={'0 0 0 4px'}>
|
||||
<Copy size={18} />
|
||||
</ColorButton>
|
||||
</CopyToClipboard>
|
||||
) : null}
|
||||
</SingleLine>
|
||||
</ButtonRow>
|
||||
</Responsive>
|
||||
</Card>
|
||||
</CardWithTitle>
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
SubTitle,
|
||||
Card,
|
||||
CardTitle,
|
||||
ColorButton,
|
||||
SmallButton,
|
||||
} from '../../../components/generic/Styled';
|
||||
import { unSelectedNavButton } from '../../../styles/Themes';
|
||||
import { AdminSwitch } from '../../../components/adminSwitch/AdminSwitch';
|
||||
|
@ -87,9 +87,9 @@ export const QuickActions = () => {
|
|||
<CardTitle>
|
||||
<SubTitle>{getTitle()}</SubTitle>
|
||||
{openCard !== 'none' && (
|
||||
<ColorButton onClick={() => setOpenCard('none')} color={sectionColor}>
|
||||
<SmallButton onClick={() => setOpenCard('none')}>
|
||||
<X size={18} />
|
||||
</ColorButton>
|
||||
</SmallButton>
|
||||
)}
|
||||
</CardTitle>
|
||||
{renderContent()}
|
||||
|
|
|
@ -1,46 +1,28 @@
|
|||
import React from 'react';
|
||||
import numeral from 'numeral';
|
||||
import {
|
||||
VictoryBar,
|
||||
VictoryChart,
|
||||
VictoryAxis,
|
||||
VictoryVoronoiContainer,
|
||||
VictoryGroup,
|
||||
} from 'victory';
|
||||
import { VictoryBar, VictoryChart, VictoryAxis, VictoryGroup } from 'victory';
|
||||
import { useConfigState } from '../../../../context/ConfigContext';
|
||||
import {
|
||||
chartAxisColor,
|
||||
chartGridColor,
|
||||
// chartColors,
|
||||
flowBarColor,
|
||||
flowBarColor2,
|
||||
} from '../../../../styles/Themes';
|
||||
import { getPrice } from '../../../../components/price/Price';
|
||||
import { usePriceState } from '../../../../context/PriceContext';
|
||||
// import { WaterfallProps } from '.';
|
||||
|
||||
// const beforeMap = {
|
||||
// amount: 'amountBefore',
|
||||
// tokens: 'tokensBefore',
|
||||
// };
|
||||
|
||||
interface Props {
|
||||
isTime: string;
|
||||
isType: string;
|
||||
// isGraph: string;
|
||||
parsedData: {}[];
|
||||
parsedData2: {}[];
|
||||
// waterfall: WaterfallProps[];
|
||||
}
|
||||
|
||||
export const FlowReport = ({
|
||||
isTime,
|
||||
isType,
|
||||
// isGraph,
|
||||
parsedData,
|
||||
parsedData2,
|
||||
}: // waterfall,
|
||||
Props) => {
|
||||
}: Props) => {
|
||||
const { theme, currency, displayValues } = useConfigState();
|
||||
const priceContext = usePriceState();
|
||||
const format = getPrice(currency, displayValues, priceContext);
|
||||
|
@ -55,13 +37,6 @@ Props) => {
|
|||
barWidth = 3;
|
||||
}
|
||||
|
||||
const getLabelString = (value: number) => {
|
||||
if (isType === 'amount') {
|
||||
return numeral(value).format('0,0');
|
||||
}
|
||||
return format({ amount: value });
|
||||
};
|
||||
|
||||
return (
|
||||
<VictoryChart
|
||||
height={100}
|
||||
|
@ -72,12 +47,6 @@ Props) => {
|
|||
right: 50,
|
||||
bottom: 10,
|
||||
}}
|
||||
containerComponent={
|
||||
<VictoryVoronoiContainer
|
||||
voronoiDimension="x"
|
||||
labels={({ datum }) => `${getLabelString(datum[isType])}`}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<VictoryAxis
|
||||
domain={[0, domain]}
|
||||
|
@ -96,7 +65,9 @@ Props) => {
|
|||
grid: { stroke: chartGridColor[theme] },
|
||||
axis: { stroke: 'transparent' },
|
||||
}}
|
||||
tickFormat={a => (isType === 'tokens' ? format({ amount: a }) : a)}
|
||||
tickFormat={a =>
|
||||
isType === 'tokens' ? format({ amount: a, breakNumber: true }) : a
|
||||
}
|
||||
/>
|
||||
<VictoryGroup offset={barWidth}>
|
||||
<VictoryBar
|
||||
|
@ -127,30 +98,6 @@ Props) => {
|
|||
},
|
||||
}}
|
||||
/>
|
||||
{/* {isGraph === 'graph' && (
|
||||
<VictoryBar
|
||||
data={waterfall}
|
||||
x="period"
|
||||
y={isType}
|
||||
y0={beforeMap[isType]}
|
||||
style={{
|
||||
data: {
|
||||
fill: ({ data, index }: any) => {
|
||||
console.log(data, index);
|
||||
return data[index][isType] -
|
||||
data[index][beforeMap[isType]] >
|
||||
0
|
||||
? chartColors.green
|
||||
: 'red';
|
||||
},
|
||||
width: barWidth,
|
||||
},
|
||||
labels: {
|
||||
fontSize: '12px',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)} */}
|
||||
</VictoryGroup>
|
||||
</VictoryChart>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { CardTitle, ColorButton } from '../../../../components/generic/Styled';
|
||||
import { CardTitle, SmallButton } from '../../../../components/generic/Styled';
|
||||
|
||||
interface ButtonProps {
|
||||
isTime: string;
|
||||
|
@ -44,12 +44,12 @@ ButtonProps) => {
|
|||
index: number
|
||||
) => {
|
||||
return (
|
||||
<ColorButton
|
||||
<SmallButton
|
||||
color={buttonBorder}
|
||||
onClick={() => setFn(toggleButtons(array, index))}
|
||||
>
|
||||
{mapped[index]}
|
||||
</ColorButton>
|
||||
</SmallButton>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React, { useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { GitCommit, ArrowDown, ArrowUp } from 'react-feather';
|
||||
import styled from 'styled-components';
|
||||
import styled, { css } from 'styled-components';
|
||||
import { useAccountState } from 'src/context/AccountContext';
|
||||
import { useGetForwardChannelsReportQuery } from 'src/graphql/queries/__generated__/getForwardChannelsReport.generated';
|
||||
import { getErrorContent } from '../../../../utils/error';
|
||||
import {
|
||||
DarkSubTitle,
|
||||
ColorButton,
|
||||
SmallButton,
|
||||
SingleLine,
|
||||
} from '../../../../components/generic/Styled';
|
||||
import { LoadingCard } from '../../../../components/loading/LoadingCard';
|
||||
|
@ -28,9 +28,19 @@ const ButtonRow = styled.div`
|
|||
margin-bottom: 5px;
|
||||
`;
|
||||
|
||||
const TriButton = styled(ColorButton)`
|
||||
type TriButtonProps = {
|
||||
selected: boolean;
|
||||
};
|
||||
|
||||
const TriButton = styled(SmallButton)<TriButtonProps>`
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
|
||||
${({ selected }) =>
|
||||
selected &&
|
||||
css`
|
||||
color: white;
|
||||
`}
|
||||
`;
|
||||
|
||||
const LeftButton = styled(TriButton)`
|
||||
|
|
|
@ -91,7 +91,7 @@ export const LiquidReport = () => {
|
|||
grid: { stroke: chartGridColor[theme] },
|
||||
axis: { stroke: 'transparent' },
|
||||
}}
|
||||
tickFormat={a => `${format({ amount: a })}`}
|
||||
tickFormat={a => `${format({ amount: a, breakNumber: true })}`}
|
||||
/>
|
||||
<VictoryBar
|
||||
horizontal
|
||||
|
|
|
@ -46,7 +46,7 @@ export const Accounts = () => {
|
|||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!loading && data?.getNodeInfo && newAccount) {
|
||||
if (!loading && data && data.getNodeInfo && newAccount) {
|
||||
dispatch({ type: 'changeAccount', changeId: newAccount });
|
||||
dispatchStatus({ type: 'connected' });
|
||||
push(appendBasePath('/home'));
|
||||
|
|
|
@ -12,10 +12,9 @@ import {
|
|||
CardWithTitle,
|
||||
SubTitle,
|
||||
SingleLine,
|
||||
SimpleButton,
|
||||
Sub4Title,
|
||||
} from '../../components/generic/Styled';
|
||||
import { textColor, fontColors } from '../../styles/Themes';
|
||||
import { fontColors } from '../../styles/Themes';
|
||||
import { ColorButton } from '../../components/buttons/colorButton/ColorButton';
|
||||
import {
|
||||
MultiButton,
|
||||
|
@ -40,14 +39,6 @@ export const SettingsLine = styled(SingleLine)`
|
|||
margin: 10px 0;
|
||||
`;
|
||||
|
||||
export const SettingsButton = styled(SimpleButton)`
|
||||
padding: 10px;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${textColor};
|
||||
}
|
||||
`;
|
||||
|
||||
export const CheckboxText = styled.div`
|
||||
font-size: 13px;
|
||||
color: ${fontColors.grey7};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { SingleLine, SimpleButton } from '../../components/generic/Styled';
|
||||
import { textColor } from '../../styles/Themes';
|
||||
import { SingleLine } from '../../components/generic/Styled';
|
||||
import { InterfaceSettings } from './Interface';
|
||||
import { AccountSettings } from './Account';
|
||||
import { DangerView } from './Danger';
|
||||
|
@ -17,14 +16,6 @@ export const SettingsLine = styled(SingleLine)`
|
|||
margin: 8px 0;
|
||||
`;
|
||||
|
||||
export const SettingsButton = styled(SimpleButton)`
|
||||
padding: 8px;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${textColor};
|
||||
}
|
||||
`;
|
||||
|
||||
const SettingsView = () => {
|
||||
return (
|
||||
<>
|
||||
|
|
Loading…
Add table
Reference in a new issue