Skip to content

Commit

Permalink
Merge pull request #308 from Pixilib/PreviewStudy
Browse files Browse the repository at this point in the history
preview study
  • Loading branch information
Ceciliadrc authored Sep 2, 2024
2 parents f45d016 + 98b6db9 commit 7b78246
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 72 deletions.
1 change: 0 additions & 1 deletion src/content/series/EditSeries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ const EditSeries: React.FC<EditSeriesProps> = ({ series, onEditSeries, onClose,
<SeriesEditForm
data={series}
onSubmit={handleSubmit}
onCancel={onClose}
jobId={jobId ?? undefined}
onJobCompleted={handleJobCompletion}
/>
Expand Down
77 changes: 35 additions & 42 deletions src/content/series/PreviewSeries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ import React, { ChangeEvent, useMemo, useState } from "react";
import { getInstancesOfSeries } from "../../services/orthanc";
import { useCustomQuery } from "../../utils";

import { Input, Modal, Spinner } from "../../ui";
import { Input, Spinner } from "../../ui";
import PreviewInstance from "./PreviewInstance";
import { Instances } from "../../utils/types";

type PreviewSeriesProps = {
seriesId: string;
onClose: () => void;
show: boolean;
}

const PreviewSeries: React.FC<PreviewSeriesProps> = ({ seriesId, onClose, show }) => {
const PreviewSeries: React.FC<PreviewSeriesProps> = ({ seriesId}) => {

const [rows, setRows] = useState(1)
const [columns, setColumns] = useState(3)
Expand Down Expand Up @@ -63,45 +61,40 @@ const PreviewSeries: React.FC<PreviewSeriesProps> = ({ seriesId, onClose, show }
};

return (
<Modal show={show} size='xl'>
<Modal.Header onClose={onClose} >
<Modal.Title>Preview Series</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className={"flex w-full h-full"} style={{ display: 'grid', gridTemplateColumns: `repeat(${columns}, 1fr)`, gridTemplateRows: `repeat(${rows}, 1fr)` }}>
{
selectedInstanceUIDs?.map((instance: Instances) => {
return <PreviewInstance key={instance.id} instanceUID={instance.id} />
})
}
<>
<div className={"flex w-full h-full"} style={{ display: 'grid', gridTemplateColumns: `repeat(${columns}, 1fr)`, gridTemplateRows: `repeat(${rows}, 1fr)` }}>
{
selectedInstanceUIDs?.map((instance: Instances) => {
return <PreviewInstance key={instance.id} instanceUID={instance.id} />
})
}
</div>
<input className="w-full" type="range" value={imageIndex} min={0} max={(instanceUIDs?.length ?? 1) - 1} onChange={(event: ChangeEvent<HTMLInputElement>) => setImageIndex(Number(event.target.value))} />
<div className={"flex w-full justify-center"}>
<div className="flex gap-3">
<Input
label="Columns :"
type="number"
id="number"
name="columns"
min={0}
max={10}
value={columns}
onChange={handleColumnChange}
/>
<Input
label="Rows :"
type="number"
id="number"
name="rows"
min={1}
max={10}
value={rows}
onChange={handleRowChange}
/>
</div>
<input className="w-full" type="range" value={imageIndex} min={0} max={(instanceUIDs?.length ?? 1) - 1} onChange={(event: ChangeEvent<HTMLInputElement>) => setImageIndex(Number(event.target.value))} />
<div className={"flex w-full justify-center"}>
<div className="flex gap-3">
<Input
label="Columns :"
type="number"
id="number"
name="columns"
min={0}
max={10}
value={columns}
onChange={handleColumnChange}
/>
<Input
label="Rows :"
type="number"
id="number"
name="rows"
min={1}
max={10}
value={rows}
onChange={handleRowChange}
/>
</div>
</div>
</Modal.Body>
</Modal>
</div>
</>
);
};

Expand Down
6 changes: 5 additions & 1 deletion src/content/series/SeriesEditForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { ChangeEvent, useState } from "react";
import { Series, SeriesPayload, SeriesMainDicomTags } from '../../utils/types';
import { InputWithDelete, CheckBox } from "../../ui";
import { InputWithDelete, CheckBox, Button } from "../../ui";

import ProgressJobs from "../../query/ProgressJobs";
import { Colors } from "../../utils";

type SeriesEditFormProps = {
data: Series;
Expand Down Expand Up @@ -120,6 +121,9 @@ const SeriesEditForm = ({ data, onSubmit, jobId, onJobCompleted }: SeriesEditFor
bordered={false}
/>
</div>
<div>
<Button type="submit" color={Colors.secondary}>Modify</Button>
</div>
{
jobId && (
<div className="flex flex-col items-center justify-center">
Expand Down
31 changes: 17 additions & 14 deletions src/content/series/SeriesRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import EditSeries from './EditSeries';
import PreviewSeries from './PreviewSeries';
import { useConfirm } from '../../services/ConfirmContextProvider';
import { useCustomToast } from '../../utils/toastify';
import { Spinner } from '../../ui';
import { Modal, Spinner } from '../../ui';

interface SeriesRootProps {
studyId: string;
Expand All @@ -23,11 +23,11 @@ const SeriesRoot: React.FC<SeriesRootProps> = ({ studyId }) => {

const { confirm } = useConfirm();
const { toastSuccess, toastError } = useCustomToast();

const { data: seriesList, isLoading, refetch: refetchSeries } = useCustomQuery<Series[]>(
['series', studyId],
() => getSeriesOfStudy(studyId),
{
{
onError: (error) => {
console.error(`No series for this study or an error occured: ${error}`);
}
Expand Down Expand Up @@ -58,13 +58,13 @@ const SeriesRoot: React.FC<SeriesRootProps> = ({ studyId }) => {
const handleDeleteSeries = async (seriesId: string) => {
const confirmContent = (
<div className="italic">
Are you sure you want to delete this Series:
<span className="text-xl not-italic font-bold text-primary">{seriesId} ?</span>
Are you sure you want to delete this Series:
<span className="text-xl not-italic font-bold text-primary">{seriesId} ?</span>
</div>
);
if (await confirm({content: confirmContent})) {
mutateDeleteSeries(seriesId);
}
);
if (await confirm({ content: confirmContent })) {
mutateDeleteSeries(seriesId);
}
};


Expand Down Expand Up @@ -110,11 +110,14 @@ const SeriesRoot: React.FC<SeriesRootProps> = ({ studyId }) => {
/>
)}
{previewSeries && (
<PreviewSeries
seriesId={previewSeries.id}
onClose={() => setPreviewSeries(null)}
show={!!previewSeries}
/>
<Modal show={!!previewSeries} size='xl'>
<Modal.Header onClose={() => setPreviewSeries(null)} >
<Modal.Title>Preview Series</Modal.Title>
</Modal.Header>
<Modal.Body>
<PreviewSeries seriesId={previewSeries.id} />
</Modal.Body>
</Modal>
)}
</div>
);
Expand Down
57 changes: 57 additions & 0 deletions src/content/studies/PreviewStudy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Component for a modal to preview a study
* @name PreviewStudy
*/

import React from "react";
import { getSeriesOfStudy } from "../../services/orthanc";
import { useCustomQuery } from "../../utils";

import { Accordion, Modal, Spinner } from "../../ui";
import { Series } from "../../utils/types";
import { AccordionHeader } from "../../ui/Accordion";
import PreviewSeries from "../series/PreviewSeries";

type PreviewStudyProps = {
studyId: string;
onClose: () => void;
show: boolean;
}

const PreviewStudy: React.FC<PreviewStudyProps> = ({ studyId, onClose, show }) => {

const { data: series, isLoading } = useCustomQuery(
['study', studyId, 'series'],
() => getSeriesOfStudy(studyId),
{
select: (instances: Series[]) => {
return instances.sort((a, b) => a.mainDicomTags?.seriesDescription?.localeCompare(b.mainDicomTags?.seriesDescription ?? "") ?? 0)
}
}
)

if (isLoading) return <Spinner />

return (
<Modal show={show} size='xl'>
<Modal.Header onClose={onClose} >
<Modal.Title>Preview Study</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className={"flex flex-col w-full h-full gap-3"}>
{
series?.map((series: Series) => {
return (
<Accordion variant="secondary" header={<AccordionHeader variant="primary">{(series.mainDicomTags?.seriesDescription?.length ?? 0) > 0 ? series.mainDicomTags?.seriesDescription : "N/A"}</AccordionHeader>}>
<PreviewSeries seriesId={series.id} />
</Accordion>
)
})
}
</div>
</Modal.Body>
</Modal>
);
};

export default PreviewStudy;
19 changes: 12 additions & 7 deletions src/content/studies/StudyRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCustomMutation } from '../../utils/reactQuery';
import { deleteStudy } from '../../services/orthanc';
import StudyTable from './StudyTable';
import EditStudy from './EditStudy';
// import PreviewStudy from './PreviewStudy';
import PreviewStudy from './PreviewStudy';
import { useConfirm } from '../../services/ConfirmContextProvider';
import { useCustomToast } from '../../utils/toastify';
import Patient from '../../model/Patient';
Expand All @@ -16,6 +16,7 @@ type StudyRootProps = {

const StudyRoot: React.FC<StudyRootProps> = ({ patient, onStudyUpdated, onStudySelected }) => {
const [editingStudy, setEditingStudy] = useState<string | null>(null);
const [previewStudyId, setPreviewStudyId] = useState<string | null>(null);

const { confirm } = useConfirm();
const { toastSuccess, toastError } = useCustomToast();
Expand Down Expand Up @@ -55,6 +56,10 @@ const StudyRoot: React.FC<StudyRootProps> = ({ patient, onStudyUpdated, onStudyS
}
};

const handlePreviewStudy = (studyId: string) => {
setPreviewStudyId(studyId);
}

const handleStudyAction = (action: string, studyId: string) => {
switch (action) {
case 'edit':
Expand All @@ -64,7 +69,7 @@ const StudyRoot: React.FC<StudyRootProps> = ({ patient, onStudyUpdated, onStudyS
handleDeleteStudy(studyId);
break;
case 'preview':
// handlePreviewStudy(studyId);
handlePreviewStudy(studyId);
break;
default:
break;
Expand All @@ -91,13 +96,13 @@ const StudyRoot: React.FC<StudyRootProps> = ({ patient, onStudyUpdated, onStudyS
show={!!editingStudy}
/>
)}
{/* {previewStudy && (
{previewStudyId && (
<PreviewStudy
studyId={previewStudy.id}
onClose={() => setPreviewStudy(null)}
show={!!previewStudy}
studyId={previewStudyId}
onClose={() => setPreviewStudyId(null)}
show={!!previewStudyId}
/>
)} */}
)}
</div>
);
};
Expand Down
14 changes: 7 additions & 7 deletions src/ui/Accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const Accordion: React.FC<AccordionProps> = ({

return (
<div
className={`transition-all duration-300 ease-in-out my-2 border rounded-lg shadow-md space-y-2 ${getVariantClasses().container} ${className}`}
className={`transition-all duration-300 ease-in-out p-3 border rounded-lg shadow-md w-full ${getVariantClasses().container} ${className}`}
>
<div onClick={handleToggle}>
{header}
Expand All @@ -56,25 +56,25 @@ const Accordion: React.FC<AccordionProps> = ({
type AccordionHeaderProps = {
children?: React.ReactNode;
variant?: string
className? : string
className?: string
}
const AccordionHeader = ({ children, className="", variant="default" }: AccordionHeaderProps) => {
const AccordionHeader = ({ children, className = "", variant = "default" }: AccordionHeaderProps) => {

const getVariantClasses = () => {
switch (variant) {
case "secondary":
return "cursor-pointer flex justify-between items-center p-4 bg-secondary text-white"
return "bg-secondary text-white"
case "primary":
return "cursor-pointer flex justify-between items-center p-4 bg-primary-active text-white"
return "bg-primary-active text-white"
case "default":
default:
return "cursor-pointer flex justify-between items-center p-4 bg-gray-100"
return "bg-gray-100"
};
}


return (
<div className={"rounded-lg shadow-md " + getVariantClasses() + " "+ className} >
<div className={"w-full rounded-lg shadow-md flex flex justify-between items-center p-4 cursor-pointer " + getVariantClasses() + " " + className} >
{children}
</div>
)
Expand Down

0 comments on commit 7b78246

Please sign in to comment.