Skip to content

Add Loop History page #39

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

Merged
merged 5 commits into from
May 19, 2020
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
6 changes: 5 additions & 1 deletion app/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
module.exports = {
stories: ['../src/**/*.stories.(ts|tsx|js|jsx|mdx)'],
stories: [
// display the Loop page as the first story int he list
'../src/__stories__/LoopPage.stories.tsx',
'../src/**/*.stories.(ts|tsx|js|jsx|mdx)',
],
addons: [
'@storybook/preset-create-react-app',
'@storybook/addon-actions',
Expand Down
5 changes: 3 additions & 2 deletions app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import React from 'react';
import './App.scss';
import { createStore, StoreProvider } from 'store';
import { Layout } from 'components/layout';
import LoopPage from 'components/loop/LoopPage';
import Pages from 'components/Pages';
import { ThemeProvider } from 'components/theme';

const App = () => {
const store = createStore();

return (
<StoreProvider store={store}>
<ThemeProvider>
<Layout>
<LoopPage />
<Pages />
</Layout>
</ThemeProvider>
</StoreProvider>
Expand Down
36 changes: 36 additions & 0 deletions app/src/__stories__/HistoryPage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { SwapState, SwapType } from 'types/generated/loop_pb';
import { useStore } from 'store';
import HistoryPage from 'components/history/HistoryPage';
import { Layout } from 'components/layout';

export default {
title: 'Pages/History',
component: HistoryPage,
parameters: { contained: true },
};

export const Default = () => {
const store = useStore();
store.swapStore.stopAutoPolling();
store.swapStore.sortedSwaps.forEach((s, i) => {
if (s.typeName === 'Unknown') s.type = SwapType.LOOP_IN;
if (i === 0) s.state = SwapState.INVOICE_SETTLED;
});
return <HistoryPage />;
};

export const InsideLayout = () => {
const store = useStore();
store.uiStore.page = 'history';
store.swapStore.stopAutoPolling();
store.swapStore.sortedSwaps.forEach((s, i) => {
if (s.typeName === 'Unknown') s.type = SwapType.LOOP_IN;
if (i === 0) s.state = SwapState.INVOICE_SETTLED;
});
return (
<Layout>
<HistoryPage />
</Layout>
);
};
2 changes: 1 addition & 1 deletion app/src/__stories__/Layout.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import LoopPage from 'components/loop/LoopPage';
import { Layout } from '../components/layout';

export default {
title: 'Layout',
title: 'Components/Layout',
component: Layout,
};

Expand Down
2 changes: 1 addition & 1 deletion app/src/__stories__/LoopPage.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Layout } from 'components/layout';
import LoopPage from 'components/loop/LoopPage';

export default {
title: 'Loop Page',
title: 'Pages/Loop',
component: LoopPage,
parameters: { contained: true },
};
Expand Down
14 changes: 10 additions & 4 deletions app/src/__tests__/App.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import React from 'react';
import { render } from '@testing-library/react';
import App from '../App';

it('renders the App', () => {
const { getByText } = render(<App />);
const linkElement = getByText('Node Status');
expect(linkElement).toBeInTheDocument();
describe('App Component', () => {
const renderApp = () => {
return render(<App />);
};

it('should render the App', () => {
const { getByText } = renderApp();
const linkElement = getByText('Node Status');
expect(linkElement).toBeInTheDocument();
});
});
22 changes: 22 additions & 0 deletions app/src/__tests__/Pages.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { renderWithProviders } from 'util/tests';
import Pages from 'components/Pages';

describe('Pages Component', () => {
const render = () => {
return renderWithProviders(<Pages />);
};

it('should display the Loop page by default', () => {
const { getByText, store } = render();
expect(getByText('Lightning Loop')).toBeInTheDocument();
expect(store.uiStore.page).toBe('loop');
});

it('should display the History page', () => {
const { getByText, store } = render();
store.uiStore.goToHistory();
expect(getByText('Loop History')).toBeInTheDocument();
expect(store.uiStore.page).toBe('history');
});
});
53 changes: 53 additions & 0 deletions app/src/__tests__/components/history/HistoryPage.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import { fireEvent } from '@testing-library/react';
import { renderWithProviders } from 'util/tests';
import { createStore, Store } from 'store';
import HistoryPage from 'components/history/HistoryPage';

describe('HistoryPage', () => {
let store: Store;

beforeEach(() => {
store = createStore();
store.uiStore.goToHistory();
});

const render = () => {
return renderWithProviders(<HistoryPage />, store);
};

it('should display the title', () => {
const { getByText } = render();
expect(getByText('Loop History')).toBeInTheDocument();
});

it('should display the back link', () => {
const { getByText } = render();
expect(getByText('Lightning Loop')).toBeInTheDocument();
});

it('should display the back icon', () => {
const { getByText } = render();
expect(getByText('arrow-left.svg')).toBeInTheDocument();
});

it('should display the export icon', () => {
const { getByText } = render();
expect(getByText('download.svg')).toBeInTheDocument();
});

it('should display the table headers', () => {
const { getByText } = render();
expect(getByText('Status')).toBeInTheDocument();
expect(getByText('Loop Type')).toBeInTheDocument();
expect(getByText('Amount (sats)')).toBeInTheDocument();
expect(getByText('Created')).toBeInTheDocument();
expect(getByText('Updated')).toBeInTheDocument();
});

it('should navigate back to the Loop Page', () => {
const { getByText } = render();
fireEvent.click(getByText('arrow-left.svg'));
expect(store.uiStore.page).toEqual('loop');
});
});
37 changes: 37 additions & 0 deletions app/src/__tests__/components/history/HistoryRow.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { renderWithProviders } from 'util/tests';
import { loopListSwaps } from 'util/tests/sampleData';
import { Swap } from 'store/models';
import HistoryRow from 'components/history/HistoryRow';

describe('HistoryRow component', () => {
let swap: Swap;

beforeEach(async () => {
swap = new Swap(loopListSwaps.swapsList[0]);
});

const render = () => {
return renderWithProviders(<HistoryRow swap={swap} />);
};

it('should display the status', () => {
const { getByText } = render();
expect(getByText(swap.stateLabel)).toBeInTheDocument();
});

it('should display the type', () => {
const { getByText } = render();
expect(getByText(swap.typeName)).toBeInTheDocument();
});

it('should display the created date', () => {
const { getByText } = render();
expect(getByText(swap.createdOnLabel)).toBeInTheDocument();
});

it('should display the updated date', () => {
const { getByText } = render();
expect(getByText(swap.updatedOnLabel)).toBeInTheDocument();
});
});
19 changes: 19 additions & 0 deletions app/src/__tests__/components/layout/Layout.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,23 @@ describe('Layout component', () => {
fireEvent.click(getByTitle('menu'));
expect(store.settingsStore.sidebarVisible).toBe(true);
});

it('should navigate to the History page', () => {
const { getByText, store } = render();
expect(store.uiStore.page).toBe('loop');
fireEvent.click(getByText('History'));
expect(store.uiStore.page).toBe('history');
expect(getByText('History').parentElement).toHaveClass('active');
});

it('should navigate back to the Loop page', () => {
const { getByText, store } = render();
expect(store.uiStore.page).toBe('loop');
fireEvent.click(getByText('History'));
expect(store.uiStore.page).toBe('history');
expect(getByText('History').parentElement).toHaveClass('active');
fireEvent.click(getByText('Lightning Loop'));
expect(store.uiStore.page).toBe('loop');
expect(getByText('Lightning Loop').parentElement).toHaveClass('active');
});
});
1 change: 1 addition & 0 deletions app/src/assets/icons/clock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/src/assets/icons/download.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions app/src/components/Pages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import { observer } from 'mobx-react-lite';
import { useStore } from 'store';
import HistoryPage from './history/HistoryPage';
import LoopPage from './loop/LoopPage';

const Pages: React.FC = () => {
const { uiStore } = useStore();

switch (uiStore.page) {
case 'history':
return <HistoryPage />;
default:
return <LoopPage />;
}
};

export default observer(Pages);
79 changes: 79 additions & 0 deletions app/src/components/common/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from 'react';
import { observer } from 'mobx-react-lite';
import { styled } from 'components/theme';
import { ArrowLeft, Icon } from './icons';
import { PageTitle } from './text';

const Styled = {
Wrapper: styled.div`
display: flex;
justify-content: space-between;
`,
Left: styled.span`
flex: 1;
text-align: left;
`,
Center: styled.span`
flex: 1;
text-align: center;
`,
Right: styled.span`
flex: 1;
text-align: right;
`,
BackLink: styled.a`
text-transform: uppercase;
font-size: ${props => props.theme.sizes.s};
cursor: pointer;
color: ${props => props.theme.colors.whitish};

&:hover {
opacity: 80%;
}
`,
BackIcon: styled(ArrowLeft)`
margin-right: 5px;
`,
ActionIcon: styled(Icon)`
margin-left: 50px;
`,
};

interface Props {
title: string;
onBackClick?: () => void;
backText?: string;
onHistoryClick?: () => void;
onExportClick?: () => void;
}

const PageHeader: React.FC<Props> = ({
title,
onBackClick,
backText,
onHistoryClick,
onExportClick,
}) => {
const { Wrapper, Left, Center, Right, BackLink, BackIcon, ActionIcon } = Styled;
return (
<Wrapper>
<Left>
{onBackClick && (
<BackLink onClick={onBackClick}>
<BackIcon />
{backText}
</BackLink>
)}
</Left>
<Center>
<PageTitle>{title}</PageTitle>
</Center>
<Right>
{onHistoryClick && <ActionIcon icon="clock" onClick={onHistoryClick} />}
{onExportClick && <ActionIcon icon="download" onClick={onExportClick} />}
</Right>
</Wrapper>
);
};

export default observer(PageHeader);
17 changes: 17 additions & 0 deletions app/src/components/common/base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ export const Button = styled.button<ButtonProps>`
}
`;

/**
* the react-virtualized list doesn't play nice with the bootstrap row -15px
* margin. We need to manually offset the container and remove the
* padding from the last column to get the alignment correct
*/
export const ListContainer = styled.div`
margin-right: -15px;

.col:last-child {
padding-right: 0;
}

*:focus {
outline: none;
}
`;

/**
* the input[type=range] element. Vendor-specific rules for pseudo
* elements cannot be mixed. As such, there are no shared styles for focus or
Expand Down
Loading