Initial commit

This commit is contained in:
2026-03-16 22:05:19 +03:00
commit 8e78b8cb47
71 changed files with 7846 additions and 0 deletions

View File

@@ -0,0 +1,243 @@
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 { useMoleculeEditStore } from "Stores/MoleculeEditStore";
import CustomButton from "Components/CustomButton/CustomButton";
interface NewMoleculeModalProps {
isOpened: boolean;
setIsOpened: (opened: boolean) => void;
}
export function NewMoleculeModal(props: NewMoleculeModalProps) {
const { setCurrentMoleculeString } = useMoleculeEditStore();
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>
);
}