import React, { useState, useRef, useEffect } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { Icon, ButtonGroup, Button, Tooltip, CinePlayer } from '../'; import useOnClickOutside from '../../utils/useOnClickOutside'; const classes = { infoHeader: 'text-base text-primary-light', infoText: 'text-base text-white max-w-24 truncate', firstRow: 'flex flex-col', row: 'flex flex-col ml-4', }; const ViewportActionBar = ({ studyData, showNavArrows, showCine, cineProps, showPatientInfo: patientInfoVisibility, onSeriesChange, onDoubleClick, }) => { const [showPatientInfo, setShowPatientInfo] = useState(patientInfoVisibility); // TODO -> Remake this component with a bunch of generic slots that can be filled, // Its not generic at all, isTracked etc shouldn't be parts of this component. // It shouldn't care that a tracking mode or SR exists. // Things like the right/left buttons should be made into smaller // Components you can compose. // OHIF-200 ticket. const { label, isTracked, isLocked, modality, studyDate, currentSeries, seriesDescription, patientInformation, } = studyData; const { patientName, patientSex, patientAge, MRN, thickness, spacing, scanner, } = patientInformation; const onPatientInfoClick = () => setShowPatientInfo(!showPatientInfo); const closePatientInfo = () => setShowPatientInfo(false); const showPatientInfoRef = useRef(null); const clickOutsideListener = useOnClickOutside( showPatientInfoRef, closePatientInfo ); useEffect(() => { if (showPatientInfo) { clickOutsideListener.add(); } else { clickOutsideListener.remove(); } return () => clickOutsideListener.remove(); }, [clickOutsideListener, showPatientInfo]); const renderIconStatus = () => { if (modality === 'SR') { const TooltipMessage = isLocked ? () => (
This SR is locked.
Measurements cannot be duplicated.
) : () =>
This SR is unlocked.
; return ( <> } position="bottom-left">
SR {isLocked && ( )}
); } const trackedIcon = isTracked ? 'tracked' : 'dotted-circle'; return (
{isTracked ? ( <> Series is tracked and can be viewed
in the measurement panel ) : ( <> Measurements for untracked series
will not be shown in the
measurements panel )}
} > ); }; return (
{renderIconStatus()} {label}
{studyDate} S: {currentSeries}
{/* TODO: This is tricky. Our "no-wrap" in truncate means this has a hard length. The overflow forces ellipse. If we don't set max width appropriately, this causes the ActionBar to overflow. Can clean up by setting percentage widths + calc on parent containers */}

{seriesDescription}

{showNavArrows && !showCine && (
)} {showCine && !showNavArrows && (
)}
); }; ViewportActionBar.propTypes = { onSeriesChange: PropTypes.func.isRequired, showNavArrows: PropTypes.bool, showCine: PropTypes.bool, cineProps: PropTypes.object, showPatientInfo: PropTypes.bool, studyData: PropTypes.shape({ label: PropTypes.string.isRequired, isTracked: PropTypes.bool.isRequired, isLocked: PropTypes.bool.isRequired, studyDate: PropTypes.string.isRequired, currentSeries: PropTypes.number.isRequired, seriesDescription: PropTypes.string.isRequired, modality: PropTypes.string.isRequired, patientInformation: PropTypes.shape({ patientName: PropTypes.string.isRequired, patientSex: PropTypes.string.isRequired, patientAge: PropTypes.string.isRequired, MRN: PropTypes.string.isRequired, thickness: PropTypes.string.isRequired, spacing: PropTypes.string.isRequired, scanner: PropTypes.string.isRequired, }), }).isRequired, }; ViewportActionBar.defaultProps = { cineProps: {}, showCine: false, showNavArrows: true, showPatientInfo: false, }; function PatientInfo({ patientName, patientSex, patientAge, MRN, thickness, spacing, scanner, isOpen, showPatientInfoRef, }) { while (patientAge.charAt(0) === '0') { patientAge = patientAge.substr(1); } return (
{patientName}
Sex {patientSex}
Age {patientAge}
MRN {MRN}
Thickness {thickness}
Spacing {spacing}
Scanner {scanner}
) } >
); } export default ViewportActionBar;