import { FC, useEffect, useState } from 'react'; import { Modal } from '../../../components/modal/Modal'; import { PrimaryButton } from '../../../components/button/PrimaryButton'; import { SecondaryButton } from '../../../components/button/SecondaryButton'; import { Input } from '../../../components/input/Input'; import { useAppDispatch, useAppSelector } from '../../../redux/hooks'; import { setMissionsStatus, uploadMission, } from '../../../redux/slices/missions'; import { toastSuccess } from '../../../lib/toastNotification'; import { cn } from '../../../lib/cn'; import { Link } from 'react-router-dom'; import { NumberInput } from '../../../components/input/NumberInput'; import { DropDownList, DropDownListItem } from '../../../components/input/DropDownList'; interface ModalCreateProps { active: boolean; setActive: (value: boolean) => void; } const ModalCreate: FC = ({ active, setActive }) => { type TagsMode = 'fromArchive' | 'none' | 'custom'; const [difficulty, setDifficulty] = useState(1); const [file, setFile] = useState(null); const [tagInput, setTagInput] = useState(''); const [tags, setTags] = useState([]); const [tagsMode, setTagsMode] = useState('fromArchive'); const status = useAppSelector((state) => state.missions.statuses.upload); const dispatch = useAppDispatch(); const [clickSubmit, setClickSubmit] = useState(false); const normalizeTags = (raw: string[]): string[] => { const result: string[] = []; const seen = new Set(); for (const t of raw) { const trimmed = t.trim(); if (!trimmed) continue; const key = trimmed.toLowerCase(); if (seen.has(key)) continue; seen.add(key); result.push(trimmed); } return result; }; const addTag = () => { const parts = tagInput.split(',').map((v) => v.trim()); const next = normalizeTags([...tags, ...parts]); setTags(next); setTagInput(''); }; const removeTag = (tagToRemove: string) => { setTags(tags.filter((tag) => tag !== tagToRemove)); }; const handleFileChange = (e: React.ChangeEvent) => { if (e.target.files && e.target.files[0]) { setFile(e.target.files[0]); } }; const handleSubmit = async () => { setClickSubmit(true); if (!file) return; const payloadTags = tagsMode === 'custom' ? normalizeTags(tags) : undefined; dispatch( uploadMission({ missionFile: file, difficulty, tags: payloadTags, }), ); }; useEffect(() => { if (status === 'successful') { toastSuccess('Миссия создана!'); setDifficulty(1); setTags([]); setFile(null); setTagInput(''); setTagsMode('fromArchive'); dispatch(setMissionsStatus({ key: 'upload', status: 'idle' })); setActive(false); } }, [status]); useEffect(() => { if (active == true) { setClickSubmit(false); } dispatch(setMissionsStatus({ key: 'upload', status: 'idle' })); }, [active]); const getDifficultyErrorMessage = (): string => { if (!clickSubmit) return ''; if (!Number.isFinite(difficulty) || difficulty < 1) return 'Укажите сложность (минимум 1)'; return ''; }; const tagsModeItems: DropDownListItem[] = [ { text: 'Теги: из архива', value: 'fromArchive' }, { text: 'Теги: без тегов', value: 'none' }, { text: 'Теги: свои', value: 'custom' }, ]; const isTagsMode = (v: string): v is TagsMode => v === 'fromArchive' || v === 'none' || v === 'custom'; const currentTagsModeItem = tagsModeItems.find((i) => i.value === tagsMode) ?? tagsModeItems[0]; useEffect(() => { if (tagsMode === 'none') { setTags([]); setTagInput(''); } }, [tagsMode]); return (
Добавить задачу
setDifficulty(v)} placeholder="1" error={getDifficultyErrorMessage()} />
{
Необходимо выбрать файл задачи
}
{/* Теги */}
Режим тегов
{ if (isTagsMode(v)) setTagsMode(v); }} weight="w-full" /> {tagsMode === 'none' && (
Пустой список тегов сейчас не поддерживается в multipart. Будет использован режим “из архива”.
)}
{tagsMode === 'custom' && ( <>
setTagInput(v)} defaultState={tagInput} placeholder="arrays, dp" onKeyDown={(e) => { if (e.key === 'Enter') addTag(); }} />
{tags.map((tag) => (
{tag}
))}
)}
Создать пакет задачи можно на платформе{' '} polygon
setActive(false)} text="Отмена" />
); }; export default ModalCreate;