2026-05-18 17:33:45 +03:00

271 lines
7.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useCallback, useEffect, useMemo, useState } from 'react';
import { FormsApi } from '../api/forms';
import { CardsSkeleton } from '../components/common/Skeleton';
import { SwitchFormTask } from '../components/common/SwitchFormTask/SwitchFormTask';
import Modal from '../components/common/Modal/Modal';
import { PageContainer, TasksContainer } from './StyledForPage';
import { TaskCardComponent } from '../components/common/TaskCardComponent';
import { WhitePlus } from '../components/common/icons/icons';
import {
Autocomplete,
Box,
Button,
Divider,
FormControl,
FormLabel,
TextField,
} from '@mui/material';
import SearchComponent from '../components/common/SearchComponent';
import { CustomCheckbox } from '../components/common/StyledCheckbox';
import { HeaderSwitch } from '../components/HeaderMenu/HeaderSwitch';
import { toast } from 'react-toastify';
import { PrimaryButton } from '../components/common/Buttons/Buttons';
export default function FormsPage() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const [loadingUpdate, setLoadingUpdate] = useState(false);
const [openModalCreate, setOpenModalCreate] = useState(false);
const [query, setQuery] = useState('');
const baseFormState = useMemo(
() => ({
nameForm: '',
basis: false,
basisForSelect: [],
needBasis: false,
}),
[],
);
const [newFormState, setNewFormState] = useState(baseFormState);
const resetFormState = useCallback(() => {
setNewFormState((prev) => ({
...baseFormState,
basisForSelect: prev.basisForSelect,
}));
}, [baseFormState]);
const getFormsList = async () => {
try {
const data = await FormsApi.formsList();
setItems(data);
} catch (error) {
toast.error('Ошибка загрузки форм');
} finally {
setLoading(false);
}
};
useEffect(() => {
getFormsList();
}, []);
useEffect(() => {
const basisForSelect = items.map((item) => ({
id: item.id,
name: item.title || '',
}));
setNewFormState((prev) => ({
...prev,
basisForSelect,
}));
}, [items]);
const handleOpenCreateModal = () => {
setOpenModalCreate(true);
};
const handleCloseCreateModal = () => {
setOpenModalCreate(false);
resetFormState();
};
const createForm = async () => {
try {
let data;
setLoadingUpdate(true);
if (newFormState.needBasis) {
data = await FormsApi.createFormFromOther({
title: newFormState.nameForm,
form_id: newFormState.basis,
});
} else {
data = await FormsApi.createForm({
title: newFormState.nameForm,
});
}
setItems((prev) => [...prev, data.result]);
setOpenModalCreate(false);
resetFormState();
} catch (error) {
toast.error(error.response?.data?.detail || 'Не удалось создать форму');
} finally {
setLoadingUpdate(false);
}
};
// Фильтруем формы по query
const filteredItems = items.filter((item) =>
item.title?.toLowerCase().includes(query.toLowerCase()),
);
return (
<PageContainer>
<HeaderSwitch></HeaderSwitch>
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
<SwitchFormTask />
<PrimaryButton
onClick={handleOpenCreateModal}
startIcon={<WhitePlus />}
>
Создать форму
</PrimaryButton>
</Box>
<SearchComponent
placeholder="Поиск по названию формы"
value={query}
onChange={setQuery}
/>
<TasksContainer>
{loading ? (
<CardsSkeleton count={8} />
) : (
<>
{filteredItems.length === 0 && (
<div className="text-sm text-gray-500">
{query
? 'Ничего не найдено'
: 'Нет форм. Создайте новую, чтобы начать.'}
</div>
)}
{filteredItems.map((t) => (
<TaskCardComponent
key={t.id + '-form-id'}
taskForm={t}
isForm={true}
/>
))}
</>
)}
</TasksContainer>
<Modal
open={openModalCreate}
onClose={handleCloseCreateModal}
title="Создать форму"
actions={
<>
<Button
variant="grey"
onClick={handleCloseCreateModal}
style={{ height: '2.5rem' }}
disabled={loadingUpdate}
>
Отменить
</Button>
<Button
variant="contained"
style={{ height: '2.5rem' }}
onClick={createForm}
loading={loadingUpdate}
>
Создать
</Button>
</>
}
>
<div className="flex flex-col gap-4 min-h-[16.5rem]">
<FormControl fullWidth>
<FormLabel required>Название формы</FormLabel>
<TextField
size="small"
placeholder="Укажите название формы"
onChange={(e) =>
setNewFormState((prev) => ({
...prev,
nameForm: e.target.value,
}))
}
/>
</FormControl>
<Divider style={{ marginTop: '0.5rem', marginBottom: '0.5rem' }} />
<div className="flex items-center gap-3">
<CustomCheckbox
checked={newFormState.needBasis}
onChange={(e) => {
setNewFormState((prev) => ({
...prev,
needBasis: e.target.checked ? true : false,
}));
}}
/>
<div className="leading-tight">
<div
className="font-medium"
style={{ fontSize: '1rem', color: '#1F1F1F' }}
>
Создать на основе существующей формы
</div>
<div
className="text-gray-500 mt-1"
style={{ fontSize: '0.9rem' }}
>
Вы можете дублировать и редактировать существующую форму
</div>
</div>
</div>
{newFormState.needBasis && (
<FormControl fullWidth>
<FormLabel required>Форма</FormLabel>
<Autocomplete
size="small"
options={newFormState.basisForSelect}
noOptionsText="Не найдено"
getOptionLabel={(option) => option.name || ''}
value={
newFormState.basisForSelect.find(
(item) => item.id === newFormState.basis,
) || null
}
onChange={(event, newValue) => {
setNewFormState((prev) => ({
...prev,
basis: newValue ? newValue.id : false,
}));
}}
slotProps={{
popper: {
style: { zIndex: 60 },
},
}}
renderInput={(params) => (
<TextField
{...params}
placeholder="Не выбрана"
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: 'rgba(0,0,0,0.1)',
},
},
}}
/>
)}
/>
</FormControl>
)}
</div>
</Modal>
</PageContainer>
);
}