242 lines
6.8 KiB
TypeScript
Executable File
242 lines
6.8 KiB
TypeScript
Executable File
import {
|
||
Button,
|
||
Center,
|
||
Modal,
|
||
Space,
|
||
Stepper,
|
||
Title,
|
||
Text,
|
||
Flex,
|
||
Select,
|
||
Textarea,
|
||
} from "@mantine/core";
|
||
import { useEffect, useState } from "react";
|
||
import "./NewMolecule.css";
|
||
import {
|
||
IconArchiveFilled,
|
||
IconArticleFilled,
|
||
IconFileFilled,
|
||
} from "@tabler/icons-react";
|
||
import {
|
||
ConvertMoleculeToStandart,
|
||
GetInFormats,
|
||
} from "Api/ConvertBackendCalls";
|
||
import { AxiosError } from "axios";
|
||
import CustomButton from "Components/CustomButton/CustomButton";
|
||
|
||
interface NewMoleculeModalProps {
|
||
isOpened: boolean;
|
||
setIsOpened: (opened: boolean) => void;
|
||
}
|
||
|
||
export function NewMoleculeModal(props: NewMoleculeModalProps) {
|
||
const [activeStep, setActiveStep] = useState(0);
|
||
const [selectedMethod, setSelectedMethod] = useState(0);
|
||
|
||
const [inMolecule, setInMolecule] = useState("");
|
||
const [inFormat, setInFormat] = useState<string | null>();
|
||
|
||
const [inOptions, setInOptions] = useState<string[] | undefined>();
|
||
|
||
const getOptions = () => {
|
||
GetInFormats().then((data: { [key: string]: string } | AxiosError) => {
|
||
if (data instanceof AxiosError) {
|
||
//TODO: handle Error
|
||
} else {
|
||
const values = Object.keys(data);
|
||
setInOptions(values);
|
||
}
|
||
});
|
||
};
|
||
|
||
useEffect(() => {
|
||
getOptions();
|
||
}, []);
|
||
|
||
//reset on open dialog
|
||
useEffect(() => {
|
||
if (props.isOpened) {
|
||
setActiveStep(0);
|
||
setSelectedMethod(0);
|
||
setInMolecule("");
|
||
setInFormat(undefined);
|
||
if (inOptions == undefined) {
|
||
getOptions();
|
||
}
|
||
}
|
||
}, [props.isOpened]);
|
||
|
||
const handleClose = () => {
|
||
props.setIsOpened(false);
|
||
};
|
||
|
||
const handleConvert = () => {
|
||
if (inFormat) {
|
||
ConvertMoleculeToStandart({
|
||
inputText: inMolecule,
|
||
inputFormat: inFormat,
|
||
make_3d: true,
|
||
add_h: false,
|
||
optimize: false,
|
||
}).then((data: string | AxiosError) => {
|
||
if (data instanceof AxiosError) {
|
||
//TODO: handle Error
|
||
} else {
|
||
setCurrentMoleculeString(data);
|
||
props.setIsOpened(false);
|
||
}
|
||
});
|
||
} else {
|
||
//TODO: add no format selected handling
|
||
}
|
||
};
|
||
|
||
const handleEmptyMolecule = () => {
|
||
props.setIsOpened(false);
|
||
};
|
||
|
||
return (
|
||
<Modal
|
||
opened={props.isOpened}
|
||
onClose={handleClose}
|
||
title=<Title size="xl">Новая молекула</Title>
|
||
centered
|
||
size="75%"
|
||
styles={{
|
||
content: { paddingLeft: "10px" },
|
||
title: { width: "100%" },
|
||
}}
|
||
>
|
||
<Stepper
|
||
active={activeStep}
|
||
onStepClick={setActiveStep}
|
||
allowNextStepsSelect={false}
|
||
classNames={{ root: "StepperRoot" }}
|
||
styles={{
|
||
steps: {
|
||
paddingTop: "30px",
|
||
paddingBottom: "30px",
|
||
paddingLeft: "20px",
|
||
minWidth: "0px",
|
||
alignSelf: "center",
|
||
},
|
||
content: {
|
||
flex: 1,
|
||
},
|
||
}}
|
||
style={{ display: "flex", flexDirection: "row" }}
|
||
orientation="vertical"
|
||
>
|
||
<Stepper.Step>
|
||
<div style={{ width: "100%", textAlign: "center" }}>
|
||
<Title size="lg">Шаг 1: Способ добавления молекулы</Title>
|
||
<Space h="lg" />
|
||
<Flex justify="center" gap="md" wrap="wrap">
|
||
<Button
|
||
onClick={() => {
|
||
setSelectedMethod(1);
|
||
handleEmptyMolecule();
|
||
}}
|
||
style={{ height: "100px", flexGrow: "1" }}
|
||
size="lg"
|
||
>
|
||
<Flex direction="row" gap="lg">
|
||
<IconFileFilled size={40} />
|
||
<Center>
|
||
<Text>Пустая молекула</Text>
|
||
</Center>
|
||
</Flex>
|
||
</Button>
|
||
<Button
|
||
onClick={() => {
|
||
setSelectedMethod(2);
|
||
setActiveStep(1);
|
||
}}
|
||
style={{ height: "100px", flexGrow: "1" }}
|
||
>
|
||
<Flex direction="row" gap="lg">
|
||
<IconArchiveFilled size="40" />
|
||
<Center>
|
||
<Text>Из файла / Архива</Text>
|
||
</Center>
|
||
</Flex>
|
||
</Button>
|
||
<Button
|
||
onClick={() => {
|
||
setSelectedMethod(3);
|
||
setActiveStep(1);
|
||
}}
|
||
style={{ height: "100px", flexGrow: "1" }}
|
||
>
|
||
<Flex direction="row" gap="lg">
|
||
<IconArticleFilled size={40} />
|
||
<Center>
|
||
<Text>Другой формат</Text>
|
||
</Center>
|
||
</Flex>
|
||
</Button>
|
||
</Flex>
|
||
</div>
|
||
</Stepper.Step>
|
||
<Stepper.Step>
|
||
<div style={{ width: "100%", textAlign: "center" }}>
|
||
{selectedMethod == 2 && (
|
||
<div>
|
||
<Title size="lg">Шаг 2: Выбор файла</Title>
|
||
<Space h="lg" />
|
||
</div>
|
||
)}
|
||
{selectedMethod == 3 && (
|
||
<div>
|
||
<Title size="md">Шаг 2: Ввод молекулы</Title>
|
||
<Space h="lg" />
|
||
<Textarea
|
||
className="moleculeInput"
|
||
value={inMolecule}
|
||
onChange={(e) => setInMolecule(e.currentTarget.value)}
|
||
placeholder="Введите текст молекулы"
|
||
classNames={{
|
||
wrapper: "moleculeInputWrapper",
|
||
}}
|
||
onKeyDown={(e) => {
|
||
// Stop arrow keys from reaching react-resizable-panels
|
||
if (
|
||
[
|
||
"ArrowUp",
|
||
"ArrowDown",
|
||
"ArrowLeft",
|
||
"ArrowRight",
|
||
].includes(e.key)
|
||
) {
|
||
e.stopPropagation();
|
||
}
|
||
}}
|
||
/>
|
||
<Space h="md" />
|
||
<Select
|
||
value={inFormat}
|
||
onChange={(value: string | null) => setInFormat(value)}
|
||
searchable
|
||
data={inOptions}
|
||
placeholder="Выберите формат"
|
||
classNames={{
|
||
input: "selectInFormat",
|
||
dropdown: "selectDropDown",
|
||
option: "selectDropDownOption",
|
||
}}
|
||
/>
|
||
<Space h="md" />
|
||
<CustomButton
|
||
color="accent"
|
||
onClick={handleConvert}
|
||
text="Преобразовать"
|
||
/>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</Stepper.Step>
|
||
</Stepper>
|
||
</Modal>
|
||
);
|
||
}
|