diff --git a/pages/_app.tsx b/pages/_app.tsx
index fd9643dd..b7e5a39a 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -9,47 +9,30 @@ import { Header } from '../src/layouts/header/Header';
import { Footer } from '../src/layouts/footer/Footer';
import { ApolloProvider } from '@apollo/react-hooks';
import withApollo from '../config/apolloClient';
-import { useAccount } from '../src/context/AccountContext';
import { BitcoinFees } from '../src/components/bitcoinInfo/BitcoinFees';
import { BitcoinPrice } from '../src/components/bitcoinInfo/BitcoinPrice';
import { GridWrapper } from '../src/components/gridWrapper/GridWrapper';
import { useRouter } from 'next/router';
-import {
- useConnectionState,
- useConnectionDispatch,
-} from '../src/context/ConnectionContext';
-import {
- LoadingView,
- ErrorView,
-} from '../src/components/stateViews/StateCards';
import { toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import Head from 'next/head';
import { PageWrapper, HeaderBodyWrapper } from '../src/layouts/Layout.styled';
+import { useStatusState } from '../src/context/StatusContext';
-toast.configure({ draggable: false });
-
-const withoutGrid = ['/', '/login', '/faq', '/privacy', '/terms'];
+toast.configure({ draggable: false, pauseOnFocusLoss: false });
const Wrapper: React.FC = ({ children }) => {
- const dispatch = useConnectionDispatch();
const { theme } = useSettings();
- const { loggedIn } = useAccount();
const { pathname } = useRouter();
- const { loading, error } = useConnectionState();
+ const { connected } = useStatusState();
- const isInArray = withoutGrid.includes(pathname);
+ const isRoot = pathname === '/';
const renderContent = () => {
- if (error && pathname === '/') {
- dispatch({ type: 'disconnected' });
- }
- if ((loading || error) && pathname !== '/') {
- return (
- {loading ? : }
- );
+ if (isRoot) {
+ return <>{children}>;
}
- return {children} ;
+ return {children} ;
};
const renderGetters = () => (
@@ -60,10 +43,10 @@ const Wrapper: React.FC = ({ children }) => {
);
return (
-
+
- {loggedIn && renderGetters()}
+ {connected && renderGetters()}
diff --git a/pages/faq.tsx b/pages/faq.tsx
deleted file mode 100644
index 41c7eb2a..00000000
--- a/pages/faq.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import React from 'react';
-import { Section } from '../src/components/section/Section';
-import { themeColors } from '../src/styles/Themes';
-import {
- Title,
- Center,
- Subtitle,
- Question,
- Text,
-} from '../src/components/typography/Styled';
-import { ContactSection } from '../src/views/homepage/Sections/ContactSection';
-import styled from 'styled-components';
-
-const FaqTitle = styled(Title)`
- margin-bottom: 0px;
-`;
-
-const FaqView = () => {
- return (
- <>
-
- FAQ: Answers to Common Questions
-
-
- Learn about ThunderHub by reading these frequently asked questions.
-
-
-
-
- What is ThunderHub?
-
- ThunderHub is a LND node manager that you can open in any
- browser and on any device.
-
-
-
- How much does it cost?
-
- No cost , ThunderHub is open-source so no need to spend any
- precious sats here.
-
-
-
- What is the value of ThunderHub?
-
- ThunderHub brings a full lightning node manager
- directly to your device without the need of installing plugins,
- extensions or apps, having specific browsers or operating systems and
- is completely open-source.
-
-
- ThunderHub provides a simple and easy to use manager without
- needing to give us any private information. Everything is stored
- directly in your browser and sensitive information (like your admin
- macaroon) are AES-256 encrypted with a password only you know.
-
-
- The code is public and available for anyone to audit.
-
-
-
- Is ThunderHub safe to use?
-
- ThunderHub is open-source and available for anyone to audit.
-
- This still doesn't mean it's completely bullet proof against
- attackers.
-
-
-
- If you connect using your admin macaroon, it is
- AES-256 encrypted, password protected and
- stored only in your browser.
- The password is only known by you and you need to unlock your account
- everytime you want to perform an admin only change such as managing
- channels or sending and receiving bitcoin or lightning payments.
-
-
- The ThunderHub server uses your credentials to connect to your node
- but they are never stored outside of your browser. Still, this
- involves a certain degree of trust you must be aware of.
-
-
- If you want a more secure alternative, you can connect using a
- view-only macaroon and use ThunderHub only for monitoring your node.
-
-
-
- What happens if I forget my password?
-
- The password is only known by you and is used to unlock an encrypted
- macaroon stored only on your browser making it impossible for us to
- help you with this situation.
-
-
- The fix is simple. Delete that account on ThunderHub
- (Don't worry, this doesn't delete anything or affect in any way your
- node) and connect again with your desired macaroons.
-
-
-
- Am I being tracked in anyway?
-
- We do not track anything from our users and
- store no information on our servers.
- Should it be needed in the future, we will notify users and ask for
- explicit consent before hand.
-
-
-
-
- Can I use ThunderHub without having my own Lightning Node?
-
-
- ThunderHub provides full lightning node management which is only
- possible when you are the owner of the lightning node to which it is
- connecting. So in short,
- no you cannot use ThunderHub without having your own node.
-
-
- Nowadays with the posibility of using pruned bitcoin nodes (Bitcoin
- nodes which only have a section of the Bitcoin blockchain), you can
- get a lightning node up and running in the cloud{' '}
- for under €15/month.
-
-
-
- >
- );
-};
-
-export default FaqView;
diff --git a/pages/index.tsx b/pages/index.tsx
index d84ba660..da3451fb 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,23 +1,90 @@
-import React from 'react';
+import React, { useEffect } from 'react';
import { useAccount } from '../src/context/AccountContext';
import { SessionLogin } from '../src/views/login/SessionLogin';
import { useRouter } from 'next/router';
-import { HomePageView } from '../src/views/homepage/HomePage';
import { appendBasePath } from '../src/utils/basePath';
-import { LoadingView } from '../src/components/loading/LoadingView';
+import { TopSection } from '../src/views/homepage/Top';
+import { LoginBox } from '../src/views/homepage/LoginBox';
+import { Accounts } from '../src/views/homepage/Accounts';
+import {
+ useStatusState,
+ useStatusDispatch,
+} from '../src/context/StatusContext';
+import { useGetCanConnectLazyQuery } from '../src/generated/graphql';
+import { LoadingCard } from '../src/components/loading/LoadingCard';
+import { Section } from '../src/components/section/Section';
+import { toast } from 'react-toastify';
-const ContextApp: React.FC = () => {
+const ContextApp = () => {
const { push } = useRouter();
- const { loggedIn, admin, viewOnly, sessionAdmin } = useAccount();
+ const {
+ name,
+ host,
+ cert,
+ admin,
+ viewOnly,
+ sessionAdmin,
+ accounts,
+ } = useAccount();
+ const { loading: statusLoading } = useStatusState();
+ const dispatch = useStatusDispatch();
- if (loggedIn) {
- if (admin === '' || viewOnly !== '' || sessionAdmin !== '') {
+ const change = accounts.length <= 1 && admin === '';
+ const isSession = admin !== '' && viewOnly === '';
+
+ const [getCanConnect, { data, loading, error }] = useGetCanConnectLazyQuery({
+ fetchPolicy: 'network-only',
+ onError: () => {
+ toast.error(`Unable to connect to ${name}`);
+ dispatch({ type: 'disconnected' });
+ },
+ });
+
+ useEffect(() => {
+ if (loading && !error) {
+ dispatch({ type: 'loading' });
+ }
+ if (!loading && data?.getNodeInfo && !error) {
+ dispatch({ type: 'connected' });
push(appendBasePath('/home'));
- return ;
}
- }
+ }, [loading, data, error]);
+
+ useEffect(() => {
+ if (viewOnly !== '' || sessionAdmin !== '') {
+ getCanConnect({
+ variables: {
+ auth: {
+ host,
+ macaroon: viewOnly !== '' ? viewOnly : sessionAdmin,
+ cert,
+ },
+ },
+ });
+ }
+ }, [viewOnly, sessionAdmin]);
- return !loggedIn && admin === '' ? : ;
+ return (
+ <>
+
+ {statusLoading && (
+
+ )}
+ {!statusLoading && (
+ <>
+ {isSession && }
+
+
+ >
+ )}
+ >
+ );
};
export default ContextApp;
diff --git a/pages/privacy.tsx b/pages/privacy.tsx
deleted file mode 100644
index d4c86332..00000000
--- a/pages/privacy.tsx
+++ /dev/null
@@ -1,171 +0,0 @@
-import React from 'react';
-import { Section } from '../src/components/section/Section';
-import { themeColors, fontColors } from '../src/styles/Themes';
-import {
- Title,
- Question,
- Text,
- BulletPoint,
-} from '../src/components/typography/Styled';
-import { ContactSection } from '../src/views/homepage/Sections/ContactSection';
-
-import { Link } from '../src/components/link/Link';
-
-const PrivacyView = () => {
- const props = { color: fontColors.blue2, underline: fontColors.blue2 };
-
- const renderLinks = (terms: string, privacy: string) => (
- <>
-
- Privacy Policy
- {' '}
- and{' '}
-
- Terms of Service
-
- >
- );
-
- return (
- <>
-
-
- Last Updated: February 12, 2020
-
-
-
- ThunderHub takes your privacy very seriously, and as a general rule,
- will never collect unnecessary data from you without your explicit
- consent. However, through using it, you will end up providing us with
- some sensitive information, so we want to be explicit about that.
-
-
- This Privacy Policy describes our policies and procedures regarding
- our collection and use of your information in connection with your
- access and use of{' '}
-
- https://thunderhub.io
- {' '}
- (the "Site"). By using this service, you acknowledge and agree to this
- Privacy Policy.
-
-
- The terms "us," "we," or "our" refer to ThunderHub. The terms "you",
- "your", or "user" refer to those accessing our site.
-
-
-
- Collection, Storage, and Use of Information
-
- ThunderHub's site is designed to collect as little information as
- possible. The following outlines what is (and is not) collected, and
- how it's handled. What we do collect from users is stored either
- locally on the user's device, or using browser storage APIs that keep
- inaccessible to us without user action. Sensitive information such as
- authentication credentials are AES-256 encrypted and stored using a
- password known only to the user.
-
-
- Node Credentials - In order to communicate with your Lightning
- node, we ask for sensitive information to do so. This information is
- stored using your browser's own storage APIs, and is encrypted using a
- password only known to the user. This information is used by the
- server to connect to your node but is never recorded outside of the
- user's browser storage.
-
-
- Error Reporting / Usage Statistics - No information is
- recorded. If information must be recorded further on, it will be with
- explicit user consent from the user and efforts will be taken to keep
- the information anonymous and private.
-
-
- Personal information - Information such as your name, IP
- address, email address, or browsing activity are never collected
- without explicit consent. While there is no plan to ever ask for
- permission to passively collect it, some interactions such as support
- requests or bug reports may optionally ask for it.
-
-
-
- Third Parties
-
- The following is a list of third parties who may obtain user
- information through use of the Site and App, as well as links to their
- respective privacy policies. While we aim to only leverage third
- parties that we find to be privacy-friendly, and try to keep them as
- opt-in as possible, we are not liable for any privacy violations as a
- result of the user's interaction with third party services. Any
- services found to be exploiting our user's information will be removed
- as quickly as possible.
-
-
- Hosting - The following services are used for the hosting and
- distrubtion of our site and application. Your information is subject
- to their policies when interacting with them.
-
-
- Github - Github's{' '}
- {renderLinks(
- 'https://help.github.com/en/articles/github-privacy-statement',
- 'https://help.github.com/en/articles/github-terms-of-service'
- )}
-
-
- AWS - AWS's{' '}
- {renderLinks(
- 'https://aws.amazon.com/privacy/',
- 'https://aws.amazon.com/service-terms/'
- )}
-
-
- APIs - For information that your node can't get alone, we link
- to or use APIs in our application that leverage the following
- services. Your information is subject to their policies when
- interacting with them.
-
-
- Earn.com's Bitcoin Fee API - Earn.com's{' '}
- {renderLinks(
- 'https://earn.com/privacy/',
- 'https://earn.com/terms-of-use/'
- )}
-
-
- Blockchain Explorer and Price API - Blockchain's{' '}
- {renderLinks(
- 'https://www.blockchain.com/legal/privacy',
- 'https://www.blockchain.com/legal/terms'
- )}
-
-
-
- Law Enforcement Purposes
-
- If required by a subpoena or court order, we will share information to
- law enforcement agencies in order to comply with legal requirements.
- We will make reasonable efforts to notify any subjects of such
- informational disclosure as is permitted by law.
-
-
-
- Amendments
-
- We may alter this Privacy Policy at its discretion at any time for any
- or no reason. Any changes will include a corresponding “Last updated”
- date shown at the top of this page and such changes will go in effect
- immediately. Prominent notice of any changes may be posted on our
- site, in our application, or on social media. Such notice is not
- guaranteed and you should check for updates regularly. The latest
- version of the Privacy Policy will be considered as superseding any
- previous version unless otherwise noted.
-
-
-
- >
- );
-};
-
-export default PrivacyView;
diff --git a/pages/terms.tsx b/pages/terms.tsx
deleted file mode 100644
index 9c916108..00000000
--- a/pages/terms.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import React from 'react';
-import { Section } from '../src/components/section/Section';
-import { themeColors, fontColors } from '../src/styles/Themes';
-import { Title, Question, Text } from '../src/components/typography/Styled';
-import { ContactSection } from '../src/views/homepage/Sections/ContactSection';
-import { Link } from '../src/components/link/Link';
-
-const TermsView = () => {
- const props = { color: fontColors.blue2, underline: fontColors.blue2 };
-
- return (
- <>
-
-
- Last Updated: January 28, 2020
-
-
- 1. Terms
-
- ThunderHub ("us", "we", or "our") provides the website{' '}
-
- https://thunderhub.io
- {' '}
- (the "Site"). Your use of or access to the site is subject to the
- following Terms of Service (the "Agreement").
-
-
-
- 2. Disclaimer
-
- We are not responsible for any loss. LND, the ThunderHub website, and
- some of the underlying Javascript libraries we use are under active
- development. While every release is tested, there is always the
- possibility something unexpected happens that causes your funds to be
- lost. Please do not invest more than you are willing to lose. Please
- be careful.
-
-
-
- 3. Limitations
-
- In no event shall ThunderHub be liable for any damages (including,
- without limitation, damages for loss of data or profit, or due to
- business interruption) arising out of the use or inability to use the
- materials on our website, even if we or an authorized representative
- of ours has been notified orally or in writing of the possibility of
- such damage. Because some jurisdictions do not allow limitations on
- implied warranties, or limitations of liability for consequential or
- incidental damages, these limitations may not apply to you.
-
-
-
- 4. Accuracy of Materials
-
- The materials appearing on our website could include technical,
- typographical, or photographic errors. We do not warrant that any of
- the material on the website is accurate, complete or current. We may
- make changes to the material contained on the website at any time
- without notice. However we do not make any commitment to update the
- material.
-
-
-
- 5. Modifications
-
- We may revise these terms of service for the website at any time
- without notice. By using this website you are agreeing to be bound by
- the then current version of these terms of service.
-
-
-
- 6. Privacy Policy
-
- Our Privacy Policy describes the way we do and do not collect, use,
- store, and disclose your personal information, and is hereby
- incorporated by this reference into these Terms. You agree to the
- collection, use, storage, and disclosure of your data in accordance
- with our{' '}
-
- Privacy Policy
-
- .
-
-
-
- >
- );
-};
-
-export default TermsView;
diff --git a/src/components/animated/AnimatedNumber.tsx b/src/components/animated/AnimatedNumber.tsx
index 2b2e6e7b..a9636bcf 100644
--- a/src/components/animated/AnimatedNumber.tsx
+++ b/src/components/animated/AnimatedNumber.tsx
@@ -14,7 +14,7 @@ type AnimatedProps = {
amount: number;
};
-export const AnimatedNumber = ({ amount }: AnimatedProps) => {
+export const AnimatedNumber = ({ amount = 0 }: AnimatedProps) => {
const { value } = useSpring({
from: { value: 0 },
value: amount,
diff --git a/src/components/auth/checks/AdminCheck.tsx b/src/components/auth/checks/AdminCheck.tsx
index 2210720c..47d6c498 100644
--- a/src/components/auth/checks/AdminCheck.tsx
+++ b/src/components/auth/checks/AdminCheck.tsx
@@ -14,6 +14,7 @@ type AdminProps = {
export const AdminCheck = ({ host, admin, cert, setChecked }: AdminProps) => {
const { data, loading } = useGetCanAdminQuery({
+ fetchPolicy: 'network-only',
skip: !admin,
variables: { auth: { host, macaroon: admin, cert } },
onError: () => {
diff --git a/src/components/auth/index.tsx b/src/components/auth/index.tsx
index bdea48e9..95663b78 100644
--- a/src/components/auth/index.tsx
+++ b/src/components/auth/index.tsx
@@ -7,7 +7,6 @@ import { ViewCheck } from './checks/ViewCheck';
import CryptoJS from 'crypto-js';
import { useAccount } from '../../context/AccountContext';
import { saveUserAuth, getAccountId } from '../../utils/auth';
-import { useConnectionDispatch } from '../../context/ConnectionContext';
import { useStatusDispatch } from '../../context/StatusContext';
import { useRouter } from 'next/router';
import { toast } from 'react-toastify';
@@ -35,8 +34,7 @@ export const Auth = ({ type, status, callback, setStatus }: AuthProps) => {
const { changeAccount, accounts } = useAccount();
const { push } = useRouter();
- const dispatch = useConnectionDispatch();
- const dispatchState = useStatusDispatch();
+ const dispatch = useStatusDispatch();
const [name, setName] = useState();
const [host, setHost] = useState();
@@ -112,7 +110,6 @@ export const Auth = ({ type, status, callback, setStatus }: AuthProps) => {
const id = getAccountId(host, viewOnly, admin, cert);
dispatch({ type: 'disconnected' });
- dispatchState({ type: 'disconnected' });
changeAccount(id);
push(appendBasePath('/'));
@@ -141,7 +138,6 @@ export const Auth = ({ type, status, callback, setStatus }: AuthProps) => {
const id = getAccountId(host, viewOnly, admin, cert);
dispatch({ type: 'disconnected' });
- dispatchState({ type: 'disconnected' });
changeAccount(id);
push(appendBasePath('/'));
diff --git a/src/components/connectionCheck/ConnectionCheck.tsx b/src/components/connectionCheck/ConnectionCheck.tsx
deleted file mode 100644
index 15105c20..00000000
--- a/src/components/connectionCheck/ConnectionCheck.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { useEffect } from 'react';
-import {
- useConnectionState,
- useConnectionDispatch,
-} from '../../context/ConnectionContext';
-import { useAccount } from '../../context/AccountContext';
-import { useGetCanConnectQuery } from '../../generated/graphql';
-
-export const ConnectionCheck = () => {
- const { connected } = useConnectionState();
- const dispatch = useConnectionDispatch();
-
- const { auth } = useAccount();
-
- const { data, loading } = useGetCanConnectQuery({
- variables: { auth },
- skip: connected,
- onError: () => {
- dispatch({ type: 'error' });
- },
- });
-
- useEffect(() => {
- if (!loading && data && data.getNodeInfo) {
- dispatch({ type: 'connected' });
- }
- }, [data, loading, dispatch]);
-
- return null;
-};
diff --git a/src/components/generic/Styled.tsx b/src/components/generic/Styled.tsx
index 3f269f43..25ad491a 100644
--- a/src/components/generic/Styled.tsx
+++ b/src/components/generic/Styled.tsx
@@ -98,17 +98,19 @@ export const SmallLink = styled.a`
type SubTitleProps = {
subtitleColor?: string | ThemeSet;
fontWeight?: string;
+ inverseColor?: boolean;
};
-export const SubTitle = styled.h4`
+export const SubTitle = styled.h4`
+ color: ${({ inverseColor }) =>
+ inverseColor ? inverseTextColor : textColor};
margin: 5px 0;
- ${({ subtitleColor }: SubTitleProps) =>
+ ${({ subtitleColor }) =>
subtitleColor &&
css`
color: ${subtitleColor};
`}
- font-weight: ${({ fontWeight }: SubTitleProps) =>
- fontWeight ? fontWeight : '500'};
+ font-weight: ${({ fontWeight }) => (fontWeight ? fontWeight : '500')};
`;
export const InverseSubtitle = styled(SubTitle)`
diff --git a/src/components/gridWrapper/GridWrapper.tsx b/src/components/gridWrapper/GridWrapper.tsx
index 262e4b96..91105320 100644
--- a/src/components/gridWrapper/GridWrapper.tsx
+++ b/src/components/gridWrapper/GridWrapper.tsx
@@ -4,7 +4,6 @@ import { mediaWidths } from '../../styles/Themes';
import { Section } from '../section/Section';
import { Navigation } from '../../layouts/navigation/Navigation';
-import { ConnectionCheck } from '../connectionCheck/ConnectionCheck';
import { StatusCheck } from '../statusCheck/StatusCheck';
const Container = styled.div`
@@ -23,22 +22,10 @@ const ContentStyle = styled.div`
grid-area: content;
`;
-interface GridWrapperProps {
- without?: boolean;
-}
-
-export const GridWrapper: React.FC = ({
- children,
- without = false,
-}) => {
- if (without) {
- return <>{children}>;
- }
-
+export const GridWrapper: React.FC = ({ children }) => {
return (
-
{children}
diff --git a/src/components/loading/LoadingCard.tsx b/src/components/loading/LoadingCard.tsx
index b7d910a0..9ea97402 100644
--- a/src/components/loading/LoadingCard.tsx
+++ b/src/components/loading/LoadingCard.tsx
@@ -19,6 +19,7 @@ interface LoadingCardProps {
color?: string;
noTitle?: boolean;
loadingHeight?: string;
+ inverseColor?: boolean;
}
export const LoadingCard = ({
@@ -27,6 +28,7 @@ export const LoadingCard = ({
noCard = false,
noTitle = false,
loadingHeight,
+ inverseColor,
}: LoadingCardProps) => {
const loadingColor = color ? color : themeColors.blue3;
@@ -51,7 +53,7 @@ export const LoadingCard = ({
return (
- {title}
+ {title}
diff --git a/src/components/nodeInfo/NodeInfoModal.tsx b/src/components/nodeInfo/NodeInfoModal.tsx
index dd1c3c9e..335ab5d2 100644
--- a/src/components/nodeInfo/NodeInfoModal.tsx
+++ b/src/components/nodeInfo/NodeInfoModal.tsx
@@ -8,7 +8,6 @@ import {
} from '../generic/Styled';
import { Price } from '../price/Price';
import { ColorButton } from '../buttons/colorButton/ColorButton';
-import { useConnectionDispatch } from '../../context/ConnectionContext';
import { useStatusDispatch } from '../../context/StatusContext';
import { useAccount } from '../../context/AccountContext';
@@ -18,8 +17,7 @@ interface NodeInfoModalProps {
}
export const NodeInfoModal = ({ account, accountId }: NodeInfoModalProps) => {
- const dispatch = useConnectionDispatch();
- const dispatchState = useStatusDispatch();
+ const dispatch = useStatusDispatch();
const { changeAccount } = useAccount();
@@ -88,8 +86,7 @@ export const NodeInfoModal = ({ account, accountId }: NodeInfoModalProps) => {
withMargin={'16px 0 0'}
fullWidth={true}
onClick={() => {
- dispatch({ type: 'disconnected' });
- dispatchState({
+ dispatch({
type: 'disconnected',
});
changeAccount(accountId);
diff --git a/src/components/statusCheck/StatusCheck.tsx b/src/components/statusCheck/StatusCheck.tsx
index 11dbe3be..e9235417 100644
--- a/src/components/statusCheck/StatusCheck.tsx
+++ b/src/components/statusCheck/StatusCheck.tsx
@@ -1,31 +1,29 @@
-import { useConnectionState } from '../../context/ConnectionContext';
import { useAccount } from '../../context/AccountContext';
import { useStatusDispatch } from '../../context/StatusContext';
import { useEffect } from 'react';
-import { toast } from 'react-toastify';
-import { getErrorContent } from '../../utils/error';
import { useGetNodeInfoQuery } from '../../generated/graphql';
+import { useRouter } from 'next/router';
+import { appendBasePath } from '../../utils/basePath';
+import { toast } from 'react-toastify';
export const StatusCheck = () => {
- const { connected } = useConnectionState();
const dispatch = useStatusDispatch();
+ const { push } = useRouter();
- const { loggedIn, auth } = useAccount();
+ const { name, auth } = useAccount();
- const { data, loading, error, stopPolling } = useGetNodeInfoQuery({
+ const { data, loading, error } = useGetNodeInfoQuery({
+ fetchPolicy: 'network-only',
variables: { auth },
- skip: !connected || !loggedIn || !auth,
pollInterval: 10000,
- onError: error => toast.error(getErrorContent(error)),
});
useEffect(() => {
- if (!connected || !loggedIn) {
- stopPolling();
+ if (error) {
+ toast.error(`Unable to connect to ${name}`);
+ dispatch({ type: 'disconnected' });
+ push(appendBasePath('/'));
}
- }, [connected, loggedIn, stopPolling]);
-
- useEffect(() => {
if (data && !loading && !error) {
const {
getChainBalance,
@@ -41,7 +39,6 @@ export const StatusCheck = () => {
const numbers = onlyVersion[0].split('.');
const state = {
- loading: false,
alias,
syncedToChain: is_synced_to_chain,
version: versionNumber[0],
diff --git a/src/context/AccountContext.tsx b/src/context/AccountContext.tsx
index d6be91b0..87e1b8b5 100644
--- a/src/context/AccountContext.tsx
+++ b/src/context/AccountContext.tsx
@@ -20,7 +20,6 @@ interface AuthProps {
}
interface ChangeProps {
- loggedIn?: boolean;
name?: string;
host?: string;
admin?: string;
@@ -31,7 +30,6 @@ interface ChangeProps {
}
interface AccountProps {
- loggedIn: boolean;
name: string;
host: string;
admin: string;
@@ -41,14 +39,12 @@ interface AccountProps {
id: string;
auth: AuthProps | undefined;
accounts: SingleAccountProps[];
- setAccount: (newProps: ChangeProps) => void;
changeAccount: (account: string) => void;
deleteAccount: (account: string) => void;
refreshAccount: () => void;
}
export const AccountContext = createContext({
- loggedIn: false,
name: '',
host: '',
admin: '',
@@ -58,7 +54,6 @@ export const AccountContext = createContext({
id: '',
auth: undefined,
accounts: [],
- setAccount: () => {},
changeAccount: () => {},
deleteAccount: () => {},
refreshAccount: () => {},
@@ -69,32 +64,6 @@ const AccountProvider = ({ children }: any) => {
refreshAccount();
}, []);
- const setAccount = ({
- loggedIn,
- name,
- host,
- admin,
- sessionAdmin,
- viewOnly,
- cert,
- id,
- }: ChangeProps) => {
- updateAccount((prevState: any) => {
- const newState = { ...prevState };
- return merge(newState, {
- loggedIn,
- name,
- host,
- admin,
- sessionAdmin,
- viewOnly,
- cert,
- id,
- auth: getAuthObj(host, viewOnly, sessionAdmin, cert),
- });
- });
- };
-
const changeAccount = (changeToId: string) => {
const currentAccounts = JSON.parse(
localStorage.getItem('accounts') || '[]'
@@ -145,22 +114,14 @@ const AccountProvider = ({ children }: any) => {
const refreshAccount = (account?: string) => {
const sessionAdmin = sessionStorage.getItem('session') || '';
- const {
- name,
- host,
- admin,
- viewOnly,
- cert,
- id,
- accounts,
- loggedIn,
- } = getAuth(account);
+ const { name, host, admin, viewOnly, cert, id, accounts } = getAuth(
+ account
+ );
updateAccount((prevState: any) => {
const newState = { ...prevState };
const merged = merge(newState, {
- loggedIn,
name,
host,
admin,
@@ -176,7 +137,6 @@ const AccountProvider = ({ children }: any) => {
};
const accountState = {
- loggedIn: false,
name: '',
host: '',
admin: '',
@@ -186,7 +146,6 @@ const AccountProvider = ({ children }: any) => {
id: '',
auth: undefined,
accounts: [],
- setAccount,
changeAccount,
deleteAccount,
refreshAccount,
diff --git a/src/context/ConnectionContext.tsx b/src/context/ConnectionContext.tsx
deleted file mode 100644
index e97d5162..00000000
--- a/src/context/ConnectionContext.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import React, { createContext, useContext, useReducer } from 'react';
-
-type State = {
- connected: boolean;
- loading: boolean;
- error: boolean;
-};
-
-type ActionType = {
- type: 'connected' | 'loading' | 'error' | 'disconnected';
-};
-
-type Dispatch = (action: ActionType) => void;
-
-const StateContext = createContext(undefined);
-const DispatchContext = createContext(undefined);
-
-const stateReducer = (state: State, action: ActionType) => {
- switch (action.type) {
- case 'connected':
- return { connected: true, loading: false, error: false };
- case 'loading':
- return { connected: false, loading: true, error: false };
- case 'disconnected':
- return { connected: false, loading: false, error: false };
- case 'error':
- return { connected: false, loading: false, error: true };
- default:
- return { connected: false, loading: false, error: false };
- }
-};
-
-const initialState = {
- connected: false,
- loading: false,
- error: false,
-};
-
-const ConnectionProvider = ({ children }: any) => {
- const [state, dispatch] = useReducer(stateReducer, initialState);
-
- return (
-
-
- {children}
-
-
- );
-};
-
-const useConnectionState = () => {
- const context = useContext(StateContext);
- if (context === undefined) {
- throw new Error(
- 'useConnectionState must be used within a ConnectionProvider'
- );
- }
- return context;
-};
-
-const useConnectionDispatch = () => {
- const context = useContext(DispatchContext);
- if (context === undefined) {
- throw new Error(
- 'useConnectionDispatch must be used within a ConnectionProvider'
- );
- }
- return context;
-};
-
-export { ConnectionProvider, useConnectionState, useConnectionDispatch };
diff --git a/src/context/ContextProvider.tsx b/src/context/ContextProvider.tsx
index 08089cab..7f192948 100644
--- a/src/context/ContextProvider.tsx
+++ b/src/context/ContextProvider.tsx
@@ -2,7 +2,6 @@ import React from 'react';
import { AccountProvider } from './AccountContext';
import { SettingsProvider } from './SettingsContext';
import { BitcoinInfoProvider } from './BitcoinContext';
-import { ConnectionProvider } from './ConnectionContext';
import { StatusProvider } from './StatusContext';
import { PriceProvider } from './PriceContext';
@@ -11,9 +10,7 @@ export const ContextProvider: React.FC = ({ children }) => (
-
- {children}
-
+ {children}
diff --git a/src/context/StatusContext.tsx b/src/context/StatusContext.tsx
index 23e296d2..7e793137 100644
--- a/src/context/StatusContext.tsx
+++ b/src/context/StatusContext.tsx
@@ -1,7 +1,11 @@
import React, { createContext, useContext, useReducer } from 'react';
-type State = {
+type StateStatus = {
loading: boolean;
+ connected: boolean;
+};
+
+type State = {
alias: string;
syncedToChain: boolean;
version: string;
@@ -14,17 +18,20 @@ type State = {
channelPending: number;
};
+type CompleteState = State & StateStatus;
+
type ActionType = {
- type: 'connected' | 'disconnected';
+ type: 'connected' | 'disconnected' | 'loading';
state?: State;
};
type Dispatch = (action: ActionType) => void;
-const StateContext = createContext(undefined);
+const StateContext = createContext(undefined);
const DispatchContext = createContext(undefined);
const initialState = {
+ connected: false,
loading: false,
alias: '',
syncedToChain: false,
@@ -38,12 +45,16 @@ const initialState = {
channelPending: 0,
};
-const stateReducer = (state: State, action: ActionType): State => {
+const stateReducer = (state: State, action: ActionType): CompleteState => {
switch (action.type) {
case 'connected':
- return action.state || initialState;
+ return (
+ { ...action.state, loading: false, connected: true } || initialState
+ );
case 'disconnected':
return initialState;
+ case 'loading':
+ return { ...initialState, loading: true };
default:
return initialState;
}
diff --git a/src/layouts/footer/Footer.styled.tsx b/src/layouts/footer/Footer.styled.tsx
index e0a5d9ec..9ffa0556 100644
--- a/src/layouts/footer/Footer.styled.tsx
+++ b/src/layouts/footer/Footer.styled.tsx
@@ -1,6 +1,5 @@
import styled from 'styled-components';
import { headerTextColor, fontColors, mediaWidths } from '../../styles/Themes';
-import { HomeButton } from '../../views/homepage/HomePage.styled';
export const FooterWrapper = styled.div`
position: absolute;
@@ -67,14 +66,6 @@ export const CopyrightText = styled(SideText)`
color: ${fontColors.blue};
`;
-export const StyledRouter = styled.div`
- margin-top: 16px;
-
- ${HomeButton} {
- font-size: 14px;
- }
-`;
-
export const Line = styled.div`
display: flex;
justify-content: center;
diff --git a/src/layouts/footer/Footer.tsx b/src/layouts/footer/Footer.tsx
index 432bc667..c51bcbfa 100644
--- a/src/layouts/footer/Footer.tsx
+++ b/src/layouts/footer/Footer.tsx
@@ -2,9 +2,6 @@ import React from 'react';
import { Section } from '../../components/section/Section';
import { Link } from '../../components/link/Link';
import { Emoji } from '../../components/emoji/Emoji';
-import { useAccount } from '../../context/AccountContext';
-import RouterLink from 'next/link';
-import { Zap } from '../../components/generic/Icons';
import getConfig from 'next/config';
import { headerColor, fontColors } from '../../styles/Themes';
import {
@@ -17,15 +14,12 @@ import {
SideText,
CopyrightText,
RightFooter,
- StyledRouter,
} from './Footer.styled';
-import { HomeButton } from '../../views/homepage/HomePage.styled';
const { publicRuntimeConfig } = getConfig();
const { npmVersion } = publicRuntimeConfig;
export const Footer = () => {
- const { loggedIn } = useAccount();
return (
@@ -50,9 +44,6 @@ export const Footer = () => {
-
- FAQ
-
{
>
Twitter
-
- Terms of Use
-
-
- Privacy Policy
-
- {!loggedIn && (
-
-
-
-
- LOGIN
-
-
-
- )}
diff --git a/src/layouts/header/Header.tsx b/src/layouts/header/Header.tsx
index f9994c3b..abf430e1 100644
--- a/src/layouts/header/Header.tsx
+++ b/src/layouts/header/Header.tsx
@@ -1,15 +1,8 @@
import React, { useState } from 'react';
import { headerColor, headerTextColor } from '../../styles/Themes';
-import { HomeButton } from '../../views/homepage/HomePage.styled';
import { useAccount } from '../../context/AccountContext';
import { SingleLine } from '../../components/generic/Styled';
-import {
- Cpu,
- MenuIcon,
- XSvg,
- Zap,
- Circle,
-} from '../../components/generic/Icons';
+import { Cpu, MenuIcon, XSvg, Circle } from '../../components/generic/Icons';
import { BurgerMenu } from '../../components/burgerMenu/BurgerMenu';
import { useTransition, animated } from 'react-spring';
import { Section } from '../../components/section/Section';
@@ -18,7 +11,6 @@ import { Link } from '../../components/link/Link';
import { ViewSwitch } from '../../components/viewSwitch/ViewSwitch';
import {
IconWrapper,
- LinkWrapper,
HeaderStyle,
HeaderLine,
HeaderTitle,
@@ -29,9 +21,8 @@ const AnimatedBurger = animated(MenuIcon);
const AnimatedClose = animated(XSvg);
export const Header = () => {
- const { loggedIn } = useAccount();
const [open, setOpen] = useState(false);
- const { syncedToChain } = useStatusState();
+ const { syncedToChain, connected } = useStatusState();
const transitions = useTransition(open, null, {
from: { position: 'absolute', opacity: 0 },
@@ -62,41 +53,20 @@ export const Header = () => {
>
);
- const renderLoggedOut = () => (
- <>
-
- Faq
-
-
- Terms
-
-
- Privacy
-
-
-
-
-
-
- >
- );
-
return (
<>
-
-
-
+
+
+
ThunderHub
-
- {loggedIn ? renderLoggedIn() : renderLoggedOut()}
-
+ {connected && renderLoggedIn()}
diff --git a/src/layouts/navigation/Navigation.tsx b/src/layouts/navigation/Navigation.tsx
index 80d692d5..8f483bf7 100644
--- a/src/layouts/navigation/Navigation.tsx
+++ b/src/layouts/navigation/Navigation.tsx
@@ -24,9 +24,9 @@ import {
CreditCard,
} from '../../components/generic/Icons';
import { useSettings } from '../../context/SettingsContext';
-import { useConnectionState } from '../../context/ConnectionContext';
import { useRouter } from 'next/router';
import { Link } from '../../components/link/Link';
+import { useStatusState } from '../../context/StatusContext';
const NavigationStyle = styled.div`
grid-area: nav;
@@ -132,7 +132,7 @@ interface NavigationProps {
export const Navigation = ({ isBurger, setOpen }: NavigationProps) => {
const { pathname } = useRouter();
const { sidebar, setSettings } = useSettings();
- const { connected } = useConnectionState();
+ const { connected } = useStatusState();
const renderNavButton = (
title: string,
diff --git a/src/styles/Themes.ts b/src/styles/Themes.ts
index d1d04d93..3b2f4b32 100644
--- a/src/styles/Themes.ts
+++ b/src/styles/Themes.ts
@@ -111,12 +111,17 @@ export const headerTextColor = theme('mode', {
export const homeBackgroundColor = theme('mode', {
light: themeColors.grey,
- dark: themeColors.blue4,
+ dark: themeColors.grey,
});
export const homeBackgroundSecondColor = theme('mode', {
light: themeColors.grey2,
- dark: themeColors.blue6,
+ dark: themeColors.grey2,
+});
+
+export const homeCompatibleColor = theme('mode', {
+ light: themeColors.blue5,
+ dark: themeColors.blue5,
});
// ---------------------------------------
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
index 8bc2226e..3de85c77 100644
--- a/src/utils/auth.ts
+++ b/src/utils/auth.ts
@@ -55,7 +55,6 @@ export const getAuth = (account?: string) => {
Number(account ?? (localStorage.getItem('active') || '0')),
0
);
- const sessionAdmin = sessionStorage.getItem('session') || '';
const accountsLength = accounts.length;
@@ -83,7 +82,6 @@ export const getAuth = (account?: string) => {
`${host}-${viewOnly}-${admin !== '' ? 1 : 0}-${cert}`,
THUNDERHUB_NAMESPACE
);
- const loggedIn = host !== '' && (viewOnly !== '' || sessionAdmin !== '');
return {
name,
@@ -93,7 +91,6 @@ export const getAuth = (account?: string) => {
cert,
id: currentId,
accounts,
- loggedIn,
};
};
diff --git a/src/views/home/account/AccountInfo.tsx b/src/views/home/account/AccountInfo.tsx
index be26ffd0..7350d757 100644
--- a/src/views/home/account/AccountInfo.tsx
+++ b/src/views/home/account/AccountInfo.tsx
@@ -52,14 +52,14 @@ export const AccountInfo = () => {
const [state, setState] = useState('none');
const {
- loading,
+ connected,
chainBalance,
chainPending,
channelBalance,
channelPending,
} = useStatusState();
- if (loading) {
+ if (!connected) {
return (
<>
diff --git a/src/views/homepage/Accounts.tsx b/src/views/homepage/Accounts.tsx
new file mode 100644
index 00000000..460cfade
--- /dev/null
+++ b/src/views/homepage/Accounts.tsx
@@ -0,0 +1,95 @@
+import * as React from 'react';
+import { useAccount } from '../../context/AccountContext';
+import { Section } from '../../components/section/Section';
+import { Card, SingleLine } from '../../components/generic/Styled';
+import styled from 'styled-components';
+import { ColorButton } from '../../components/buttons/colorButton/ColorButton';
+import { useGetCanConnectLazyQuery } from '../../generated/graphql';
+import { toast } from 'react-toastify';
+import { ConnectTitle } from './HomePage.styled';
+
+const AccountLine = styled.div`
+ margin: 8px 0;
+`;
+
+const TypeText = styled.div`
+ font-size: 14px;
+ margin-right: 8px;
+`;
+
+export const Accounts = ({ change }: { change?: boolean }) => {
+ const [newAccount, setNewAccount] = React.useState();
+ const { id, changeAccount, accounts } = useAccount();
+
+ const [getCanConnect, { data, loading }] = useGetCanConnectLazyQuery({
+ fetchPolicy: 'network-only',
+ onError: () => {
+ toast.error('Unable to connect to this node');
+ },
+ });
+
+ React.useEffect(() => {
+ if (!loading && data?.getNodeInfo && newAccount) {
+ changeAccount(newAccount);
+ }
+ }, [data, loading, newAccount]);
+
+ if (accounts.length <= 1) {
+ return null;
+ }
+
+ const isType = (admin: string, viewOnly: string): string => {
+ if (!admin && viewOnly) {
+ return '(View Only)';
+ }
+ if (admin && !viewOnly) {
+ return '(Admin Only)';
+ }
+ return null;
+ };
+
+ const handleClick = account => () => {
+ const { id, viewOnly, cert, host } = account;
+ if (viewOnly) {
+ setNewAccount(id);
+ getCanConnect({
+ variables: { auth: { host, macaroon: viewOnly, cert } },
+ });
+ } else {
+ changeAccount(id);
+ }
+ };
+
+ return (
+
+
+ {change ? 'Accounts' : 'Other Accounts'}
+
+
+ {accounts.map((account, index) => {
+ if (account.id === id && !change) {
+ return;
+ }
+ return (
+
+
+ {account.name}
+
+ {isType(account.admin, account.viewOnly)}
+
+ {account.viewOnly ? 'Connect' : 'Login'}
+
+
+
+
+ );
+ })}
+
+
+ );
+};
diff --git a/src/views/homepage/HomePage.styled.ts b/src/views/homepage/HomePage.styled.ts
index e93b9c57..f73b7371 100644
--- a/src/views/homepage/HomePage.styled.ts
+++ b/src/views/homepage/HomePage.styled.ts
@@ -1,26 +1,29 @@
import styled, { keyframes } from 'styled-components';
-import { fontColors, mediaWidths } from '../../styles/Themes';
+import { fontColors, mediaWidths, headerColor } from '../../styles/Themes';
import ThunderHub from '../../assets/ThunderHub.svg';
export const Headline = styled.div`
display: flex;
align-items: center;
- justify-content: space-around;
- padding: 48px 0 140px;
+ justify-content: space-between;
+ padding: 32px 0 120px;
@media (${mediaWidths.mobile}) {
- flex-direction: column-reverse;
+ flex-direction: column;
+ padding: 0 0 60px;
+ width: 100%;
}
`;
export const LeftHeadline = styled.div`
- width: 50%;
+ width: 35%;
display: flex;
flex-direction: column;
@media (${mediaWidths.mobile}) {
width: 100%;
text-align: center;
+ margin-bottom: 0;
}
`;
@@ -52,38 +55,68 @@ export const StyledImage = styled(ThunderHub)`
}
@media (${mediaWidths.mobile}) {
- width: unset;
+ width: 100%;
}
`;
-export const HomeButton = styled.button`
- cursor: pointer;
- outline: none;
- padding: 8px 24px;
- text-decoration: 2px solid blue;
- font-size: 16px;
- background-image: linear-gradient(to right, #fd5f00, #f99325);
- color: white;
- border: none;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 8px;
- white-space: nowrap;
- width: 100%;
-`;
-
-export const Title = styled.h1`
+export const HomeTitle = styled.h1`
width: 100%;
text-align: center;
color: ${({ textColor }: { textColor?: string }) =>
textColor ? textColor : fontColors.white};
- font-size: 32px;
- margin-bottom: 0;
+ font-size: 56px;
+ margin: 0;
+ font-weight: 900;
+
+ @media (${mediaWidths.mobile}) {
+ font-size: 24px;
+ }
`;
-export const Text = styled.p`
+export const HomeText = styled.p`
color: ${fontColors.white};
- text-align: justify;
- max-width: 400px;
+ text-align: center;
+ font-size: 20px;
+
+ @media (${mediaWidths.mobile}) {
+ font-size: 15px;
+ }
+`;
+
+export const SlantedWrapper = styled.div`
+ position: relative;
+ width: 100%;
+ height: 200px;
+ margin-bottom: -290px;
+ overflow: hidden;
+ z-index: -5;
+`;
+
+export const SlantedEdge = styled.div`
+ content: '';
+ width: 100%;
+ height: 100%;
+ background: ${headerColor};
+ -webkit-transform-origin: 100% 0;
+ -ms-transform-origin: 100% 0;
+ transform-origin: 100% 0;
+ -webkit-transform: skew(84deg);
+ -ms-transform: skew(84deg);
+ transform: skew(88deg);
+ z-index: -5;
+`;
+
+export const FullWidth = styled.div`
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ margin-top: 8px;
+`;
+
+export const ConnectTitle = styled.div`
+ width: 100%;
+ font-size: 18px;
+ ${({ change }: { change?: boolean }) =>
+ change && `color: ${fontColors.white};`}
+ padding-bottom: 8px;
`;
diff --git a/src/views/homepage/HomePage.tsx b/src/views/homepage/HomePage.tsx
deleted file mode 100644
index 51765453..00000000
--- a/src/views/homepage/HomePage.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import { DetailSection } from './Sections/DetailSection';
-import { ContactSection } from './Sections/ContactSection';
-import { Compatible } from './Sections/Compatible';
-import { InfoSection } from './Sections/InfoSection';
-import { CallToAction } from './Sections/CallToAction';
-import { TopSection } from './Sections/Top';
-
-export const HomePageView = () => {
- return (
- <>
-
-
-
-
-
-
- >
- );
-};
diff --git a/pages/login.tsx b/src/views/homepage/LoginBox.tsx
similarity index 84%
rename from pages/login.tsx
rename to src/views/homepage/LoginBox.tsx
index 70b6b73f..533c6604 100644
--- a/pages/login.tsx
+++ b/src/views/homepage/LoginBox.tsx
@@ -1,14 +1,15 @@
import React, { useState } from 'react';
-import { Card, Separation } from '../src/components/generic/Styled';
+import { Card, Separation } from '../../components/generic/Styled';
import styled from 'styled-components';
-import { Section } from '../src/components/section/Section';
+import { Section } from '../../components/section/Section';
import {
MultiButton,
SingleButton,
-} from '../src/components/buttons/multiButton/MultiButton';
-import { Link } from '../src/components/link/Link';
-import { Auth } from '../src/components/auth';
-import { mediaWidths, unSelectedNavButton } from '../src/styles/Themes';
+} from '../../components/buttons/multiButton/MultiButton';
+import { Link } from '../../components/link/Link';
+import { Auth } from '../../components/auth';
+import { mediaWidths, unSelectedNavButton } from '../../styles/Themes';
+import { ConnectTitle } from './HomePage.styled';
const Text = styled.p`
width: 100%;
@@ -36,12 +37,7 @@ const Help = styled.div`
}
`;
-const ConnectTitle = styled.h1`
- width: 100%;
- text-align: center;
-`;
-
-const LoginView = () => {
+export const LoginBox = ({ change }: { change?: boolean }) => {
const [isType, setIsType] = useState('login');
const [status, setStatus] = useState('none');
const [help, setHelp] = useState(false);
@@ -142,9 +138,11 @@ const LoginView = () => {
};
return (
-
- {'How do you want to connect?'}
-
+
+
+ {change ? 'Connect to your Node' : 'Connect to another Node'}
+
+
{status === 'none' && (
<>
{renderButtons()}
@@ -164,5 +162,3 @@ const LoginView = () => {
);
};
-
-export default LoginView;
diff --git a/src/views/homepage/Sections/CallToAction.tsx b/src/views/homepage/Sections/CallToAction.tsx
deleted file mode 100644
index d689f4e3..00000000
--- a/src/views/homepage/Sections/CallToAction.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from 'react';
-import { Center } from '../../../components/typography/Styled';
-import { Section } from '../../../components/section/Section';
-import { Padding, StyledH2, StyledH1 } from './Sections.styled';
-import {
- homeBackgroundColor,
- homeBackgroundSecondColor,
-} from '../../../styles/Themes';
-import { HomeButton } from '../HomePage.styled';
-import { Zap } from '../../../components/generic/Icons';
-import styled from 'styled-components';
-import { Link } from '../../../components/link/Link';
-
-const CallToActionButton = styled(HomeButton)`
- margin: 16px 0 0;
-`;
-
-export const CallToAction = () => {
- return (
- <>
-
-
-
- Ready to take control of your Lightning Node?
-
-
-
-
-
-
-
- Control The Lightning
-
-
-
-
- >
- );
-};
diff --git a/src/views/homepage/Sections/Compatible.tsx b/src/views/homepage/Sections/Compatible.tsx
deleted file mode 100644
index 03e01fe3..00000000
--- a/src/views/homepage/Sections/Compatible.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import { Center } from '../../../components/typography/Styled';
-import { Section } from '../../../components/section/Section';
-import { WrapSingleLine, StyledH2, StyledP } from './Sections.styled';
-import { homeBackgroundColor } from '../../../styles/Themes';
-
-export const Compatible = () => {
- return (
-
-
- Compatible with the latest LND node versions.
-
-
- v0.7.1-beta
- v0.8.0-beta
- v0.8.1-beta
- v0.8.2-beta
- v0.9.0-beta
-
-
- );
-};
diff --git a/src/views/homepage/Sections/ContactSection.tsx b/src/views/homepage/Sections/ContactSection.tsx
deleted file mode 100644
index 12cbbdcd..00000000
--- a/src/views/homepage/Sections/ContactSection.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import React from 'react';
-import { Section } from '../../../components/section/Section';
-import { fontColors, homeBackgroundColor } from '../../../styles/Themes';
-import { Send, GithubIcon, MailIcon } from '../../../components/generic/Icons';
-import {
- Center,
- Question,
- SectionTitle,
- DetailCard,
- DetailLine,
- SmallText,
- IconMargin,
- IconTitle,
-} from '../../../components/typography/Styled';
-import { Link } from '../../../components/link/Link';
-
-export const ContactSection = () => (
-
-
-
- Need to contact us?
-
-
-
-
-
-
-
-
-
-
- Telegram
-
-
-
- Join the chat on Telegram. Usually the quickest reponse.
-
-
-
-
-
-
-
-
-
-
- Github
-
-
-
- See the code, open issues or contribute on github.
-
-
-
-
-
-
-
-
-
-
- Email
-
-
- Write us an email at thunderhub@protonmail.com
-
-
-
-
-);
diff --git a/src/views/homepage/Sections/DetailSection.tsx b/src/views/homepage/Sections/DetailSection.tsx
deleted file mode 100644
index 2c257a63..00000000
--- a/src/views/homepage/Sections/DetailSection.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-import React from 'react';
-import {
- Card,
- SubTitle,
- ColumnLine,
- Sub4Title,
- SingleLine,
-} from '../../../components/generic/Styled';
-import styled from 'styled-components';
-import {
- Eye,
- Send,
- Key,
- Server,
- Sliders,
- Users,
-} from '../../../components/generic/Icons';
-import { cardColor, mediaWidths } from '../../../styles/Themes';
-import { Section } from '../../../components/section/Section';
-
-const Padding = styled.div`
- padding: ${({ padding }: { padding?: string }) =>
- padding ? padding : '16px'};
-`;
-
-const DetailCard = styled(Card)`
- background-color: ${cardColor};
- margin-bottom: 0;
- margin: 8px 16px;
- z-index: 1;
- flex: 1 0 30%;
-
- @media (${mediaWidths.mobile}) {
- flex: 1 0 100%;
- }
-`;
-
-const DetailLine = styled.div`
- margin: 0 -16px;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-wrap: wrap;
- @media (${mediaWidths.mobile}) {
- margin: 0;
- }
-`;
-
-const detailCardContent = (title: string, text: string, Icon: any) => (
-
-
-
-
-
-
- {title}
- {text}
-
-
-
-);
-
-export const DetailSection = () => {
- return (
-
-
- {detailCardContent(
- 'Make Payments',
- 'Send and receive both Lightning and On-Chain payments.',
- Send
- )}
- {detailCardContent(
- 'Multiple Nodes',
- 'Connect to multiple nodes and quickly switch between them.',
- Server
- )}
- {detailCardContent(
- 'View-Only Mode',
- 'Check the status of your node any time without risk.',
- Eye
- )}
- {detailCardContent(
- 'AES Encryption',
- 'Your Macaroon is AES encrypted with a password only you know.',
- Key
- )}
- {detailCardContent(
- 'Open Source',
- "Don't trust anyone. Verify the code yourself.",
- Users
- )}
- {detailCardContent(
- 'Manage Channels',
- 'Open, close and monitor channel status and liquidity',
- Sliders
- )}
-
-
- );
-};
diff --git a/src/views/homepage/Sections/InfoSection.tsx b/src/views/homepage/Sections/InfoSection.tsx
deleted file mode 100644
index 94b2870e..00000000
--- a/src/views/homepage/Sections/InfoSection.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import React from 'react';
-import { Section } from '../../../components/section/Section';
-import {
- InfoRow,
- ImageSection,
- ImagePlace,
- TextSection,
-} from './Sections.styled';
-import { Text } from '../../../components/typography/Styled';
-import { appendBasePath } from '../../../utils/basePath';
-
-export const InfoSection = () => {
- return (
- <>
-
-
-
- Send and Receive
-
- Send and receive both Lightning and Bitcoin payments in a simple
- and easy to use interface with both basic and advanced features.
-
-
-
-
-
-
-
-
-
-
-
-
-
- Transaction Reports
-
- Have a quick overview of the invoices coming into your node and
- payments being made. Check both the amount and value of your
- transactions. See total amount together with confirmed and
- unconfirmed invoices.
-
-
-
-
-
-
-
- Channel Management
-
- See all your channels and get a quick preview of how balanced and
- active they are. Open new channels or close them.
-
-
-
-
-
-
-
-
-
-
-
-
-
- Forwarded Payments
-
- Quick glance at the forwarded payments that have been going
- through your node. See the incoming and outgoing channels being
- used.
-
-
-
-
-
-
-
- Night/Day Mode
-
- Prefer working in the dark? We have an awesome night mode just for
- you. Want it more bright? Got you covered as well.
-
-
-
-
-
-
-
- >
- );
-};
diff --git a/src/views/homepage/Sections/Sections.styled.tsx b/src/views/homepage/Sections/Sections.styled.tsx
deleted file mode 100644
index 31076ebb..00000000
--- a/src/views/homepage/Sections/Sections.styled.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import styled from 'styled-components';
-import { SingleLine } from '../../../components/generic/Styled';
-import { headerColor, mediaWidths } from '../../../styles/Themes';
-
-export const Padding = styled.div`
- padding: 4px 4px 0 0;
-`;
-
-export const SlantedWrapper = styled.div`
- width: 100%;
- height: 200px;
- margin-bottom: -260px;
- overflow: hidden;
- z-index: -5;
-`;
-
-export const SlantedEdge = styled.div`
- content: '';
- width: 100%;
- height: 100%;
- background: ${headerColor};
- -webkit-transform-origin: 100% 0;
- -ms-transform-origin: 100% 0;
- transform-origin: 100% 0;
- -webkit-transform: skew(84deg);
- -ms-transform: skew(84deg);
- transform: skew(88deg);
- z-index: -5;
-`;
-
-export const FullWidth = styled.div`
- display: flex;
- justify-content: center;
- width: 100%;
- margin-top: 18px;
-`;
-
-export const InfoRow = styled.div`
- display: flex;
- align-items: center;
- justify-content: space-between;
- align-items: stretch;
-
- @media (${mediaWidths.mobile}) {
- flex-direction: ${({ reverse }: { reverse?: boolean }) =>
- reverse ? 'column-reverse' : 'column'};
- }
-`;
-
-export const HalfSection = styled.div`
- width: 50%;
- display: flex;
- flex-direction: column;
-
- @media (${mediaWidths.mobile}) {
- width: 100%;
- text-align: center;
- }
-`;
-
-export const ImageSection = styled(HalfSection)`
- align-self: center;
-`;
-
-export const TextSection = styled(HalfSection)`
- padding: 0 32px;
-
- @media (${mediaWidths.mobile}) {
- padding: 0 8px;
- }
-`;
-
-export const ImagePlace = styled.img`
- display: flex;
- width: 100%;
- height: auto;
- justify-content: center;
- align-items: center;
-`;
-
-export const WrapSingleLine = styled(SingleLine)`
- flex-wrap: wrap;
- justify-content: space-around;
- flex-grow: 1;
-`;
-
-export const StyledH1 = styled.h1``;
-
-export const StyledH2 = styled.h2``;
-
-export const StyledP = styled.p``;
diff --git a/src/views/homepage/Sections/Top.tsx b/src/views/homepage/Sections/Top.tsx
deleted file mode 100644
index bec77a74..00000000
--- a/src/views/homepage/Sections/Top.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import {
- Headline,
- LeftHeadline,
- StyledImage,
- HomeButton,
- Title,
- Text,
-} from '../HomePage.styled';
-import { Zap } from '../../../components/generic/Icons';
-import { headerColor, inverseTextColor } from '../../../styles/Themes';
-import { Section } from '../../../components/section/Section';
-import {
- FullWidth,
- Padding,
- SlantedWrapper,
- SlantedEdge,
-} from './Sections.styled';
-import { Link } from '../../../components/link/Link';
-
-export const TopSection = () => {
- return (
- <>
-
-
-
- Control The Power of Lightning
-
-
- Take full control of your lightning node for quick monitoring
- and management inside your browser.
-
-
-
-
-
-
-
-
- Control The Lightning
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
diff --git a/src/views/homepage/Top.tsx b/src/views/homepage/Top.tsx
new file mode 100644
index 00000000..6c175d5c
--- /dev/null
+++ b/src/views/homepage/Top.tsx
@@ -0,0 +1,60 @@
+import React, { useState } from 'react';
+import {
+ Headline,
+ LeftHeadline,
+ StyledImage,
+ HomeTitle,
+ HomeText,
+ FullWidth,
+ SlantedWrapper,
+ SlantedEdge,
+} from './HomePage.styled';
+import { headerColor, inverseTextColor } from '../../styles/Themes';
+import { Section } from '../../components/section/Section';
+import { useTransition, animated, config } from 'react-spring';
+
+export const TopSection = () => {
+ const [state] = useState(true);
+
+ const transition = useTransition(state, null, {
+ config: config.slow,
+ from: { transform: 'translate3d(-80px,0,0)', opacity: 0 },
+ enter: { transform: 'translate3d(0,0,0)', opacity: 1 },
+ });
+
+ const transition2 = useTransition(state, null, {
+ config: config.slow,
+ from: { transform: 'translate3d(80px,0,0)', opacity: 0 },
+ enter: { transform: 'translate3d(0,0,0)', opacity: 1 },
+ });
+
+ return (
+ <>
+
+
+
+ {transition.map(({ props, key }) => (
+
+ Control the Lightning
+
+
+ Monitor and manage your node from any browser and any
+ device.
+
+
+
+ ))}
+
+ {transition2.map(({ props, key }) => (
+
+
+
+ ))}
+
+
+
+
+
+ >
+ );
+};
diff --git a/src/views/login/SessionLogin.tsx b/src/views/login/SessionLogin.tsx
index a4d90720..38ffdab2 100644
--- a/src/views/login/SessionLogin.tsx
+++ b/src/views/login/SessionLogin.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
import { useAccount } from '../../context/AccountContext';
import { SingleLine, Sub4Title, Card } from '../../components/generic/Styled';
import CryptoJS from 'crypto-js';
@@ -9,31 +9,58 @@ import { Input } from '../../components/input/Input';
import { Section } from '../../components/section/Section';
import { Title } from '../../components/typography/Styled';
import styled from 'styled-components';
-import { textColor } from '../../styles/Themes';
+import { inverseTextColor, mediaWidths } from '../../styles/Themes';
+import { useGetCanConnectLazyQuery } from '../../generated/graphql';
+import { useStatusDispatch } from '../../context/StatusContext';
const StyledTitle = styled(Title)`
- font-size: 28px;
- color: ${textColor};
+ font-size: 24px;
+ color: ${inverseTextColor};
+
+ @media (${mediaWidths.mobile}) {
+ font-size: 18px;
+ }
`;
export const SessionLogin = () => {
- const { name, admin, refreshAccount } = useAccount();
+ const { name, host, admin, cert, refreshAccount } = useAccount();
const [pass, setPass] = useState('');
+ const dispatch = useStatusDispatch();
- const handleClick = () => {
- try {
+ const [getCanConnect, { data, loading }] = useGetCanConnectLazyQuery({
+ fetchPolicy: 'network-only',
+ onError: () => {
+ toast.error('Unable to connect to this node');
+ dispatch({ type: 'disconnected' });
+ },
+ });
+
+ useEffect(() => {
+ if (!loading && data?.getNodeInfo) {
const bytes = CryptoJS.AES.decrypt(admin, pass);
const decrypted = bytes.toString(CryptoJS.enc.Utf8);
saveSessionAuth(decrypted);
refreshAccount();
+ dispatch({ type: 'connected' });
+ }
+ }, [data, loading]);
+
+ const handleClick = () => {
+ try {
+ const bytes = CryptoJS.AES.decrypt(admin, pass);
+ const decrypted = bytes.toString(CryptoJS.enc.Utf8);
+
+ getCanConnect({
+ variables: { auth: { host, macaroon: decrypted, cert } },
+ });
} catch (error) {
toast.error('Wrong Password');
}
};
return (
-
+
{`Please Login (${name}):`}
@@ -45,11 +72,11 @@ export const SessionLogin = () => {
/>
Connect
diff --git a/src/views/settings/Account.tsx b/src/views/settings/Account.tsx
index 3cb29500..34f7804f 100644
--- a/src/views/settings/Account.tsx
+++ b/src/views/settings/Account.tsx
@@ -15,7 +15,6 @@ import {
MultiButton,
SingleButton,
} from '../../components/buttons/multiButton/MultiButton';
-import { useConnectionDispatch } from '../../context/ConnectionContext';
import { useStatusDispatch } from '../../context/StatusContext';
import { Auth } from '../../components/auth';
import { useRouter } from 'next/router';
@@ -27,8 +26,7 @@ export const AccountSettings = () => {
const { push } = useRouter();
const { id, changeAccount, accounts } = useAccount();
- const dispatch = useConnectionDispatch();
- const dispatchState = useStatusDispatch();
+ const dispatch = useStatusDispatch();
const [isType, setIsType] = useState('login');
const [willAdd, setWillAdd] = useState(false);
@@ -82,9 +80,6 @@ export const AccountSettings = () => {
onClick={() => {
if (accountId !== id) {
dispatch({ type: 'disconnected' });
- dispatchState({
- type: 'disconnected',
- });
changeAccount(accountId);
push(appendBasePath('/'));
}
diff --git a/src/views/settings/Danger.tsx b/src/views/settings/Danger.tsx
index ca2f7dce..86aa0c2c 100644
--- a/src/views/settings/Danger.tsx
+++ b/src/views/settings/Danger.tsx
@@ -17,7 +17,6 @@ import {
SingleButton,
} from '../../components/buttons/multiButton/MultiButton';
import { AlertCircle } from '../../components/generic/Icons';
-import { useConnectionDispatch } from '../../context/ConnectionContext';
import { useStatusDispatch } from '../../context/StatusContext';
import { useRouter } from 'next/router';
import { appendBasePath } from '../../utils/basePath';
@@ -76,8 +75,7 @@ export const DangerView = () => {
id,
} = useAccount();
- const dispatch = useConnectionDispatch();
- const dispatchState = useStatusDispatch();
+ const dispatch = useStatusDispatch();
const { push } = useRouter();
@@ -125,9 +123,6 @@ export const DangerView = () => {
const handleDelete = (admin?: boolean) => {
deleteAccountPermissions(id, accounts, admin);
dispatch({ type: 'disconnected' });
- dispatchState({
- type: 'disconnected',
- });
changeAccount(id);
push(appendBasePath('/'));
};