Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: add home screen and update sessions list #401

Merged
merged 4 commits into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"mobx": "6.3.2",
"mobx-react-lite": "3.2.0",
"mobx-utils": "6.0.4",
"qrcode.react": "^3.1.0",
"rc-dialog": "^8.9.0",
"rc-select": "11.5.0",
"rc-tooltip": "4.2.1",
"react": "17.0.2",
Expand Down
1 change: 1 addition & 0 deletions app/src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

// react-component component styles
@import '../node_modules/rc-tooltip/assets/bootstrap_white.css';
@import '../node_modules/rc-dialog/assets/index.css';
@import './assets/styles/rc-select.scss';

// react-toastify styles
Expand Down
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');
});
});
5 changes: 5 additions & 0 deletions app/src/assets/icons/bolt-outlined.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions app/src/assets/icons/qr.svg
Loading
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_dash_ss.png
Loading
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
Loading
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
Loading
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/components/base/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { ReactComponent as RefreshIcon } from 'assets/icons/refresh-cw.svg';
import { ReactComponent as SettingsIcon } from 'assets/icons/settings.svg';
import { ReactComponent as CancelIcon } from 'assets/icons/slash.svg';
import { ReactComponent as UserPlusIcon } from 'assets/icons/user-plus.svg';
import { ReactComponent as QRCodeIcon } from 'assets/icons/qr.svg';
import { ReactComponent as BoltOutlinedIcon } from 'assets/icons/bolt-outlined.svg';

interface IconProps {
size?: 'x-small' | 'small' | 'medium' | 'large';
Expand Down Expand Up @@ -119,3 +121,5 @@ export const Settings = Icon.withComponent(SettingsIcon);
export const UserPlus = Icon.withComponent(UserPlusIcon);
export const BarChart = Icon.withComponent(BarChartIcon);
export const List = Icon.withComponent(ListIcon);
export const QRCode = Icon.withComponent(QRCodeIcon);
export const BoltOutlined = Icon.withComponent(BoltOutlinedIcon);
46 changes: 46 additions & 0 deletions app/src/components/base/text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,49 @@ export const Jumbo = styled.span`
font-size: ${props => props.theme.sizes.xl};
line-height: 38px;
`;

//
// v2 Text Styles
//

interface TextProps {
bold?: boolean;
semiBold?: boolean;
center?: boolean;
block?: boolean;
muted?: boolean;
space?: 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 96 | 120 | 160 | 200;
desktopSpace?: 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 96 | 120 | 160 | 200;
}

const BaseText = styled.span<TextProps>`
// On larger devices, make bold elements bold instead of semi-bold
font-family: ${props =>
props.bold
? props.theme.fonts.open.bold
: props.semiBold
? props.theme.fonts.open.semiBold
: props.theme.fonts.open.regular};

// The text-align property is ignored on mobile
${props => props.muted && `color: ${props.theme.colors.gray};`}
${props => props.space && `margin-bottom: ${props.space}px;`}
text-align: ${props => (props.center ? 'center' : 'left')};
`;

const BaseBlock = BaseText.withComponent('div');

export const DisplayLarge = styled(BaseBlock)`
font-size: 40px;
line-height: 48px;
`;

export const Display = styled(BaseBlock)`
font-size: 32px;
line-height: 40px;
`;

export const Paragraph = styled(BaseBlock)`
font-size: 16px;
line-height: 24px;
`;
4 changes: 4 additions & 0 deletions app/src/components/common/AlertContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ const Styled = {
color: ${props => props.theme.colors.offWhite};
background-color: ${props => props.theme.colors.pink};
}
.Toastify__toast--warning {
color: ${props => props.theme.colors.offWhite};
background-color: ${props => props.theme.colors.gold};
}
`,
};

Expand Down
84 changes: 84 additions & 0 deletions app/src/components/common/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React from 'react';
import { Global, Theme } from '@emotion/react';
import CloseIcon from 'assets/icons/close.svg';
import Dialog from 'rc-dialog';

const GlobalStyles = (theme: Theme) => `
div.rc-dialog {
font-family: ${theme.fonts.open.regular};
font-size: ${theme.sizes.m};
}
div.rc-dialog-content {
color: ${theme.colors.offWhite};
background-color: ${theme.colors.blue};
}
div.rc-dialog-header {
color: ${theme.colors.offWhite};
background-color: ${theme.colors.blue};
border-width: 0px;
padding: 32px 40px;
}
div.rc-dialog-title {
font-size: 32px;
line-height: 40px;
overflow: hidden;
text-overflow: ellipsis;
}
button.rc-dialog-close {
color: ${theme.colors.offWhite};
font-size: ${theme.sizes.xxl};
opacity: 1;
top: 34px;
right: 34px;
width: 24px;
height: 24px;
padding: 0;
background-color: ${theme.colors.offWhite};
mask-image: url(${CloseIcon});
padding: 0;

&:hover {
opacity: 0.6;
}
}
span.rc-dialog-close-x:after {
content: "";
}
div.rc-dialog-body {
padding: 0 40px 40px;
}
div.rc-dialog-mask {
background-color: rgba(0, 0, 0, 0.8);
}
div.rc-dialog-footer {
border-width: 0px;
padding: 0 40px 40px;
text-align: left;
}
`;

interface Props {
title: string;
visible: boolean;
onClose: () => void;
className?: string;
}

const Modal: React.FC<Props> = ({ title, visible, onClose, className, children }) => {
return (
<Dialog
title={title}
animation="zoom"
maskAnimation="fade"
visible={visible}
onClose={onClose}
maskClosable
className={className}
>
{children}
<Global styles={GlobalStyles} />
</Dialog>
);
};

export default Modal;
4 changes: 2 additions & 2 deletions app/src/components/connect/AddSession.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useCallback, useState } from 'react';
import { observer } from 'mobx-react-lite';
import * as LIT from 'types/generated/lit-sessions_pb';
import styled from '@emotion/styled';
import { usePrefixedTranslation } from 'hooks';
import * as LIT from 'types/generated/lit-sessions_pb';
import { MAX_DATE } from 'util/constants';
import { useStore } from 'store';
import { Button, Column, HeaderFour, Row } from 'components/base';
Expand Down Expand Up @@ -55,7 +55,7 @@ const AddSession: React.FC<Props> = ({ primary }) => {
? LIT.SessionType.TYPE_MACAROON_ADMIN
: LIT.SessionType.TYPE_MACAROON_READONLY;

const session = await sessionStore.addSession(label, sessionType, MAX_DATE);
const session = await sessionStore.addSession(label, sessionType, MAX_DATE, true);

if (session) {
setLabel('');
Expand Down
47 changes: 10 additions & 37 deletions app/src/components/connect/ConnectPage.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,34 @@
import React from 'react';
import React, { useEffect } from 'react';
import { observer } from 'mobx-react-lite';
import styled from '@emotion/styled';
import nodeConnectSvg from 'assets/images/lightning-node-connect.svg';
import { usePrefixedTranslation } from 'hooks';
import { useStore } from 'store';
import { Copy } from 'components/base';
import { DisplayLarge } from 'components/base';
import AddSession from './AddSession';
import PurpleButton from './PurpleButton';
import SessionList from './SessionList';

const Styled = {
Wrapper: styled.section`
padding-top: 80px;
`,
DisplayLarge: styled.div`
font-family: ${props => props.theme.fonts.open.semiBold};
font-size: 32px;
line-height: 40px;
margin-top: 32px;
margin-bottom: 16px;
`,
Description: styled.div`
margin-bottom: 32px;
`,
Divider: styled.div`
max-width: 640px;
border: 1px solid #384770;
margin: 32px 0;
`,
};

const ConnectPage: React.FC = () => {
const { l } = usePrefixedTranslation('cmps.connect.ConnectPage');
const { sessionStore } = useStore();

const { Wrapper, DisplayLarge, Description, Divider } = Styled;
return !sessionStore.hasMultiple ? (
<Wrapper>
<img src={nodeConnectSvg} alt={l('pageTitle')} />
<DisplayLarge>{l('pageTitle')}</DisplayLarge>
<Description>
{l('description1')}
<br />
{l('description2')}
</Description>
<PurpleButton onClick={sessionStore.copyFirstPhrase}>
<Copy />
{l('copyPhraseLabel')}
</PurpleButton>
<Divider />
<Description>{l('addlDesc')}</Description>
<AddSession />
</Wrapper>
) : (
useEffect(() => {
sessionStore.fetchSessions();
}, []);

const { Wrapper, Description } = Styled;
return (
<Wrapper>
<DisplayLarge>{l('pageTitle')}</DisplayLarge>
<Description>{l('description1')}</Description>
<DisplayLarge space={16}>{l('pageTitle')}</DisplayLarge>
<Description>{l('description')}</Description>
<AddSession primary />
<SessionList />
</Wrapper>
Expand Down
13 changes: 13 additions & 0 deletions app/src/components/connect/PurpleButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import styled from '@emotion/styled';

interface Props {
secondary?: boolean;
tertiary?: boolean;
}

Expand All @@ -23,6 +24,18 @@ const PurpleButton = styled.button<Props>`
outline: none;
}

${props =>
props.secondary &&
`
color: #252F4A;
background-color: ${props.theme.colors.white};

&:hover {
opacity: 0.8;
background-color: ${props.theme.colors.white};
}
`}

${props =>
props.tertiary &&
`
Expand Down
Loading