import './StudyList.styl'; import React from 'react'; import classNames from 'classnames'; import TableSearchFilter from './TableSearchFilter.js'; import useMedia from '../../hooks/useMedia.js'; import PropTypes from 'prop-types'; import ColorHash from './internal/color-hash.js'; import { StudyListLoadingText } from './StudyListLoadingText.js'; import { withTranslation } from '../../utils/LanguageProvider'; const colorHash = new ColorHash(); /** * * * @param {*} props * @returns */ function StudyList(props) { const { isLoading, hasError, studies, sort, onSort: handleSort, filterValues, onFilterChange: handleFilterChange, onSelectItem: handleSelectItem, t, // studyListDateFilterNumDays, } = props; const largeTableMeta = [ { displayText: t('PatientName'), fieldName: 'patientName', inputType: 'text', size: 330, }, { displayText: t('MRN'), fieldName: 'patientId', inputType: 'text', size: 378, }, { displayText: t('AccessionNumber'), fieldName: 'accessionNumber', inputType: 'text', size: 180, }, { displayText: t('StudyDate'), fieldName: 'studyDate', inputType: 'date-range', size: 300, }, { displayText: t('Modality'), fieldName: 'modalities', inputType: 'text', size: 114, }, { displayText: t('StudyDescription'), fieldName: 'studyDescription', inputType: 'text', size: 335, }, ]; const mediumTableMeta = [ { displayText: 'Patient / MRN', fieldName: 'patientNameOrId', inputType: 'text', size: 250, }, { displayText: 'Description', fieldName: 'accessionOrModalityOrDescription', inputType: 'text', size: 350, }, { displayText: t('StudyDate'), fieldName: 'studyDate', inputType: 'date-range', size: 300, }, ]; const smallTableMeta = [ { displayText: 'Search', fieldName: 'allFields', inputType: 'text', size: 100, }, ]; const tableMeta = useMedia( ['(min-width: 1750px)', '(min-width: 1000px)', '(min-width: 768px)'], [largeTableMeta, mediumTableMeta, smallTableMeta], smallTableMeta ); const totalSize = tableMeta .map(field => field.size) .reduce((prev, next) => prev + next); return ( {tableMeta.map((field, i) => { const size = field.size; const percentWidth = (size / totalSize) * 100.0; return ; })} {/* I'm not in love with this approach, but it's the quickest way for now * * - Display different content based on loading, empty, results state * * This is not ideal because it create a jump in focus. For loading especially, * We should keep our current results visible while we load the new ones. */} {/* LOADING */} {isLoading && ( )} {!isLoading && hasError && ( )} {/* EMPTY */} {!isLoading && !studies.length && ( )} {!isLoading && studies.map((study, index) => ( handleSelectItem(studyInstanceUid)} accessionNumber={study.accessionNumber || ''} modalities={study.modalities} patientId={study.patientId || ''} patientName={study.patientName || ''} studyDate={study.studyDate} studyDescription={study.studyDescription || ''} studyInstanceUid={study.studyInstanceUid} t={t} /> ))}
{t('There was an error fetching studies')}
{t('No matching results')}
); } StudyList.propTypes = { isLoading: PropTypes.bool.isRequired, hasError: PropTypes.bool.isRequired, studies: PropTypes.array.isRequired, onSelectItem: PropTypes.func.isRequired, // ~~ SORT sort: PropTypes.shape({ fieldName: PropTypes.string, direction: PropTypes.oneOf(['desc', 'asc', null]), }).isRequired, onSort: PropTypes.func.isRequired, // ~~ FILTERS filterValues: PropTypes.shape({ patientName: PropTypes.string.isRequired, patientId: PropTypes.string.isRequired, accessionNumber: PropTypes.string.isRequired, studyDate: PropTypes.string.isRequired, modalities: PropTypes.string.isRequired, studyDescription: PropTypes.string.isRequired, patientNameOrId: PropTypes.string.isRequired, accessionOrModalityOrDescription: PropTypes.string.isRequired, allFields: PropTypes.string.isRequired, }).isRequired, onFilterChange: PropTypes.func.isRequired, // studyListDateFilterNumDays: PropTypes.number, }; StudyList.defaultProps = {}; function TableRow(props) { const { accessionNumber, isHighlighted, modalities, patientId, patientName, studyDate, studyDescription, studyInstanceUid, onClick: handleClick, t, } = props; const largeRowTemplate = ( handleClick(studyInstanceUid)} className={classNames({ active: isHighlighted })} > {patientName || `(${t('Empty')})`} {patientId} {accessionNumber} {studyDate} {modalities} {studyDescription} ); const mediumRowTemplate = ( handleClick(studyInstanceUid)} className={classNames({ active: isHighlighted })} > {patientName || `(${t('Empty')})`}
{patientId}
{/* DESCRIPTION */}
{studyDescription}
{/* MODALITY & ACCESSION */}
{modalities}
{accessionNumber}
{/* DATE */} {studyDate} ); const smallRowTemplate = ( handleClick(studyInstanceUid)} className={classNames({ active: isHighlighted })} >
{/* NAME AND ID */}
{patientName || `(${t('Empty')})`}
{patientId}
{/* DESCRIPTION */}
{studyDescription}
{/* MODALITY & DATE */}
{modalities}
{studyDate}
); const rowTemplate = useMedia( ['(min-width: 1750px)', '(min-width: 1000px)', '(min-width: 768px)'], [largeRowTemplate, mediumRowTemplate, smallRowTemplate], smallRowTemplate ); return rowTemplate; } TableRow.propTypes = { accessionNumber: PropTypes.string.isRequired, isHighlighted: PropTypes.bool, modalities: PropTypes.string.isRequired, patientId: PropTypes.string.isRequired, patientName: PropTypes.string.isRequired, studyDate: PropTypes.string.isRequired, studyDescription: PropTypes.string.isRequired, studyInstanceUid: PropTypes.string.isRequired, }; TableRow.defaultProps = { isHighlighted: false, }; const connectedComponent = withTranslation('StudyList')(StudyList); export { connectedComponent as StudyList };