Skip to content

Commit

Permalink
Merge pull request #150 from leinelissen/providers-ui
Browse files Browse the repository at this point in the history
Providers ui
  • Loading branch information
leinelissen authored Nov 2, 2020
2 parents f9e5ac0 + 2e576d8 commit b4cfdad
Show file tree
Hide file tree
Showing 16 changed files with 394 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/app/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const LinkButton = styled.button`
padding: 0;
`;

export const GhostButton = styled(LinkButton)`
export const GhostButton = styled<Pick>(LinkButton)`
color: black;
opacity: 0.3;
font-size: 14px;
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ export default function Menu(): JSX.Element {
<span className="icon"><FontAwesomeIcon icon={faClock} fixedWidth /></span>
<span>Timeline</span>
</Link>
{/* <Link to="/requests" activeClassName="active">
<Link to="/requests" activeClassName="active">
<span className="icon"><FontAwesomeIcon icon={faSync} fixedWidth /></span>
<span>Requests</span>
</Link> */}
</Link>
<Link to="/data" activeClassName="active">
<span className="icon"><FontAwesomeIcon icon={faTable} fixedWidth /></span>
<span>Data</span>
Expand Down
116 changes: 105 additions & 11 deletions src/app/components/PanelGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import React, { PropsWithChildren } from 'react';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import theme from 'app/styles/theme';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import styled, { css } from 'styled-components';
import { faChevronRight } from 'app/assets/fa-light';
import { PullRight } from './Utility';

export const ListItem = styled.div`
padding: 8px 32px;
Expand All @@ -9,39 +15,127 @@ export const ListItem = styled.div`

export const RowHeading = styled(ListItem)`
border-bottom: 1px solid ${theme.colors.border};
text-transform: uppercase;
font-weight: 400;
font-size: 12px;
letter-spacing: 0.5px;
position: sticky;
top: 0;
align-self: flex-start;
z-index: 2;
font-size: 14px;
width: 100%;
background-color: ${theme.colors.grey.light};
`;

export const SubHeading = styled(RowHeading)`
font-size: 10px;
font-family: 'IBM Plex Mono';
text-transform: uppercase;
color: ${theme.colors.grey.dark};
letter-spacing: 0.3px;
`;


export const PanelGrid = styled.div`
export const PanelGrid = styled.div<{ columns?: number; noTopPadding?: boolean; }>`
display: grid;
grid-auto-columns: auto;
grid-template-columns: 1fr 1fr 1fr;
padding-top: 40px;
grid-template-columns: repeat(${props => props.columns || 3}, 1fr);
padding-top: ${props => props.noTopPadding ? 0 : 40}px;
height: 100%;
position: relative;
overflow: hidden;
`;

export const List = styled.div`
export const List = styled.div<{ topMargin?: boolean }>`
display: flex;
flex-direction: column;
border-right: 1px solid ${theme.colors.border};
flex-grow: 1;
overflow-y: auto;
position: relative;
`;
${props => props.topMargin && css`
margin-top: 40px;
`}
`;

const IconWrapper = styled.div`
margin: 0 8px;
`;

type ListButtonProps = {
active?: boolean;
disabled?: boolean;
deleted?: boolean;
modified?: boolean;
added?: boolean;
large?: boolean;
};

export const NavigatableListEntryContainer = styled<React.FC<ListButtonProps>>(Link)`
border: 0;
background: transparent;
display: flex;
align-items: center;
font-size: 14px;
margin: 0;
padding: 14px 24px;
font-weight: 400;
color: ${theme.colors.black};
img {
max-height: 100px;
width: auto;
border-radius: 5px;
}
${props => props.active ? css`
background: ${theme.colors.grey.medium};
` : css`
&:hover {
background: ${theme.colors.grey.medium}BB;
opacity: 0.8;
}
`}
${props => props.added && css`
background-color: ${theme.colors.green}${props.active ? 33 : 22};;
`}
${props => props.deleted && css`
background-color: ${theme.colors.red}${props.active ? 33 : 22};;
`}
${props => props.modified && css`
background-color: ${theme.colors.yellow}${props.active ? 33 : 22};
`}
${props => props.large && css`
font-size: 16px;
`}
&:disabled {
opacity: 0.25;
}
`;

type NavigatableListEntryProps = PropsWithChildren<{
to: string,
icon?: IconProp,
} & ListButtonProps>;

export function NavigatableListEntry({
icon,
children,
...props
}: NavigatableListEntryProps): JSX.Element {
return (
<NavigatableListEntryContainer {...props}>
{icon ?
<IconWrapper>
<FontAwesomeIcon fixedWidth icon={icon} />
</IconWrapper>
: null}
{children}
<PullRight>
<FontAwesomeIcon fixedWidth icon={faChevronRight} />
</PullRight>
</NavigatableListEntryContainer>
)
}
26 changes: 14 additions & 12 deletions src/app/components/RightSideOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ import { faChevronRight } from 'app/assets/fa-light';
export interface RightSideOverlayProps {
children: JSX.Element;
onClose?: () => void;
columnPosition: number;
}

const Container = styled.div<Pick<RightSideOverlayProps, 'columnPosition'>>`
const Container = styled.div`
position: absolute;
z-index: 2;
height: 100%;
width: ${props => 100 / props.columnPosition}%;
width: 100%;
max-width: 500px;
right: 0;
top: 0;
padding-top: 40px;
`;

const InnerContainer = styled.div`
Expand All @@ -30,12 +29,12 @@ const InnerContainer = styled.div`
overflow-y: auto;
max-height: calc(100% - 20px);
background-color: white;
box-shadow: 0 -1px 1px rgba(0,0,0,0.01),
0 -2px 2px rgba(0,0,0,0.01),
0 -4px 4px rgba(0,0,0,0.01),
0 -8px 8px rgba(0,0,0,0.01),
0 -16px 16px rgba(0,0,0,0.01),
0 -32px 32px rgba(0,0,0,0.01);
box-shadow: 0 1px 1px rgba(0,0,0,0.01),
0 2px 2px rgba(0,0,0,0.01),
0 4px 4px rgba(0,0,0,0.01),
0 8px 8px rgba(0,0,0,0.01),
0 16px 16px rgba(0,0,0,0.01),
0 32px 32px rgba(0,0,0,0.01);
`;

export const CloseButton = styled(GhostButton)`
Expand All @@ -48,6 +47,10 @@ export const Section = styled.div<{ smallPadding?: boolean}>`
border-bottom: 1px solid #eee;
padding: ${props => props.smallPadding ? 15: 25}px;
p:first-child {
margin-top: 0;
}
img {
max-width: 100%;
height: auto;
Expand All @@ -67,7 +70,6 @@ const RightSideOverlay = (props: RightSideOverlayProps): JSX.Element => {
const {
onClose: handleClose,
children,
columnPosition
} = props;

return (
Expand All @@ -77,7 +79,7 @@ const RightSideOverlay = (props: RightSideOverlayProps): JSX.Element => {
>
{children => children &&
(props =>
<Container style={props} columnPosition={columnPosition}>
<Container style={props}>
<InnerContainer>
{handleClose ?
<CloseButton onClick={handleClose}>
Expand Down
14 changes: 8 additions & 6 deletions src/app/screens/Data/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class Data extends Component<Props, State> {
return (
<PanelGrid>
<List>
<RowHeading>CATEGORIES</RowHeading>
<RowHeading>Categories</RowHeading>
{Object.values(ProvidedDataTypes).map((key) => (
<ClickableCategory
key={key}
Expand All @@ -140,7 +140,7 @@ class Data extends Component<Props, State> {
))}
</List>
<List>
<RowHeading>DATA POINTS</RowHeading>
<RowHeading>Data Points</RowHeading>
{category && groupedData[category].map((datum, index) => (
<ClickableDataPoint
type={category as ProvidedDataTypes}
Expand All @@ -154,10 +154,12 @@ class Data extends Component<Props, State> {
/>
))}
</List>
<DatumOverlay
datum={groupedData[category]?.[parsedDatumId]}
onDelete={this.deleteDatum}
/>
<List>
<DatumOverlay
datum={groupedData[category]?.[parsedDatumId]}
onDelete={this.deleteDatum}
/>
</List>
<CreateNewCommit isModalOpen={false} groupedData={groupedData} deletedData={deletedData} />
<TutorialOverlay />
</PanelGrid>
Expand Down
94 changes: 94 additions & 0 deletions src/app/screens/Requests/components/ProviderOverlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCheck, faClock, faPlus, faQuestion, faSync } from 'app/assets/fa-light';
import Button from 'app/components/Button';
import RightSideOverlay, { Section } from 'app/components/RightSideOverlay';
import { H2 } from 'app/components/Typography';
import Providers from 'app/utilities/Providers';
import { formatDistanceToNow } from 'date-fns';
import { DataRequestStatus } from 'main/providers/types';
import React, { useCallback } from 'react';

interface Props {
selectedProvider: string;
status?: DataRequestStatus;
}

function ProviderOverlay({ selectedProvider, status }: Props): JSX.Element {
const handleNewRequest = useCallback(() => {
Providers.dispatchDataRequest(selectedProvider);
}, [selectedProvider]);

return (
<RightSideOverlay>
{selectedProvider && (
<>
<Section>
<H2>
<FontAwesomeIcon
icon={Providers.getIcon(selectedProvider)}
style={{ marginRight: 8 }}
/>
{selectedProvider}
</H2>
</Section>
<Section>
<span>
<FontAwesomeIcon
icon={faQuestion}
style={{ marginRight: 8 }}
fixedWidth
/>
Data requested: <i>{status?.dispatched ? formatDistanceToNow(status.dispatched) + ' ago' : 'never'}</i>
<br />
<FontAwesomeIcon
icon={faClock}
style={{ marginRight: 8 }}
fixedWidth
/>
Last check: <i>{status?.lastCheck ? formatDistanceToNow(status.lastCheck) + ' ago' : 'never'}</i>
{status?.completed &&
<>
<br />
<FontAwesomeIcon
icon={faCheck}
style={{ marginRight: 8 }}
fixedWidth
/>
Completed: <i>{formatDistanceToNow(status?.completed)} ago</i>
</>
}
</span>
</Section>
{status?.dispatched ?
<Section>
<p>The data request you issued has not been completed yet. We&apos;ll let you know as soon as it&apos;s completed.</p>
<Button
fullWidth
icon={faCheck}
onClick={handleNewRequest}
disabled
>
Complete Data Request
</Button>
</Section>
:
<Section>
<p>If you would like to retrieve your data, use the button below to start a new data request.</p>
<p><i>Note: you may be asked to confirm your password</i></p>
<Button
fullWidth
icon={faPlus}
onClick={handleNewRequest}
disabled={!!status?.dispatched}
>
Start Data Request
</Button>
</Section>
}
</>
)}
</RightSideOverlay>
);
}

export default ProviderOverlay;
17 changes: 17 additions & 0 deletions src/app/screens/Requests/getDescription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { formatDistanceToNow } from 'date-fns';
import { DataRequestStatus } from 'main/providers/types';

/**
* A helper to convert a particular DataRequestStatus to a human-readable string
*/
export default function getDescription(status?: DataRequestStatus): string {
if (status?.completed) {
return `Received data ${formatDistanceToNow(status.completed)} ago`;
}

if (status?.dispatched) {
return `Requested data ${formatDistanceToNow(status.dispatched)} ago`;
}

return 'No data requested yet';
}
Loading

0 comments on commit b4cfdad

Please sign in to comment.