Skip to content

Commit

Permalink
refactor: ♻️ forward charts
Browse files Browse the repository at this point in the history
  • Loading branch information
apotdevin committed Nov 15, 2020
1 parent 05fd6b2 commit eb99622
Show file tree
Hide file tree
Showing 6 changed files with 478 additions and 164 deletions.
97 changes: 46 additions & 51 deletions pages/forwards.tsx
Original file line number Diff line number Diff line change
@@ -1,96 +1,91 @@
import React, { useState } from 'react';
import { toast } from 'react-toastify';
import { GridWrapper } from 'src/components/gridWrapper/GridWrapper';
import { Forward } from 'src/graphql/types';
import { NextPageContext } from 'next';
import { getProps } from 'src/utils/ssr';
import { useGetForwardsPastDaysQuery } from 'src/graphql/queries/__generated__/getForwardsPastDays.generated';
import {
MultiButton,
SingleButton,
} from 'src/components/buttons/multiButton/MultiButton';
import { ForwardsList } from 'src/views/forwards/index';
import {
ForwardProvider,
useForwardDispatch,
useForwardState,
} from 'src/views/forwards/context';
import {
ForwardReport,
ReportType,
} from 'src/views/home/reports/forwardReport/ForwardReport';
import { ForwardChannelsReport } from 'src/views/home/reports/forwardReport/ForwardChannelReport';
import {
SubTitle,
Card,
CardWithTitle,
CardTitle,
Separation,
SingleLine,
} from '../src/components/generic/Styled';
import { getErrorContent } from '../src/utils/error';
import { LoadingCard } from '../src/components/loading/LoadingCard';
import { ForwardCard } from '../src/views/forwards/ForwardsCard';
import { ForwardBox } from '../src/views/home/reports/forwardReport';

const ForwardsView = () => {
const [time, setTime] = useState<number>(30);
const [indexOpen, setIndexOpen] = useState(0);

const { loading, data } = useGetForwardsPastDaysQuery({
variables: { days: time },
onError: error => toast.error(getErrorContent(error)),
});

if (loading || !data || !data.getForwardsPastDays) {
return (
<>
<ForwardBox />
<LoadingCard title={'Forwards'} />
</>
);
}
const { days, infoType } = useForwardState();
const dispatch = useForwardDispatch();

const renderButton = (selectedTime: number, title: string) => (
<SingleButton
selected={selectedTime === time}
onClick={() => setTime(selectedTime)}
selected={selectedTime === days}
onClick={() => dispatch({ type: 'day', days: selectedTime })}
>
{title}
</SingleButton>
);

const renderNoForwards = () => (
<Card>
<p>{`Your node has not forwarded any payments in the past ${time} ${
time > 1 ? 'days' : 'day'
}.`}</p>
</Card>
const renderTypeButton = (type: ReportType, title: string) => (
<SingleButton
selected={infoType === type}
onClick={() => dispatch({ type: 'infoType', infoType: type })}
>
{title}
</SingleButton>
);

return (
<>
<ForwardBox />
<CardWithTitle>
<CardTitle>
<SubTitle>Forwards</SubTitle>
<MultiButton margin={'0 0 8px'}>
</CardTitle>
<SingleLine>
<MultiButton margin={'8px 0'}>
{renderButton(1, 'D')}
{renderButton(7, '1W')}
{renderButton(30, '1M')}
{renderButton(90, '3M')}
{renderButton(180, '6M')}
{renderButton(360, '1Y')}
</MultiButton>
</CardTitle>
{data?.getForwardsPastDays?.length ? (
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
{data?.getForwardsPastDays?.map((forward, index) => (
<ForwardCard
forward={forward as Forward}
key={index}
index={index + 1}
setIndexOpen={setIndexOpen}
indexOpen={indexOpen}
/>
))}
</Card>
) : (
renderNoForwards()
)}
<MultiButton margin={'8px 0'}>
{renderTypeButton('amount', 'Amount')}
{renderTypeButton('tokens', 'Tokens')}
{renderTypeButton('fee', 'Fees')}
</MultiButton>
</SingleLine>
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
<ForwardReport days={days} order={infoType} />
<Separation />
<ForwardChannelsReport days={days} order={infoType} />
</Card>
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
<ForwardsList days={days} />
</Card>
</CardWithTitle>
</>
);
};

const Wrapped = () => (
<GridWrapper>
<ForwardsView />
<ForwardProvider>
<ForwardsView />
</ForwardProvider>
</GridWrapper>
);

Expand Down
175 changes: 175 additions & 0 deletions src/components/table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { useMemo, useState } from 'react';
import styled, { css } from 'styled-components';
import {
useTable,
useSortBy,
useAsyncDebounce,
useGlobalFilter,
} from 'react-table';
import { separationColor } from 'src/styles/Themes';
import { Input } from '../input';

type StyledTableProps = {
withBorder?: boolean;
alignCenter?: boolean;
fontSize?: string;
};

const Styles = styled.div`
overflow-x: auto;
table {
border-spacing: 0;
tr {
:last-child {
td {
border-bottom: 0;
}
}
}
th,
td {
font-size: ${({ fontSize }: StyledTableProps) => fontSize || '14px'};
text-align: left;
margin: 0;
padding: 8px;
${({ withBorder }: StyledTableProps) =>
withBorder &&
css`
border-bottom: 1px solid ${separationColor};
`}
${({ alignCenter }: StyledTableProps) =>
alignCenter &&
css`
text-align: center;
padding: 8px;
`}
:last-child {
border-right: 0;
}
}
}
`;

const FilterLine = styled.div`
margin-bottom: 24px;
`;

const GlobalFilter = ({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
filterPlaceholder,
}: any) => {
const count = preGlobalFilteredRows.length;
const [value, setValue] = useState(globalFilter);
const onChange = useAsyncDebounce(value => {
setGlobalFilter(value || undefined);
}, 200);

return (
<FilterLine>
<Input
maxWidth={'300px'}
value={value || ''}
onChange={e => {
setValue(e.target.value);
onChange(e.target.value);
}}
placeholder={`Search ${count} ${filterPlaceholder || ''}`}
/>
</FilterLine>
);
};

type TableProps = {
tableData: any[];
tableColumns:
| { Header: string; accessor: string }[]
| { Header: string; columns: { Header: string; accessor: string }[] }[];
withBorder?: boolean;
fontSize?: string;
filterPlaceholder?: string;
notSortable?: boolean;
};

export const Table: React.FC<TableProps> = ({
tableData,
tableColumns,
withBorder,
fontSize,
filterPlaceholder,
notSortable,
}) => {
const data = useMemo(() => tableData, [tableData]);
const columns = useMemo(() => tableColumns, [tableColumns]);

const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
state,
preGlobalFilteredRows,
setGlobalFilter,
} = useTable(
{
columns,
data,
},
useGlobalFilter,
useSortBy
);

return (
<>
{!!filterPlaceholder && (
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
filterPlaceholder={filterPlaceholder}
/>
)}
<Styles withBorder={withBorder} fontSize={fontSize}>
<table {...getTableProps()} style={{ width: '100%' }}>
<thead>
{headerGroups.map((headerGroup, index) => (
<tr {...headerGroup.getHeaderGroupProps()} key={index}>
{headerGroup.headers.map((column, index) => (
<th
{...column.getHeaderProps(
notSortable ? undefined : column.getSortByToggleProps()
)}
key={index}
>
{column.render('Header')}
<span>
{column.isSorted ? (column.isSortedDesc ? '⬇' : '⬆') : ''}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, index) => {
prepareRow(row);
return (
<tr {...row.getRowProps()} key={index}>
{row.cells.map((cell, index) => {
return (
<td {...cell.getCellProps()} key={index}>
{cell.render('Cell')}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</Styles>
</>
);
};
67 changes: 67 additions & 0 deletions src/views/forwards/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { FC, createContext, useContext, useReducer } from 'react';

type ReportType = 'fee' | 'tokens' | 'amount';

type State = {
days: number;
infoType: ReportType;
};

type ActionType =
| {
type: 'day';
days: number;
}
| {
type: 'infoType';
infoType: ReportType;
};

type Dispatch = (action: ActionType) => void;

export const StateContext = createContext<State | undefined>(undefined);
export const DispatchContext = createContext<Dispatch | undefined>(undefined);

const initialState: State = {
days: 30,
infoType: 'amount',
};

const stateReducer = (state: State, action: ActionType): State => {
switch (action.type) {
case 'day':
return { ...state, days: action.days };
case 'infoType':
return { ...state, infoType: action.infoType };
default:
return state;
}
};

const ForwardProvider: FC = ({ children }) => {
const [state, dispatch] = useReducer(stateReducer, initialState);

return (
<DispatchContext.Provider value={dispatch}>
<StateContext.Provider value={state}>{children}</StateContext.Provider>
</DispatchContext.Provider>
);
};

const useForwardState = () => {
const context = useContext(StateContext);
if (context === undefined) {
throw new Error('useForwardState must be used within a ForwardProvider');
}
return context;
};

const useForwardDispatch = () => {
const context = useContext(DispatchContext);
if (context === undefined) {
throw new Error('useForwardDispatch must be used within a ForwardProvider');
}
return context;
};

export { ForwardProvider, useForwardState, useForwardDispatch };
Loading

0 comments on commit eb99622

Please sign in to comment.