diff --git a/extensions/default/src/Components/SidePanelWithServices.tsx b/extensions/default/src/Components/SidePanelWithServices.tsx index c4fd32a..2b02164 100644 --- a/extensions/default/src/Components/SidePanelWithServices.tsx +++ b/extensions/default/src/Components/SidePanelWithServices.tsx @@ -71,11 +71,25 @@ const SidePanelWithServices = ({ const activatePanelSubscription = panelService.subscribe( panelService.EVENTS.ACTIVATE_PANEL, (activatePanelEvent: Types.ActivatePanelEvent) => { - if (sidePanelOpen || activatePanelEvent.forceActive) { - const tabIndex = tabs.findIndex(tab => tab.id === activatePanelEvent.panelId); - if (tabIndex !== -1) { - setActiveTabIndex(tabIndex); + // Handle the `-exp` suffix logic + const isExpertisePanel = activatePanelEvent.panelId.endsWith('-exp'); + const realPanelID = isExpertisePanel + ? activatePanelEvent.panelId.replace(/-exp$/, '') + : activatePanelEvent.panelId; + + const tabIndex = tabs.findIndex(tab => tab.id === realPanelID); + + if (isExpertisePanel && side === 'right') { + const shouldOpen = !sidePanelOpen; // Use sidePanelOpen to determine toggle state + setSidePanelOpen(shouldOpen); + + if (shouldOpen) { + setActiveTabIndex(tabIndex !== -1 ? tabIndex : null); + } else { + setActiveTabIndex(null); } + } else if (tabIndex !== -1) { + setActiveTabIndex(tabIndex); } } ); @@ -95,6 +109,7 @@ const SidePanelWithServices = ({ onClose={handleClose} onActiveTabIndexChange={handleActiveTabIndexChange} expandedWidth={expandedWidth} + servicesManager={servicesManager} // Pass servicesManager ke SidePanel /> ); }; diff --git a/platform/ui-next/src/components/SidePanel/SidePanel.tsx b/platform/ui-next/src/components/SidePanel/SidePanel.tsx index feee007..f866190 100644 --- a/platform/ui-next/src/components/SidePanel/SidePanel.tsx +++ b/platform/ui-next/src/components/SidePanel/SidePanel.tsx @@ -4,6 +4,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Icons } from '../Icons'; import { TooltipTrigger, TooltipContent, TooltipProvider, Tooltip } from '../Tooltip'; import { Separator } from '../Separator'; +import { ScrollArea } from '../ScrollArea'; type StyleMap = { open: { @@ -152,10 +153,22 @@ const SidePanel = ({ onClose, expandedWidth = 280, onActiveTabIndexChange, + servicesManager, // Tambah servicesManager as a prop }) => { const [panelOpen, setPanelOpen] = useState(activeTabIndexProp !== null); const [activeTabIndex, setActiveTabIndex] = useState(0); + const [isExpertiseVisible, setIsExpertiseVisible] = useState(false); // New state for expertise visibility + const [expertiseData, setExpertiseData] = useState(null); + const [isExpertiseLoading, setIsExpertiseLoading] = useState(false); + + const { cornerstoneViewportService } = servicesManager.services; + const [viewportData, setViewportData] = useState(null); + + // Harusnya (viewportId), tapi karena gabutuh perubahan viewport maka dihardcode 'default' + const viewportInfo = cornerstoneViewportService.getViewportInfo('default'); + const studyInstanceUID = viewportInfo?.viewportData?.data?.[0]?.StudyInstanceUID || ''; + const styleMap = createStyleMap(expandedWidth, borderSize, collapsedWidth); const baseStyle = createBaseStyle(expandedWidth); const gridAvailableWidth = expandedWidth - closeIconWidth - gridHorizontalPadding; @@ -196,6 +209,16 @@ const SidePanel = ({ updateActiveTabIndex(activeTabIndexProp); }, [activeTabIndexProp, updateActiveTabIndex]); + const toggleExpertiseVisibility = () => { + const shouldOpenExpertise = !isExpertiseVisible; + setIsExpertiseVisible(shouldOpenExpertise); + + // Open the side panel if the expertise panel is being shown + if (shouldOpenExpertise && !panelOpen) { + updatePanelOpen(true); + } + }; + const getCloseStateComponent = () => { const _childComponents = Array.isArray(tabs) ? tabs : [tabs]; return ( @@ -255,6 +278,230 @@ const SidePanel = ({ ); }; + // Tambahkan di atas useEffect fetchExpertiseData + useEffect(() => { + const fetchAccessionNumber = async () => { + if (!studyInstanceUID) { + console.warn('No StudyInstanceUID available'); + return; + } + + try { + const qidoRootUrl = getQidoRootUrl(); + if (!qidoRootUrl) { + console.warn('QIDO root URL not configured'); + return; + } + + // Fetch data with specific fields including Accession Number + const response = await fetch( + `${qidoRootUrl}/studies?includefield=00080050&StudyInstanceUID=${studyInstanceUID}` + ); + + if (!response.ok) { + throw new Error('Failed to fetch study data'); + } + + const data = await response.json(); + + if (data && data.length > 0) { + // Extract accession number from DICOM tag 00080050 + const accessionNumber = data[0]['00080050']?.Value?.[0] || ''; + + // If we have an accession number, call fetchExpertiseData + if (accessionNumber) { + console.log('Found Accession Number:', accessionNumber); + fetchExpertiseData(accessionNumber); + } else { + console.warn('Accession number not found in study data'); + } + } else { + console.warn('No study data returned'); + } + } catch (error) { + console.error('Error fetching accession number:', error); + } + }; + + // Helper function to get QIDO root URL + const getQidoRootUrl = () => { + const { config } = window; + if (!config?.dataSources || !config.defaultDataSourceName) { + return null; + } + + const dataSource = config.dataSources.find( + ds => ds.sourceName === config.defaultDataSourceName + ); + + return dataSource?.configuration?.qidoRoot; + }; + + fetchAccessionNumber(); + }, [studyInstanceUID]); // Run when studyInstanceUID changes + + // Ubah fungsi fetchExpertiseData menjadi dengan parameter accessionNumber + const fetchExpertiseData = async accessionNumber => { + try { + // Check if window.config.expertise_host exists + if (!window.config?.expertise_host) { + console.warn('Expertise host not configured in window.config.expertise_host'); + return; + } + + if (!accessionNumber) { + console.warn('No accession number available for expertise lookup'); + return; + } + + setIsExpertiseLoading(true); + const url = `${window.config.expertise_host}/nv/query.php?method=view&AccessionNumber=${encodeURIComponent(accessionNumber)}`; + + const response = await fetch(url); + const data = await response.json(); + // console.log('Study data:', data); + + const data = { + study: { + accession_no: 'CR.250411.001', + study_iuid: '1.2.826.0.1.3680043.9.7307.1.20250411001', + study_description: '', + study_datetime: '20250411093937', + number_of_series: '1', + number_of_instances: '1', + modality: 'CR', + patient_mrn: '00000941', + patient_name: 'NEFANNY RIDWAN', + patient_sex: 'F', + patient_date_of_birth: '19881127', + patient_age: '36Y 4M 14D', + expertise: [ + { + expertise: + 'Keterangan : MCU\r\n\r\nRadiografi Thorax PA (inspirasi kurang)\r\n\r\nCor : besar dan bentuk normal\r\nPulmo : tak tampak infiltrat\r\nTrachea tampak di tengah\r\nSinus phrenicocostalis kanan kiri tajam\r\nHemidiafragma kanan kiri tampak baik\r\nTulang-tulang tampak baik\r\nSoft tissue tak tampak kelainan\r\n\r\nKesan :\r\nTidak tampak kelainan signifikan pada pemeriksaan saat ini\r\n\r\nBTK,', + radiologist: 'dr. Hendra Boy Situmorang, Sp.Rad ', + expertise_dttm: '2025-04-11 09:43', + radiologist_edit: null, + expertise_edit_dttm: '0000-00-00 00:00', + ordering_physician: 'dr. Laksmitasari Dewi', + }, + ], + series: [ + { + series_number: '1', + series_iuid: '1.2.156.112536.2.560.28134011043131122.1519098341436.1', + series_description: 'V04_0014', + number_of_instances: 1, + thumbnail: + 'http://192.168.22.3/nv/wado_proxy_thumb.php?requestType=WADO&studyUID=1.2.826.0.1.3680043.9.7307.1.20250411001&seriesUID=1.2.156.112536.2.560.28134011043131122.1519098341436.1&objectUID=1.2.156.112536.2.560.28134011043131122.1519098341436.4&rows=123', + sop_iuids: ['1.2.156.112536.2.560.28134011043131122.1519098341436.4'], + }, + ], + }, + }; + + if (data?.study?.expertise && data.study.expertise.length > 0) { + setExpertiseData(data.study.expertise[0]); + } + } catch (error) { + console.error('Error fetching expertise data:', error); + } finally { + setIsExpertiseLoading(false); + } + }; + + const getExpertisePanel = () => { + if (side !== 'right') return null; // Only show in the right side panel + + if (isExpertiseLoading) { + return ( +
{section.value}
+ )} +