diff --git a/src/import/create/CreateDrop.tsx b/src/import/create/CreateDrop.tsx index 7a2fbd99..066367d3 100644 --- a/src/import/create/CreateDrop.tsx +++ b/src/import/create/CreateDrop.tsx @@ -1,38 +1,32 @@ -import React, { useCallback, useState } from "react"; +import React, { useCallback } from "react"; import { BsFillCloudArrowUpFill as CloudIcon, BsCheckCircleFill as CheckIcon } from 'react-icons/bs'; -import { ProgressBar } from '../../ui'; import { useDropzone } from "react-dropzone"; import { useCustomToast } from "../../utils"; interface CreateDropProps { + files: File[], onDrop: (files: File[]) => void; } -const CreateDrop: React.FC = ({ onDrop }) => { +const CreateDrop: React.FC = ({ files, onDrop }) => { - const {toastError} = useCustomToast() - const [numberOfLoadedFiles, setNumberOfLoadedFiles] = useState(0); - const [numberOfProcessedFiles, setNumberOfProcessedFiles] = useState(0); - - const uploadComplete = numberOfLoadedFiles > 0 && numberOfLoadedFiles === numberOfProcessedFiles; + const { toastError } = useCustomToast() const { getRootProps, open } = useDropzone({ multiple: true, - onDrop: async (files : File[]) => { + onDrop: async (files: File[]) => { if (files && files.length > 0) { - setNumberOfLoadedFiles(files.length); - setNumberOfProcessedFiles(files.length); onDrop(files); } }, - onDropRejected : (_fileRejection :any)=>{ + onDropRejected: (_fileRejection: any) => { toastError("File format rejected (accepts png, jpeg or pdf)") }, accept: { 'image/png': [], 'image/jpeg': [], - 'application/pdf' : [] - } + 'application/pdf': [] + } }); const handleDragOver = useCallback( @@ -48,7 +42,7 @@ const CreateDrop: React.FC = ({ onDrop }) => { {...getRootProps({ onClick: open })} onDragOver={handleDragOver} > - {uploadComplete ? ( + {files.length > 0 ? ( @@ -57,12 +51,8 @@ const CreateDrop: React.FC = ({ onDrop }) => { size={40} className={`text-primary`} /> )} -

{uploadComplete ? numberOfLoadedFiles + ' files loaded' : 'Drag and drop image files here'}

+

{files.length > 0 ? files.length + ' files loaded' : 'Drag and drop image files here'}

- {numberOfLoadedFiles > 0 && ( - - )} ); }; diff --git a/src/import/create/CreateForm.tsx b/src/import/create/CreateForm.tsx index 5c02fcdc..79b3d57b 100644 --- a/src/import/create/CreateForm.tsx +++ b/src/import/create/CreateForm.tsx @@ -7,7 +7,7 @@ import { Colors } from "../../utils/enums"; interface TagFormProps { title: string; className?: string; - onAddTag: (tag: { TagName: string; Value: string }) => void; + onAddTag: (tag: { name: string; value: string }) => void; } const CreateForm = ({ title, className, onAddTag }: TagFormProps) => { @@ -17,7 +17,7 @@ const CreateForm = ({ title, className, onAddTag }: TagFormProps) => { const handleAddTag = () => { if (tag && value) { - onAddTag({ TagName: tag, Value: value }); + onAddTag({ name: tag, value: value }); setTag(''); setValue(''); } diff --git a/src/import/create/CreateRoot.tsx b/src/import/create/CreateRoot.tsx index 4bdfc5f1..8081609d 100644 --- a/src/import/create/CreateRoot.tsx +++ b/src/import/create/CreateRoot.tsx @@ -1,104 +1,84 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState } from 'react'; import { Button } from '../../ui'; -import Model from '../../model/Model'; -import CreateTableSeries from './CreateTableSeries'; -import CreateTableStudy from './CreateTableStudy'; import CreateForm from './CreateForm'; import CreateDrop from './CreateDrop'; import TagTable from './TagTable'; -import { Colors } from '../../utils'; +import { Colors, useCustomMutation, useCustomToast } from '../../utils'; +import { createDicom } from '../../services/instances'; const CreateRoot: React.FC = () => { - const refModel = useRef(new Model()); - const [currentStudyInstanceUID, setCurrentStudyInstanceUID] = useState(null); - const [studiesData, setStudiesData] = useState([]); - const [seriesData, setSeriesData] = useState([]); - const [tags, setTags] = useState<{ TagName: string, Value: string }[]>([]); - + const { toastError, toastSuccess } = useCustomToast() + const [tags, setTags] = useState<{ name: string, value: string }[]>([]); + const [files, setFiles] = useState([]) + + const { mutate } = useCustomMutation( + ({ content, tags }) => createDicom(content, tags), + [[]], + { + onSuccess: () => { + toastSuccess('Dicom series created') + }, + onError: () => { + toastError('Unable to create series') + } + } + ) - const handleFilesUploaded = () => setStudiesData(refModel.current.getStudies()); - const handleStudyClick = (studyInstanceUID: string) => { - setCurrentStudyInstanceUID(studyInstanceUID); - updateSeriesData(studyInstanceUID); + const handleFilesUploaded = (files: File[]) => { + setFiles(files) }; - const updateSeriesData = (studyInstanceUID: string) => { - setSeriesData(refModel.current.getStudy(studyInstanceUID).getAllseries()); - }; - - useEffect(() => { - if (currentStudyInstanceUID) { - updateSeriesData(currentStudyInstanceUID); + const handleCreateDicoms = async () => { + const content: string[] = [] + for (const file of files) { + const dataURI = await readFileAsDataURL(file) + content.push(dataURI) } - }, [currentStudyInstanceUID]); + const formattedtags = {} + tags.forEach(tag => formattedtags[tag.name] = tag.value); + mutate({ content: content, tags: formattedtags }) + } - const handleAddTag = (tag: { TagName: string, Value: string }) => { + const handleAddTag = (tag: { name: string, value: string }) => { setTags(prevTags => [...prevTags, tag]); }; - const handleTagUpdate = (tagName: string, columnId: string, value: string) => { - setTags(prevTags => - prevTags.map(tag => - tag.TagName === tagName ? { ...tag, [columnId]: value } : tag - ) - ); - }; - - const handleTagDelete = (tagName: string) => { - setTags(prevTags => prevTags.filter(tag => tag.TagName !== tagName)); + const handleTagDelete = (name: string) => { + setTags(prevTags => prevTags.filter(tag => tag.name !== name)); }; - const readFileAsDataURL = (file : File) => { - return new Promise((resolve) => { + const readFileAsDataURL = (file: File) => { + return new Promise((resolve) => { var reader = new FileReader() reader.readAsDataURL(file) reader.onload = () => { - resolve(reader.result) + resolve(reader.result as string) } }) } - + return ( <> - -
- - -
- {studiesData.length > 0 && ( - - )} -
-
- {seriesData.length > 0 && ( - - )} -
+
- -
diff --git a/src/import/create/CreateTableSeries.tsx b/src/import/create/CreateTableSeries.tsx deleted file mode 100644 index d6b4a25b..00000000 --- a/src/import/create/CreateTableSeries.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React, { useMemo } from "react"; -import { Table } from "../../ui"; -import { Colors } from "../../utils/enums"; - -interface CreateTableSeriesProps { - data: object[]; -} - -const CreateTableSeries: React.FC = ({ data = [] }) => { - const rows = useMemo(() => data, [data]); - - const columns = useMemo(() => { - return [ - { - accessorKey: "seriesDescription", - header: "Series Description" - }, - { - accessorKey: "modality", - header: "Modality" - }, - { - accessorKey: "seriesNumber", - header: "Series Number" - }, - { - accessorFn: (originalRow: any) => originalRow.instances.length, - header: "Number Of Instances" - } - ]; - }, []); - - const getRowClasses = (row: any) => { - if (row.someCondition) { - return 'bg-primary text-white'; - } else { - return 'bg-indigo-100'; - } - }; - - return ( - getRowClasses(row)} - /> - ); -}; - -export default CreateTableSeries; diff --git a/src/import/create/CreateTableStudy.tsx b/src/import/create/CreateTableStudy.tsx deleted file mode 100644 index 406f09cd..00000000 --- a/src/import/create/CreateTableStudy.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React, { useMemo } from "react"; -import { Table } from "../../ui"; -import { Colors } from "../../utils/enums"; -import Study from "../../model/Study"; - -interface CreateTableStudyProps { - data: Study[]; - onStudyClick: (studyInstanceUID: string) => void; - selectedStudyInstanceUID: string | null; -} - -const CreateTableStudy: React.FC = ({ data = [], onStudyClick, selectedStudyInstanceUID }) => { - const rows = useMemo(() => data, [data]); - - const columns = useMemo(() => { - return [ - { - accessorKey: "patient.patientId", - header: "Patient ID", - cell: (info: { getValue: () => any; }) => {info.getValue() as string} - }, - { - accessorKey: "patient.patientName", - header: "Patient Name", - cell: (info: { getValue: () => any; }) => {info.getValue() as string} - }, - { - accessorKey: "studyDescription", - header: "Study Description", - cell: (info: { getValue: () => any; }) => {info.getValue() as string} - }, - { - accessorKey: "studyDate", - header: "Study Date", - cell: (info: { getValue: () => any; }) => {info.getValue() as string} - }, - { - accessorKey: "accessionNumber", - header: "Accession Number", - cell: (info: { getValue: () => any; }) => {info.getValue() as string} - } - ]; - }, []); - - const getRowClasses = (row: Study) => { - if (row.studyInstanceUID === selectedStudyInstanceUID) { - return 'bg-primary hover:cursor-pointer'; - } else { - return 'hover:bg-indigo-100 hover:cursor-pointer'; - } - }; - - const handleRowClick = (study: Study) => { - if (study.studyInstanceUID !== undefined) { - onStudyClick(study.studyInstanceUID); - } - }; - - return ( -
- ); -}; - -export default CreateTableStudy; diff --git a/src/import/create/TagTable.tsx b/src/import/create/TagTable.tsx index 5533314c..6a819f9c 100644 --- a/src/import/create/TagTable.tsx +++ b/src/import/create/TagTable.tsx @@ -4,32 +4,20 @@ import { ColumnDef } from '@tanstack/react-table'; import DeleteButton from '../../ui/DeleteButton'; import { Colors } from '../../utils'; type TagTableProps = { - data: { TagName: string, Value: string }[]; - onDataUpdate: (tagName: string, columnId: string, value: string) => void; + data: { name: string, value: string }[]; onDeleteTag: (tagName: string) => void; }; -const TagTable: React.FC = ({ data, onDataUpdate, onDeleteTag }) => { - const handleInputChange = (tagName: string, columnId: string, event: React.ChangeEvent) => { - onDataUpdate(tagName, columnId, event.target.value); - }; +const TagTable: React.FC = ({ data, onDeleteTag }) => { - const columns: ColumnDef<{ TagName: string, Value: string }>[] = [ + const columns: ColumnDef<{ name: string, value: string }>[] = [ { - accessorKey: 'TagName', + accessorKey: 'name', header: 'Tag Name', }, { - accessorKey: 'Value', + accessorKey: 'value', header: 'Value', - cell: ({ row }) => ( - handleInputChange(row.original.TagName, 'Value', event)} - className="form-control" - /> - ) }, { id: 'delete', @@ -37,7 +25,7 @@ const TagTable: React.FC = ({ data, onDataUpdate, onDeleteTag }) cell: ({ row }) => (
onDeleteTag(row.original.TagName)} + onClick={() => onDeleteTag(row.original.name)} />