diff --git a/src/App.tsx b/src/App.tsx index 8148a9dd..aec06f3a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -104,6 +104,7 @@ function App(props: RouteComponentProps) { const currentSpec = useRef(); + // Clinical Panel will only render in non-minimal mode and if the demo has clinical info const [isClinicalPanelOpen, setIsClinicalPanelOpen] = useState(false); const CLINICAL_PANEL_WIDTH = isMinimalMode || !demo?.clinicalInfo ? 0 : isClinicalPanelOpen ? 250 : 45; @@ -145,8 +146,8 @@ function App(props: RouteComponentProps) { } useEffect(() => { - setVisPanelWidth(INIT_VIS_PANEL_WIDTH - (VIS_PADDING.left + VIS_PADDING.right + CLINICAL_PANEL_WIDTH)); - }, [isClinicalPanelOpen]); + setVisPanelWidth(INIT_VIS_PANEL_WIDTH - (VIS_PADDING.left + VIS_PADDING.right + CLINICAL_PANEL_WIDTH + 6)); + }, [demo, isClinicalPanelOpen]); // update demo useEffect(() => { @@ -196,7 +197,7 @@ function App(props: RouteComponentProps) { rightReads.current = []; // Update the appearance of the clinical panel - setIsClinicalPanelOpen(!!demo?.clinicalInfo); + setIsClinicalPanelOpen(!!demo?.clinicalInfo && isClinicalPanelOpen); }, [demo]); useEffect(() => { @@ -564,7 +565,18 @@ function App(props: RouteComponentProps) { /> ); // !! Removed `demo` not to update twice since `drivers` are updated right after a demo update. - }, [ready, xDomain, visPanelWidth, drivers, showOverview, showPutativeDriver, selectedSvId, breakpoints, svReads]); + }, [ + ready, + xDomain, + visPanelWidth, + drivers, + showOverview, + showPutativeDriver, + selectedSvId, + breakpoints, + svReads, + isClinicalPanelOpen + ]); const trackTooltips = useMemo(() => { // calculate the offset by the Genome View @@ -981,7 +993,7 @@ function App(props: RouteComponentProps) { {!isMinimalMode && (
- {!isMinimalMode && demo?.clinicalInfo && ( + {!isMinimalMode && !!demo?.clinicalInfo && ( { return { group: 'default', ...d }}); diff --git a/src/ui/ClinicalPanel/index.tsx b/src/ui/ClinicalPanel/index.tsx index 74f385e4..e5c6c14d 100644 --- a/src/ui/ClinicalPanel/index.tsx +++ b/src/ui/ClinicalPanel/index.tsx @@ -15,12 +15,42 @@ export type DataRowProps = { handleClick?: () => void; }; +export type ClinicalInfo = { + summary: SummaryItem[]; + variants: VariantItem[]; + signatures: SignatureItem[]; +}; + +export type SummaryItem = { + label: string; + value: string; +}; + +export type VariantItem = { + gene: string; + type?: string; // if we know all the possible types, we can narrow down further, i.e., type: "Germline" | "homozygous loss" | ...; + cDNA?: string; + chr: string; + start: string | number; + end: string | number; + position: string | number; + handleClick?: () => void; +}; + +export type SignatureItem = { + type: string; // if we know all the possible types, we can narrow down further, i.e., type: "indels" | "point_mutations" | ...; + count: string | number; + label: string; + hrDetect: boolean; +}; + // Data row with label and value const DataRow = ({ handleClick, label, value }: DataRowProps) => { - // Format label to be capitalized - let capitalizedLabel: string; - if (label) { - capitalizedLabel = label.charAt(0).toUpperCase() + label.slice(1); + let formattedLabel = label; + + // Format label to be capitalized if string + if (label && typeof label === 'string') { + formattedLabel = label.charAt(0).toUpperCase() + label.slice(1); } return ( @@ -29,7 +59,7 @@ const DataRow = ({ handleClick, label, value }: DataRowProps) => { onClick={handleClick ? () => handleClick() : null} role={handleClick ? 'button' : ''} > - {label ? {capitalizedLabel} : null} + {label ? {formattedLabel} : null} {value} ); @@ -82,11 +112,12 @@ const ToggleRowGroup = ({ callout = null, header, data }: ToggleRowGroupProps) = type PanelSectionProps = { data: DataRowProps[]; + callout?: string; handleZoomToGene?: (gene: string) => void; }; // Panel section for Clinical Summary data -const ClinicalSummary = ({ data }: PanelSectionProps) => { +const ClinicalSummary = ({ data, callout = null }: PanelSectionProps) => { const [isExpanded, setIsExpanded] = useState(true); return ( @@ -101,11 +132,13 @@ const ClinicalSummary = ({ data }: PanelSectionProps) => {
-
-
- Invasive Ductal Carcinoma + {callout && ( +
+
+ {callout} +
-
+ )}
    {data.map((row: DataRowProps, i: number) => { return ; @@ -240,7 +273,15 @@ export const ClinicalPanel = ({ setInteractiveMode, setIsClinicalPanelOpen }: ClinicalPanelProps) => { - const [clinicalInformation, setClinicalInformation] = useState(null); + const { clinicalInfo: clinicalInformation, cancer } = demo; + + // Format cancer label to add as callout + const formattedCancerLabel = cancer + ? cancer + .split(' ') + .map((s: string) => s.charAt(0).toUpperCase() + s.slice(1)) + .join(' ') + : null; const handleZoomToGene = (gene: string) => { setInteractiveMode(true); @@ -256,12 +297,6 @@ export const ClinicalPanel = ({ gosRef.current.api.zoomToGene(`${demo.id}-mid-ideogram`, `${gene}`, 1000); }; - useEffect(() => { - if (hasClinicalInfo && demo?.clinicalInfo) { - setClinicalInformation(demo.clinicalInfo); - } - }, [demo]); - return (
    - +