Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
SophieLab committed Sep 26, 2024
1 parent 784eb52 commit 0885b61
Show file tree
Hide file tree
Showing 27 changed files with 657 additions and 174 deletions.
1 change: 0 additions & 1 deletion src/admin/users/roles/RolesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ const RolesTable = ({ data = [], onEdit, onDelete }: RolesTableProps) => {
];
return (
<div className="pb-6 mx-5 mt-4">

<Table
data={data}
columns={columns}
Expand Down
10 changes: 10 additions & 0 deletions src/anonymize/AnonymizeRoot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const AnonymizeRoot = () => {
return (
<div>
Hello World Anon
</div>
)
}


export default AnonymizeRoot
12 changes: 12 additions & 0 deletions src/assets/Anon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
91 changes: 85 additions & 6 deletions src/content/ContentRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,27 @@ import { QueryPayload, useCustomMutation, useCustomQuery, useCustomToast, Study
import Model from "../model/Model";
import Patient from "../model/Patient";

import { FormCard, Spinner } from "../ui";
import { FormCard, Spinner, Button } from "../ui";

import SearchForm from "../query/SearchForm";
import AccordionPatient from "./patients/AccordionPatient";
import EditPatient from "./patients/EditPatient";
import { Label } from "../utils/types";

import { addStudyIdToDeleteList, addSeriesOfStudyIdToExportList, addStudyIdToAnonymizeList } from '../utils/actionsUtils';

import { Colors } from '../utils';

import AnonIcon from './../assets/Anon.svg?react';
import { BsTrashFill as DeleteIcon } from "react-icons/bs";
import { FaFileExport as ExportIcon } from "react-icons/fa";

const ContentRoot: React.FC = () => {
const { confirm } = useConfirm();
const { toastSuccess, toastError } = useCustomToast();

const [selectedStudies, setSelectedStudies] = useState<{ [studyId: string]: boolean }>({});

const [model, setModel] = useState<Model | null>(null);
const [queryPayload, setQueryPayload] = useState<QueryPayload | null>(null);
const [editingPatient, setEditingPatient] = useState<Patient | null>(null);
Expand Down Expand Up @@ -86,14 +96,51 @@ const ContentRoot: React.FC = () => {
mutateToolsFind(formData);
};

const handlePatientSelectionChange = (selected: boolean, patient: Patient) => {
const studies = patient.getStudies().map(study => study.id)
const newSelectedStudies = { ...selectedStudies };
if (selected) {
studies.forEach((studyId) => {
newSelectedStudies[studyId] = true;
})
setSelectedStudies(newSelectedStudies);
} else {
studies.forEach((studyId) => {
delete newSelectedStudies[studyId];
})
setSelectedStudies(newSelectedStudies);
}
}

const refreshFind = () => {
if (queryPayload) {
mutateToolsFind(queryPayload);
}
};

const handleSendAnonymizeList = async () => {
const studyIds = Object.keys(selectedStudies);
for (const studyId of studyIds) {
await addStudyIdToAnonymizeList(studyId);
}
};

const handleSendExportList = async () => {
const studyIds = Object.keys(selectedStudies);
for (const studyId of studyIds) {
await addSeriesOfStudyIdToExportList(studyId)
}
};

const handleSendDeleteList = async () => {
const studyIds = Object.keys(selectedStudies);
for (const studyId of studyIds) {
await addStudyIdToDeleteList(studyId);
}
};

return (
<div className="flex flex-col items-center w-full">
<div className="flex flex-col gap-3">
<EditPatient
key={editingPatient?.id ?? undefined}
patient={editingPatient as Patient}
Expand All @@ -102,30 +149,62 @@ const ContentRoot: React.FC = () => {
show={editingPatient != null}
/>
<FormCard
className="flex flex-col justify-center w-11/12 bg-white gap-y-2"
className="bg-white"
title="Search"
collapsible={true}
>
<SearchForm onSubmit={handleSubmit} labelsData={labelsData} withAets={true} />
</FormCard>
<div className="flex flex-col items-center w-full">
<div className="mb-4 text-2xl font-bold text-primary">Results</div>
<div className="w-11/12">
<div className="flex flex-col items-center w-full gap-3">
<div className="flex justify-center w-full text-2xl font-bold text-primary">Results</div>
<div className="flex w-full">

<Button
color={Colors.primary}
className="flex items-center mx-2 text-sm transition-transform duration-200 bg-blue-700 hover:scale-105"
onClick={handleSendAnonymizeList}>
<AnonIcon className="text-xl" onClick={undefined} />
<span className="ml-2">Send to Anonymize</span>
</Button>

<Button
color={Colors.secondary}
className="flex items-center mx-2 text-sm transition-transform duration-200 hover:scale-105"
onClick={handleSendExportList}
>
<ExportIcon className="text-xl" />
<span className="ml-2">Send to Export</span>
</Button>

<Button
color={Colors.danger}
className="flex items-center mx-2 text-sm transition-transform duration-200 hover:scale-105"
onClick={handleSendDeleteList}
>
<DeleteIcon className="text-xl" />
<span className="ml-2">Send to delete</span>
</Button>
</div>
<div className="w-full">
{isPending ? (
<Spinner />
) : (
patients.map((patient: Patient) => (
<AccordionPatient
key={patient.id}
patient={patient}
onPatientSelectionChange={handlePatientSelectionChange}
onDeletePatient={handleDeletePatient}
onEditPatient={(patient) => setEditingPatient(patient)}
onStudyUpdated={() => refreshFind()}
onSelectedStudyChange={(selectedState) => setSelectedStudies(selectedState)}
selectedStudies={selectedStudies}
/>
))
)}
</div>
</div>

</div>
);
};
Expand Down
21 changes: 17 additions & 4 deletions src/content/patients/AccordionPatient.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";

import { Accordion, DeleteButton, DownloadButton, EditButton } from "../../ui";
import { Accordion, CheckBox, DeleteButton, DownloadButton, EditButton } from "../../ui";

import Patient from "../../model/Patient";

Expand All @@ -12,15 +12,25 @@ import { useCustomToast } from "../../utils";

type AccordionPatientProps = {
patient: Patient;
onPatientSelectionChange: (selected: boolean, patient: Patient) => void
onEditPatient: (patient: Patient) => void;
onStudyUpdated: (patient: Patient) => void;
onDeletePatient: (patient: Patient) => void;
selectedStudies: { [studyId: string]: boolean }
onSelectedStudyChange: (selectedState: { [studyId: string]: boolean }) => void
};

const AccordionPatient: React.FC<AccordionPatientProps> = ({ patient, onEditPatient, onDeletePatient, onStudyUpdated }) => {
const AccordionPatient = ({ patient, onPatientSelectionChange, onEditPatient, onDeletePatient, onStudyUpdated, selectedStudies, onSelectedStudyChange }: AccordionPatientProps) => {

const { toastSuccess, updateExistingToast } = useCustomToast()
const [selected, setSelected] = useState(false)
const [selectedStudyId, setSelectedStudyId] = useState<string | null>(null);


useEffect(() => {
onPatientSelectionChange(selected, patient)
}, [selected])

const handleStudySelected = (studyId: string) => {
setSelectedStudyId(studyId);
};
Expand Down Expand Up @@ -51,6 +61,7 @@ const AccordionPatient: React.FC<AccordionPatientProps> = ({ patient, onEditPati
<span className="text-sm font-medium group-hover:text-white ">Name: {patient.patientName}</span>
<span className="text-sm font-medium group-hover:text-white">Nb of Studies: {patient.getStudies().length}</span>
<div className="flex justify-end w-full space-x-7">
<CheckBox bordered={false} onClick={(event) => event.stopPropagation()} onChange={(event) => setSelected(event.target.checked)} checked={selected} />
<EditButton onClick={handleEditClick} />
<DownloadButton onClick={handleSaveClick} />
<DeleteButton onClick={handleDeleteClick} />
Expand All @@ -61,12 +72,14 @@ const AccordionPatient: React.FC<AccordionPatientProps> = ({ patient, onEditPati
}
className="w-full rounded-2xl"
>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<div className="grid w-full grid-cols-1 gap-4 lg:grid-cols-2">
<div className={`${!selectedStudyId ? 'lg:col-span-2' : ''}`}>
<StudyRoot
patient={patient}
onStudyUpdated={() => onStudyUpdated(patient)}
onStudySelected={handleStudySelected}
selectedStudies={selectedStudies}
onSelectedStudyChange={onSelectedStudyChange}
/>
</div>
{selectedStudyId && (
Expand Down
80 changes: 4 additions & 76 deletions src/content/studies/StudyRoot.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,31 @@
import React, { useMemo, useState } from 'react';

import { useDispatch } from 'react-redux';
import { useCustomMutation } from '../../utils/reactQuery';
import { useCustomToast } from '../../utils/toastify';
import { Colors } from '../../utils';
import { addStudyIdToDeleteList, addSeriesToExportList, addStudyIdToAnonymizeList } from '../../utils/actionsUtils';

import { deleteStudy } from '../../services/orthanc';
import { exportRessource } from '../../services/export';
import { useConfirm } from '../../services/ConfirmContextProvider';

import Patient from '../../model/Patient';

import StudyTable from './StudyTable';
import EditStudy from './EditStudy';
import PreviewStudy from './PreviewStudy';
import AiStudy from './AiStudy';

import Toolsbar from '../../ui/Toolsbar';
import { Button } from '../../ui';
import { addStudyToAnonymizeList } from '../../reducers/AnonymizeSlice';

import AnonIcon from '../../ui/AnonIcon';
import { BsTrashFill as DeleteIcon } from "react-icons/bs";
import { FaFileExport as ExportIcon } from "react-icons/fa";

type StudyRootProps = {
patient: Patient;
onStudyUpdated: () => void;
onStudySelected?: (studyId: string) => void;
selectedStudies: { [studyId: string]: boolean }
onSelectedStudyChange: (selectedState: { [studyId: string]: boolean }) => void
};

const StudyRoot: React.FC<StudyRootProps> = ({ patient, onStudyUpdated, onStudySelected }) => {
const dispatch = useDispatch();
const StudyRoot = ({ patient, onStudyUpdated, onStudySelected, selectedStudies, onSelectedStudyChange } :StudyRootProps) => {
const [editingStudy, setEditingStudy] = useState<string | null>(null);
const [aiStudyId, setAIStudyId] = useState<string | null>(null);
const [previewStudyId, setPreviewStudyId] = useState<string | null>(null);
const [selectedStudies, setSelectedStudies] = useState<{ [studyId: string]: boolean }>({});
const [isToolsbarVisible, setIsToolsbarVisible] = useState(true);

const { confirm } = useConfirm();
const { toastSuccess, toastError, updateExistingToast } = useCustomToast();
Expand Down Expand Up @@ -89,37 +77,6 @@ const StudyRoot: React.FC<StudyRootProps> = ({ patient, onStudyUpdated, onStudyS
exportRessource("studies", studyId, (mb) => updateExistingToast(id, `Downloaded ${mb} mb`));
};

const handleRowSelectionChange = (selectedState: { [studyId: string]: boolean }) => {
setSelectedStudies(selectedState);
};

const handleSendDeleteList = async () => {
const studyIds = Object.keys(selectedStudies);
for (const studyId of studyIds) {
await addStudyIdToDeleteList(studyId);
}
};

const handleSendExportList = () => {
const studyIds = Object.keys(selectedStudies);
studyIds.forEach(studyId => {
const series = studies.find(study => study.id === studyId);
if (series) {
dispatch(addSeriesToExportList({ series }));
}
});
};

const handleSendAnonymizeList = () => {
const studyIds = Object.keys(selectedStudies);
studyIds.forEach(studyId => {
const series = studies.find(study => study.id === studyId);
if (series) {
dispatch(addStudyToAnonymizeList({ series }));
}
});
};

const handleStudyAction = (action: string, studyId: string) => {
switch (action) {
case 'edit':
Expand Down Expand Up @@ -155,7 +112,7 @@ const StudyRoot: React.FC<StudyRootProps> = ({ patient, onStudyUpdated, onStudyS
onRowClick={handleRowClick}
onActionClick={handleStudyAction}
selectedRows={selectedStudies}
onRowSelectionChange={handleRowSelectionChange}
onRowSelectionChange={onSelectedStudyChange}
/>
{editingStudy && (
<EditStudy
Expand All @@ -180,35 +137,6 @@ const StudyRoot: React.FC<StudyRootProps> = ({ patient, onStudyUpdated, onStudyS
/>
)}
</div>

{isToolsbarVisible && (
<Toolsbar isSticky={true} className="sticky bottom-0 flex items-center justify-center w-full bg-white"> //
<Button
color={Colors.danger}
className="flex items-center mx-2 text-sm transition-transform duration-200 hover:scale-105"
onClick={handleSendDeleteList}
>
<DeleteIcon className="text-xl" />
<span className="ml-2">Send to delete</span>
</Button>

<Button
color={Colors.secondary}
className="flex items-center mx-2 text-sm transition-transform duration-200 hover:scale-105"
onClick={handleSendExportList}
>
<ExportIcon className="text-xl" />
<span className="ml-2">Send to Export</span>
</Button>

<Button //TODO: Add anonymize action
className="flex items-center mx-2 text-sm transition-transform duration-200 bg-blue-700 hover:scale-105"
onClick={handleSendAnonymizeList}>
<AnonIcon className="text-xl" onClick={undefined} />
<span className="ml-2">Send to Anonymize</span>
</Button>
</Toolsbar>
)}
</div>
);
};
Expand Down
Loading

0 comments on commit 0885b61

Please sign in to comment.