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

fix: 2285 - Improve design of the result header #2319

Merged
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
20 changes: 16 additions & 4 deletions src/components/CohortBuilder/Results.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,23 @@
border-left: 1px solid #a9adc0;
}

.cb-summary-entity:last-child {
padding: 0 0 0 10px;
}

.cb-summary-files {
display: grid;
grid-template-columns: auto auto;
}

.cb-detail {
align-items: center;
flex: 2;
align-items: baseline;
align-content: space-between;
justify-content: flex-end;
}

.cb-detail > :first-child {
margin-right: 10px;
}

.cb-view-links > div:not(:last-child) {
Expand All @@ -42,11 +51,14 @@
font-weight: 600;
font-family: Montserrat, sans-serif;
font-size: 16px;
padding: 0 3px;
margin: 0;
color: #2b388f;
}

.cb-sub-heading :first-child {
margin-right: 10px;
}

.cb-purple-link {
color: #a6278f;
}
Expand Down Expand Up @@ -77,4 +89,4 @@
font-size: 14px;
font-family: Montserrat, sans-serif;
height: 50px;
}
}
280 changes: 137 additions & 143 deletions src/components/CohortBuilder/Results.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,43 @@
import React from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import gql from 'graphql-tag';
import { compose } from 'recompose';
import isEmpty from 'lodash/isEmpty';
import get from 'lodash/get';
import { injectState } from 'freactal';
import saveSet from '@kfarranger/components/dist/utils/saveSet';

import ContentBar from './ContentBar';
import Summary from './Summary';
import Row from 'uikit/Row';
import ViewLink from 'uikit/ViewLink';
import { H2 } from 'uikit/Headings';
import ParticipantsTableView from './ParticipantsTableView';
import LoadingSpinner from 'uikit/LoadingSpinner';
import LinkWithLoader from 'uikit/LinkWithLoader';

import SummaryIcon from 'icons/AllAppsMenuIcon';
import TableViewIcon from 'icons/TableViewIcon';
import DemographicIcon from 'icons/DemographicIcon';
import FilesIcon from 'icons/FilesIcon';
import familyMembers from 'assets/icon-families-grey.svg';

import { withApi } from 'services/api';
import graphql from 'services/arranger';

import TableErrorView from './ParticipantsTableView/TableErrorView';
import ParticipantsTableView from './ParticipantsTableView';
import QueriesResolver from './QueriesResolver';
import LoadingSpinner from 'uikit/LoadingSpinner';
import EmptyCohortOverlay from './EmptyCohortOverlay';
import LinkWithLoader from 'uikit/LinkWithLoader';
import { createFileRepoLink } from './util';
import { injectState } from 'freactal';
import saveSet from '@kfarranger/components/dist/utils/saveSet';
import graphql from 'services/arranger';
import FilesIcon from 'icons/FilesIcon';
import familyMembers from 'assets/icon-families-grey.svg';
import ContentBar from './ContentBar';
import Summary from './Summary';
import { setActiveView } from './actionCreators';

import { styleComponent } from 'components/Utils';

import './Results.css';

const SUMMARY = 'summary';
const TABLE = 'table';

const PurpleLinkWithLoader = styleComponent(LinkWithLoader, 'cb-purple-link cb-sub-heading');
const PurpleLink = styleComponent(Link, 'cb-purple-link cb-sub-heading');

const generateAllFilesLink = async (user, api, files) => {
const sqon = {
op: 'and',
Expand Down Expand Up @@ -120,139 +118,135 @@ const cohortResultsQuery = sqon => ({
},
});

class Results extends React.Component {
static propTypes = {
activeSqonIndex: PropTypes.number.isRequired,
sqon: PropTypes.object,
onRemoveFromCohort: PropTypes.func.isRequired,
setActiveView: PropTypes.func.isRequired,
activeView: PropTypes.string.isRequired,
};

render() {
const {
activeView,
activeSqonIndex,
setActiveView,
sqon = { op: 'and', content: [] },
api,
state,
onRemoveFromCohort,
} = this.props;

return (
<QueriesResolver name="GQL_RESULT_QUERIES" api={api} queries={[cohortResultsQuery(sqon)]}>
{({ isLoading, data, error }) => {
const resultsData = data[0];
const participantCount = get(resultsData, 'participantCount', null);
const familiesCount = get(resultsData, 'familiesCount', null);
const cohortIsEmpty = (!isLoading && !resultsData) || participantCount === 0;
const Results = ({
activeView,
activeSqonIndex,
setActiveView,
sqon = { op: 'and', content: [] },
api,
state,
onRemoveFromCohort,
}) => (
<QueriesResolver name="GQL_RESULT_QUERIES" api={api} queries={[cohortResultsQuery(sqon)]}>
{({ isLoading, data, error }) => {
const resultsData = data[0];
const participantCount = get(resultsData, 'participantCount', null);
const familiesCount = get(resultsData, 'familiesCount', null);
const cohortIsEmpty = (!isLoading && !resultsData) || participantCount === 0;

const filesCountHeading = resultsData
? `${Number(data[0].filesCount || 0).toLocaleString()}`
: '';
const filesCountHeading = resultsData
? `${Number(data[0].filesCount || 0).toLocaleString()}`
: '';

const hasNoFile = resultsData ? data[0].filesCount === 0 : true;
const hasNoFile = resultsData ? data[0].filesCount === 0 : true;

return error ? (
<TableErrorView error={error} />
) : (
<React.Fragment>
<ContentBar style={{ padding: '0 30px 0 34px' }}>
<Row className="cb-detail">
<div style={{ display: 'flex', marginRight: '14px' }}>
{isEmpty(sqon.content) ? (
<H2>All Data</H2>
) : (
<React.Fragment>
<H2>Cohort Results</H2>
<h3 className="cb-sub-heading" style={{ fontWeight: 'normal' }}>
for Query {activeSqonIndex + 1}
</h3>
</React.Fragment>
)}
</div>{' '}
{isLoading ? (
<LoadingSpinner />
) : (
<div className="cb-summary">
<div className="cb-summary-entity">
<h3 className="cb-sub-heading">
<DemographicIcon width="14px" height="17px" />
{Number(participantCount || 0).toLocaleString()}{' '}
{participantCount === 1 ? 'Participant' : 'Participants'}
</h3>
</div>
<div className="cb-summary-entity">
<h3 className="cb-sub-heading">
<img src={familyMembers} alt="" height="13px" />{' '}
{Number(familiesCount || 0).toLocaleString()}{' '}
{familiesCount === 1 ? 'Family' : 'Families'}
</h3>
</div>
<div className="cb-summary-entity">
<h3 className="cb-sub-heading">
<div className="cb-summary-files">
{hasNoFile ? (
<div>
<FilesIcon style={{ marginRight: '6px' }} /> {'0 File'}
</div>
) : (
<React.Fragment>
<div>
<FilesIcon />
{isEmpty(sqon.content) ? (
<PurpleLink to="/search/file">{filesCountHeading} </PurpleLink>
) : (
<PurpleLinkWithLoader
replaceText={false}
getLink={() =>
generateAllFilesLink(state.loggedInUser, api, data[0].files)
}
>
{filesCountHeading}
</PurpleLinkWithLoader>
)}
</div>
<div>Files</div>
</React.Fragment>
)}
return error ? (
<TableErrorView error={error} />
) : (
<Fragment>
<ContentBar style={{ padding: '0 30px 0 34px' }}>
<Row className="cb-view-links">
<ViewLink
onClick={() => setActiveView(SUMMARY)}
active={activeView === SUMMARY}
Icon={SummaryIcon}
>
Summary View
</ViewLink>
<ViewLink
onClick={() => setActiveView(TABLE)}
active={activeView === TABLE}
Icon={TableViewIcon}
>
Table View
</ViewLink>
</Row>
<Row className="cb-detail">
{isEmpty(sqon.content) ? (
<H2>All Data</H2>
) : (
<Fragment>
<H2>Cohort Results</H2>
<h3 className="cb-sub-heading" style={{ fontWeight: 'normal' }}>
for Query {activeSqonIndex + 1}
</h3>
</Fragment>
)}
{isLoading ? (
<LoadingSpinner />
) : (
<div className="cb-summary">
<div className="cb-summary-entity">
<h3 className="cb-sub-heading">
<DemographicIcon width="14px" height="17px" />
{`${Number(participantCount || 0).toLocaleString()} ${
participantCount === 1 ? 'Participant' : 'Participants'
}`}
</h3>
</div>
<div className="cb-summary-entity">
<h3 className="cb-sub-heading">
<img src={familyMembers} alt="" height="13px" />
{`${Number(familiesCount || 0).toLocaleString()} ${
familiesCount === 1 ? 'Family' : 'Families'
}`}
</h3>
</div>
<div className="cb-summary-entity">
<h3 className="cb-sub-heading">
<div className="cb-summary-files">
{hasNoFile ? (
<div>
<FilesIcon style={{ marginRight: '6px' }} /> {'0 File'}
</div>
</h3>
) : (
<Fragment>
<div>
<FilesIcon />
{isEmpty(sqon.content) ? (
<Link className="cb-purple-link cb-sub-heading" to="/search/file">
{filesCountHeading}{' '}
</Link>
) : (
<LinkWithLoader
className="cb-purple-link cb-sub-heading"
replaceText={false}
getLink={() =>
generateAllFilesLink(state.loggedInUser, api, data[0].files)
}
>
{filesCountHeading}
</LinkWithLoader>
)}
</div>
<div>Files</div>
</Fragment>
)}
</div>
</div>
)}
</Row>
</h3>
</div>
</div>
)}
</Row>
</ContentBar>
<div className={`cb-active-view ${activeView}`}>
<Summary sqon={sqon} />
<ParticipantsTableView sqon={sqon} onRemoveFromCohort={onRemoveFromCohort} />
{cohortIsEmpty ? <EmptyCohortOverlay /> : null}
</div>
</Fragment>
);
}}
</QueriesResolver>
);

<Row className="cb-view-links">
<ViewLink
onClick={() => setActiveView(SUMMARY)}
active={activeView === SUMMARY}
Icon={SummaryIcon}
>
Summary View
</ViewLink>
<ViewLink
onClick={() => setActiveView(TABLE)}
active={activeView === TABLE}
Icon={TableViewIcon}
>
Table View
</ViewLink>
</Row>
</ContentBar>
<div className={`cb-active-view ${activeView}`}>
<Summary sqon={sqon} />
<ParticipantsTableView sqon={sqon} onRemoveFromCohort={onRemoveFromCohort} />
{cohortIsEmpty ? <EmptyCohortOverlay /> : null}
</div>
</React.Fragment>
);
}}
</QueriesResolver>
);
}
}
Results.propTypes = {
activeSqonIndex: PropTypes.number.isRequired,
sqon: PropTypes.object,
onRemoveFromCohort: PropTypes.func.isRequired,
setActiveView: PropTypes.func.isRequired,
activeView: PropTypes.string.isRequired,
};

const mapStateToProps = state => {
const { activeView } = state.ui.cohortBuilderPage;
Expand Down
11 changes: 2 additions & 9 deletions src/icons/DemographicIcon.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { BaseSvg } from 'icons';

export default ({
fill = '#a9adc0',
width = '14px',
height = '17px',
marginRight = '4px',
style = {},
...props
}) =>
export default ({ fill = '#a9adc0', width = '14px', height = '17px', style = {}, ...props }) =>
BaseSvg({
svg: `<svg id="Isolation_Mode" data-name="Isolation Mode" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 45.49"><defs><style>.cls-1{fill:${fill};fill-rule:evenodd;}</style></defs><title>icon-demographic</title><path class="cls-1" d="M11.24,31.52c0,4.77-2.78,11.06.23,13.57,2.32,1.93,4.63-3.48,6.94-7.45,2.64-4.53,4-3.57,9.5-4.07,12.8-1.17,10.17-4.61,3.77-5.68-2.38-.4-5.87-.92-7.48-4.43-1.53-3.32.1-6.47,2.65-10.09,3.46-4.9,4.45-7.72-3.12-3.42-7.8,4.44-8.22,5.58-16.41,1.29-11-5.76-7.65.1-2.63,5A21.67,21.67,0,0,1,11.24,31.52Z"/><path class="cls-1" d="M11.53,10.42c-1.91-2.1-1.57-6.64.56-8.58,2.72-2.47,5.12-2.19,6.61-.7C23.88,6.34,15.7,15,11.53,10.42Z"/></svg>`,
width,
height,
style: { ...style, marginRight },
style: { ...style },
...props,
});