import './StudyList.styl'; import React from 'react'; import classNames from 'classnames'; import TableSearchFilter from './TableSearchFilter.js'; import PropTypes from 'prop-types'; import { StudyListLoadingText } from './StudyListLoadingText.js'; import { useTranslation } from 'react-i18next'; const getContentFromUseMediaValue = ( displaySize, contentArrayMap, defaultContent ) => { const content = displaySize in contentArrayMap ? contentArrayMap[displaySize] : defaultContent; return content; }; /** * * * @param {*} props * @returns */ function StudyList(props) { const { isLoading, hasError, studies, sort, onSort: handleSort, filterValues, onFilterChange: handleFilterChange, onSelectItem: handleSelectItem, studyListDateFilterNumDays, displaySize, } = props; const { t, ready: translationsAreReady } = useTranslation('StudyList'); 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: `${t('Patient')} / ${t('MRN')}`, fieldName: 'patientNameOrId', inputType: 'text', size: 250, }, { displayText: t('Description'), fieldName: 'accessionOrModalityOrDescription', inputType: 'text', size: 350, }, { displayText: t('StudyDate'), fieldName: 'studyDate', inputType: 'date-range', size: 300, }, ]; const smallTableMeta = [ { displayText: t('Search'), fieldName: 'allFields', inputType: 'text', size: 100, }, ]; const tableMeta = getContentFromUseMediaValue( displaySize, { large: largeTableMeta, medium: mediumTableMeta, small: smallTableMeta }, smallTableMeta ); const totalSize = tableMeta .map(field => field.size) .reduce((prev, next) => prev + next); return translationsAreReady ? ( {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} displaySize={displaySize} /> ))}
{t('There was an error fetching studies')}
{t('No matching results')}
) : null; } 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, studyDateTo: PropTypes.any, studyDateFrom: PropTypes.any, }).isRequired, onFilterChange: PropTypes.func.isRequired, studyListDateFilterNumDays: PropTypes.number, displaySize: PropTypes.string, }; StudyList.defaultProps = {}; function TableRow(props) { const { accessionNumber, isHighlighted, modalities, patientId, patientName, studyDate, studyDescription, studyInstanceUid, onClick: handleClick, t, displaySize, } = props; const largeRowTemplate = ( handleClick(studyInstanceUid)} className={classNames({ active: isHighlighted })} > {patientName || `(${t('Empty')})`} {patientId} {accessionNumber} {studyDate} {modalities || `(${t('Empty')})`} {studyDescription} ); const mediumRowTemplate = ( handleClick(studyInstanceUid)} className={classNames({ active: isHighlighted })} > {patientName || `(${t('Empty')})`}
{patientId}
{/* DESCRIPTION */}
{studyDescription}
{/* MODALITY & ACCESSION */}
{modalities || `(${t('Empty')})`}
{accessionNumber}
{/* DATE */} {studyDate} ); const smallRowTemplate = ( handleClick(studyInstanceUid)} className={classNames({ active: isHighlighted })} >
{/* NAME AND ID */}
{patientName || `(${t('Empty')})`}
{patientId}
{/* DESCRIPTION */}
{studyDescription}
{/* MODALITY & DATE */}
{modalities || `(${t('Empty')})`}
{studyDate}
); const rowTemplate = getContentFromUseMediaValue( displaySize, { large: largeRowTemplate, medium: mediumRowTemplate, small: smallRowTemplate, }, smallRowTemplate ); return rowTemplate; } TableRow.propTypes = { accessionNumber: PropTypes.string.isRequired, isHighlighted: PropTypes.bool, modalities: PropTypes.string, patientId: PropTypes.string.isRequired, patientName: PropTypes.string.isRequired, studyDate: PropTypes.string.isRequired, studyDescription: PropTypes.string.isRequired, studyInstanceUid: PropTypes.string.isRequired, displaySize: PropTypes.string, }; TableRow.defaultProps = { isHighlighted: false, }; export { StudyList };