import React, { useState } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useDrag } from 'react-dnd'; import { Icons } from '../Icons'; import { DisplaySetMessageListTooltip } from '../DisplaySetMessageListTooltip'; import { TooltipTrigger, TooltipContent, Tooltip } from '../Tooltip'; import { Button } from '../Button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '../DropdownMenu'; /** * Display a thumbnail for a display set. */ const Thumbnail = ({ displaySetInstanceUID, className, imageSrc, imageAltText, description, seriesNumber, numInstances, loadingProgress, countIcon, messages, dragData = {}, isActive, onClick, onDoubleClick, viewPreset = 'thumbnails', modality, isHydratedForDerivedDisplaySet = false, canReject = false, onReject = () => {}, isTracked = false, thumbnailType = 'thumbnail', onClickUntrack = () => {}, onThumbnailContextMenu, }: withAppTypes): React.ReactNode => { // TODO: We should wrap our thumbnail to create a "DraggableThumbnail", as // this will still allow for "drag", even if there is no drop target for the // specified item. const [collectedProps, drag, dragPreview] = useDrag({ type: 'displayset', item: { ...dragData }, canDrag: function (monitor) { return Object.keys(dragData).length !== 0; }, }); const [lastTap, setLastTap] = useState(0); const handleTouchEnd = e => { const currentTime = new Date().getTime(); const tapLength = currentTime - lastTap; if (tapLength < 300 && tapLength > 0) { onDoubleClick(e); } else { onClick(e); } setLastTap(currentTime); }; const renderThumbnailPreset = () => { return (
{imageSrc ? ( {imageAltText} ) : (
)} {/* bottom left */}
{modality}
{/* top right */}
{isTracked && (
{isTracked ? 'Series is tracked' : 'Series is untracked'}
)}
{/* bottom right */}
{ onThumbnailContextMenu('openDICOMTagViewer', { displaySetInstanceUID, }); }} className="gap-[6px]" > Tag Browser {canReject && ( { onReject(); }} className="gap-[6px]" > Delete Report )}
{description}
S:{seriesNumber}
{countIcon ? ( React.createElement(Icons[countIcon] || Icons.MissingIcon, { className: 'w-3' }) ) : ( )}
{numInstances}
); }; const renderListPreset = () => { return (
{modality}
{description}
S:{seriesNumber}
{' '} {countIcon ? ( React.createElement(Icons[countIcon] || Icons.MissingIcon, { className: 'w-3' }) ) : ( )}
{numInstances}
{isTracked && (
{isTracked ? 'Series is tracked' : 'Series is untracked'}
)} { onThumbnailContextMenu('openDICOMTagViewer', { displaySetInstanceUID, }); }} className="gap-[6px]" > Tag Browser {canReject && ( { onReject(); }} className="gap-[6px]" > Delete Report )}
); }; return (
{viewPreset === 'thumbnails' && renderThumbnailPreset()} {viewPreset === 'list' && renderListPreset()}
); }; Thumbnail.propTypes = { displaySetInstanceUID: PropTypes.string.isRequired, className: PropTypes.string, imageSrc: PropTypes.string, /** * Data the thumbnail should expose to a receiving drop target. Use a matching * `dragData.type` to identify which targets can receive this draggable item. * If this is not set, drag-n-drop will be disabled for this thumbnail. * * Ref: https://react-dnd.github.io/react-dnd/docs/api/use-drag#specification-object-members */ dragData: PropTypes.shape({ /** Must match the "type" a dropTarget expects */ type: PropTypes.string.isRequired, }), imageAltText: PropTypes.string, description: PropTypes.string.isRequired, seriesNumber: PropTypes.any, numInstances: PropTypes.number.isRequired, loadingProgress: PropTypes.number, messages: PropTypes.object, isActive: PropTypes.bool.isRequired, onClick: PropTypes.func.isRequired, onDoubleClick: PropTypes.func.isRequired, viewPreset: PropTypes.string, modality: PropTypes.string, isHydratedForDerivedDisplaySet: PropTypes.bool, canReject: PropTypes.bool, onReject: PropTypes.func, isTracked: PropTypes.bool, onClickUntrack: PropTypes.func, countIcon: PropTypes.string, thumbnailType: PropTypes.oneOf(['thumbnail', 'thumbnailTracked', 'thumbnailNoImage']), }; export { Thumbnail };