Skip to content

Commit

Permalink
ui+home: add home screen with connect buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
jamaljsr committed Aug 3, 2022
1 parent fd7f5d3 commit ca3b710
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 19 deletions.
9 changes: 9 additions & 0 deletions app/src/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Layout } from 'components/layout';

const LazyAuthPage = React.lazy(() => import('components/auth/AuthPage'));
const LazyLoopPage = React.lazy(() => import('components/loop/LoopPage'));
const LazyHomePage = React.lazy(() => import('components/home/HomePage'));
const LazyHistoryPage = React.lazy(() => import('components/history/HistoryPage'));
const LazyPoolPage = React.lazy(() => import('components/pool/PoolPage'));
const LazySettingsPage = React.lazy(() => import('components/settings/SettingsPage'));
Expand All @@ -14,6 +15,14 @@ const AppRoutes: React.FC = () => {
<Routes>
<Route path="/" element={<LazyAuthPage />} />
<Route>
<Route
path="home"
element={
<Layout>
<LazyHomePage />
</Layout>
}
/>
<Route
path="loop"
element={
Expand Down
24 changes: 12 additions & 12 deletions app/src/__tests__/components/layout/Layout.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,31 @@ describe('Layout component', () => {
it('should navigate to the History page', () => {
const { getByText, store } = render();
expect(store.router.location.pathname).toBe('/loop');
fireEvent.click(getByText('History'));
fireEvent.click(getByText('Loop History'));
expect(store.router.location.pathname).toBe('/history');
expect(getByText('History').parentElement).toHaveClass('active');
expect(getByText('Loop History').parentElement).toHaveClass('active');
});

it('should navigate back to the Loop page', () => {
const { getByText, store } = render();
expect(store.router.location.pathname).toBe('/loop');
fireEvent.click(getByText('History'));
fireEvent.click(getByText('Loop History'));
expect(store.router.location.pathname).toBe('/history');
expect(getByText('History').parentElement).toHaveClass('active');
fireEvent.click(getByText('Lightning Loop'));
expect(getByText('Loop History').parentElement).toHaveClass('active');
fireEvent.click(getByText('Loop'));
expect(store.router.location.pathname).toBe('/loop');
expect(getByText('Lightning Loop').parentElement).toHaveClass('active');
expect(getByText('Loop').parentElement).toHaveClass('active');
});

it('should navigate to the Pool page', () => {
const { getByText, store } = render();
expect(store.router.location.pathname).toBe('/loop');
fireEvent.click(getByText('Lightning Pool'));
fireEvent.click(getByText('Pool'));
expect(store.router.location.pathname).toBe('/pool');
expect(getByText('Lightning Pool').parentElement).toHaveClass('active');
fireEvent.click(getByText('Lightning Loop'));
expect(getByText('Pool').parentElement).toHaveClass('active');
fireEvent.click(getByText('Loop'));
expect(store.router.location.pathname).toBe('/loop');
expect(getByText('Lightning Loop').parentElement).toHaveClass('active');
expect(getByText('Loop').parentElement).toHaveClass('active');
});

it('should navigate to the Settings page', () => {
Expand All @@ -61,8 +61,8 @@ describe('Layout component', () => {
fireEvent.click(getByText('Settings'));
expect(store.router.location.pathname).toBe('/settings');
expect(getByText('Settings').parentElement).toHaveClass('active');
fireEvent.click(getByText('Lightning Loop'));
fireEvent.click(getByText('Loop'));
expect(store.router.location.pathname).toBe('/loop');
expect(getByText('Lightning Loop').parentElement).toHaveClass('active');
expect(getByText('Loop').parentElement).toHaveClass('active');
});
});
Binary file added app/src/assets/images/home_dash_ss.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/assets/images/home_loop_ss.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions app/src/assets/images/youtube.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
115 changes: 115 additions & 0 deletions app/src/components/home/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useCallback, useState } from 'react';
import { observer } from 'mobx-react-lite';
import styled from '@emotion/styled';
import DashUX from 'assets/images/home_dash_ss.png';
import LoopUX from 'assets/images/home_loop_ss.png';
import { ReactComponent as Youtube } from 'assets/images/youtube.svg';
import { usePrefixedTranslation } from 'hooks';
import { useStore } from 'store';
import {
BoltOutlined,
Button,
Column,
Display,
Paragraph,
QRCode,
Row,
} from 'components/base';
import PurpleButton from 'components/connect/PurpleButton';
import QRCodeModal from 'components/connect/QRCodeModal';
import YoutubeModal from './YoutubeModal';

const Styled = {
Wrapper: styled.div`
padding: 72px 0;
`,
PurpleButton: styled(PurpleButton)`
font-size: ${props => props.theme.sizes.s};
line-height: 24px;
padding: 8px 16px;
margin-right: 24px;
`,
YoutubeButton: styled(Button)`
font-family: ${props => props.theme.fonts.open.semiBold};
padding-left: 0;
svg {
margin-right: 16px;
}
`,
Image: styled.img`
width: 100%;
margin-bottom: 24px;
`,
};

const HomePage: React.FC = () => {
const { l } = usePrefixedTranslation('cmps.home.HomePage');
const [showQR, setShowQR] = useState(false);
const [showVideo, setShowVideo] = useState(false);
const { sessionStore } = useStore();

const toggleQRModal = useCallback(() => setShowQR(v => !v), []);
const toggleVideoModal = useCallback(() => setShowVideo(v => !v), []);

const { Wrapper, PurpleButton, YoutubeButton, Image } = Styled;
return (
<Wrapper>
<Display semiBold space={16}>
{l('pageTitle')}
</Display>
<Paragraph space={32}>{l('connectDesc')}</Paragraph>
<Paragraph space={40}>
<a href={sessionStore.firstSessionTerminalUrl} target="_blank" rel="noreferrer">
<PurpleButton>
<BoltOutlined />
{l('connectTerminalBtn')}
</PurpleButton>
</a>
<PurpleButton secondary onClick={toggleQRModal}>
<QRCode />
{l('connectQrBtn')}
</PurpleButton>
</Paragraph>
<Paragraph space={32}>{l('learnDesc')}</Paragraph>
<Paragraph space={40}>
<YoutubeButton ghost borderless compact onClick={toggleVideoModal}>
<Youtube />
Learn More
</YoutubeButton>
</Paragraph>
<Display semiBold space={16}>
{l('whatsDiff')}
</Display>
<Paragraph space={24}>{l('diffDesc')}</Paragraph>
<Row>
<Column>
<Image src={LoopUX} alt={l('loopTitle')} />
<Paragraph semiBold space={8}>
{l('loopTitle')}
</Paragraph>
<Paragraph muted>{l('loopDesc')}</Paragraph>
</Column>
<Column>
<Image src={DashUX} alt={l('dashTitle')} />
<Paragraph semiBold space={8}>
{l('dashTitle')}
</Paragraph>
<Paragraph muted>{l('dashDesc')}</Paragraph>
</Column>
</Row>
<QRCodeModal
url={sessionStore.firstSessionTerminalUrl}
visible={showQR}
onClose={toggleQRModal}
/>
<YoutubeModal
videoId="5kH1ByxjkTM"
visible={showVideo}
onClose={toggleVideoModal}
/>
</Wrapper>
);
};

export default observer(HomePage);
53 changes: 53 additions & 0 deletions app/src/components/home/YoutubeModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import styled from '@emotion/styled';
import { usePrefixedTranslation } from 'hooks';
import Modal from 'components/common/Modal';

const Styled = {
VideoModal: styled(Modal)`
width: 800px;
max-width: 90%;
overflow: hidden;
`,
VideoWrap: styled.div`
position: relative;
padding-bottom: 56.25%; /* 16:9 */
height: 0;
> iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
`,
};

interface Props {
videoId: string;
visible: boolean;
onClose: () => void;
}

const YoutubeModal: React.FC<Props> = ({ videoId, visible, onClose }) => {
const { l } = usePrefixedTranslation('cmps.home.YoutubeModal');
const { VideoModal, VideoWrap } = Styled;
return (
<VideoModal title={l('title')} visible={visible} onClose={onClose}>
<VideoWrap>
<iframe
width="568"
height="315"
src={`https://www.youtube.com/embed/${videoId}`}
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</VideoWrap>
</VideoModal>
);
};

export default YoutubeModal;
14 changes: 11 additions & 3 deletions app/src/components/layout/NavMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import { PUBLIC_URL } from '../../config';

const Styled = {
NavHeader: styled(HeaderFour)`
padding: 8px 14px;
padding: 44px 14px 8px;
font-size: 10px;
line-height: 16px;
`,
Nav: styled.ul`
padding-left: 0;
Expand Down Expand Up @@ -78,12 +80,18 @@ const NavMenu: React.FC = () => {
const { NavHeader, Nav } = Styled;
return (
<>
<NavHeader>{l('menu')}</NavHeader>
<Nav>
<NavItem page="home" onClick={appView.goToHome} />
<NavItem page="settings" onClick={appView.goToSettings} />
</Nav>
<NavHeader>{l('liquidityHeader')}</NavHeader>
<Nav>
<NavItem page="loop" onClick={appView.goToLoop} />
<NavItem page="history" onClick={appView.goToHistory} />
<NavItem page="pool" badge={l('common.preview')} onClick={appView.goToPool} />
<NavItem page="settings" onClick={appView.goToSettings} />
</Nav>
<NavHeader>{l('connectHeader')}</NavHeader>
<Nav>
<NavItem page="connect" badge={l('common.beta')} onClick={appView.goToConnect} />
</Nav>
</>
Expand Down
24 changes: 20 additions & 4 deletions app/src/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@
"cmps.connect.SessionRow.revoke": "Revoke Session",
"cmps.connect.QRCodeModal.title": "LNC QR",
"cmps.connect.QRCodeModal.desc": "Scan to connect to Terminal from your mobile phone.",
"cmps.home.HomePage.pageTitle": "Home",
"cmps.home.HomePage.connectDesc": "Connect your node to Terminal on the web via the link below. For mobile, generate a QR code to connect.",
"cmps.home.HomePage.connectTerminalBtn": "Connect to Terminal",
"cmps.home.HomePage.connectQrBtn": "Connect with QR",
"cmps.home.HomePage.learnDesc": "The connection to your node occurs through the Lightning Node Connect protocol.",
"cmps.home.HomePage.learnMore": "Learn More",
"cmps.home.HomePage.whatsDiff": "What's different?",
"cmps.home.HomePage.diffDesc": "In the web based Terminal experience, you can expect new features like:",
"cmps.home.HomePage.loopTitle": "Improved Lightning Loop UX",
"cmps.home.HomePage.loopDesc": "Visually focused loop experience with Autoloop built-in.",
"cmps.home.HomePage.dashTitle": "Lightning Terminal Dashboard",
"cmps.home.HomePage.dashDesc": "Easily monitor routing activity and manage your channels through the dashboard.",
"cmps.home.YoutubeModal.title": "Get Connected",
"cmps.home.YoutubeModal.desc": "Get Connected with Lightning Node Connect",
"cmps.history.HistoryPage.backText": "Lightning Loop",
"cmps.history.HistoryPage.pageTitle": "History",
"cmps.history.HistoryRowHeader.status": "Status",
Expand Down Expand Up @@ -128,11 +142,13 @@
"cmps.loop.swap.SwapReviewStep.fees": "Fees",
"cmps.loop.swap.SwapReviewStep.total": "Total",
"cmps.loop.swap.SwapWizard.backTip": "Back to Previous",
"cmps.layout.NavMenu.menu": "Menu",
"cmps.layout.NavMenu.loop": "Lightning Loop",
"cmps.layout.NavMenu.history": "History",
"cmps.layout.NavMenu.pool": "Lightning Pool",
"cmps.layout.NavMenu.home": "Home",
"cmps.layout.NavMenu.settings": "Settings",
"cmps.layout.NavMenu.liquidityHeader": "Liquidity",
"cmps.layout.NavMenu.loop": "Loop",
"cmps.layout.NavMenu.history": "Loop History",
"cmps.layout.NavMenu.pool": "Pool",
"cmps.layout.NavMenu.connectHeader": "Connect",
"cmps.layout.NavMenu.connect": "Lightning Node Connect",
"cmps.NodeStatus.title": "Node Status",
"cmps.NodeStatus.offchainTip": "Off-chain Funds",
Expand Down

0 comments on commit ca3b710

Please sign in to comment.