upload mission modal
This commit is contained in:
@@ -18,7 +18,7 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (status == "successful"){
|
||||
if (status == "successful") {
|
||||
setActive(false);
|
||||
}
|
||||
}, [status]);
|
||||
@@ -27,12 +27,12 @@ const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
<Modal className="bg-liquid-background border-liquid-lighter border-[2px] p-[25px] rounded-[20px] text-liquid-white" onOpenChange={setActive} open={active} backdrop="blur" >
|
||||
<div className="w-[500px]">
|
||||
<div className="font-bold text-[30px]">Создать группу</div>
|
||||
<Input name="name" autocomplete="name" className="mt-[10px]" type="text" label="Название" onChange={(v) => { setName(v)}} placeholder="login" />
|
||||
<Input name="description" autocomplete="description" className="mt-[10px]" type="text" label="Описание" onChange={(v) => { setDescription(v)}} placeholder="login" />
|
||||
<Input name="name" autocomplete="name" className="mt-[10px]" type="text" label="Название" onChange={(v) => { setName(v) }} placeholder="login" />
|
||||
<Input name="description" autocomplete="description" className="mt-[10px]" type="text" label="Описание" onChange={(v) => { setDescription(v) }} placeholder="login" />
|
||||
|
||||
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">
|
||||
<PrimaryButton onClick={() => {dispatch(createGroup({name, description}))}} text="Создать" disabled={status=="loading"}/>
|
||||
<SecondaryButton onClick={() => {setActive(false);}} text="Отмена" />
|
||||
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">
|
||||
<PrimaryButton onClick={() => { dispatch(createGroup({ name, description })) }} text="Создать" disabled={status == "loading"} />
|
||||
<SecondaryButton onClick={() => { setActive(false); }} text="Отмена" />
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import MissionItem from "./MissionItem";
|
||||
import { SecondaryButton } from "../../../components/button/SecondaryButton";
|
||||
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { setMenuActivePage } from "../../../redux/slices/store";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { fetchMissions } from "../../../redux/slices/missions";
|
||||
import ModalCreate from "./ModalCreate";
|
||||
|
||||
|
||||
export interface Mission {
|
||||
@@ -22,7 +23,7 @@ export interface Mission {
|
||||
const Missions = () => {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const naivgate = useNavigate();
|
||||
const [modalActive, setModalActive] = useState<boolean>(false);
|
||||
|
||||
const missions = useAppSelector((state) => state.missions.missions);
|
||||
|
||||
@@ -41,8 +42,8 @@ const Missions = () => {
|
||||
Задачи
|
||||
</div>
|
||||
<SecondaryButton
|
||||
onClick={() => {naivgate("/upload")}}
|
||||
text="Создать задачу"
|
||||
onClick={() => {setModalActive(true)}}
|
||||
text="Добавить задачу"
|
||||
className="absolute right-0"
|
||||
/>
|
||||
</div>
|
||||
@@ -75,6 +76,8 @@ const Missions = () => {
|
||||
pages
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ModalCreate setActive={setModalActive} active={modalActive} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
160
src/views/home/missions/ModalCreate.tsx
Normal file
160
src/views/home/missions/ModalCreate.tsx
Normal file
@@ -0,0 +1,160 @@
|
||||
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';
|
||||
|
||||
interface ModalCreateProps {
|
||||
active: boolean;
|
||||
setActive: (value: boolean) => void;
|
||||
}
|
||||
|
||||
const ModalCreate: FC<ModalCreateProps> = ({ active, setActive }) => {
|
||||
const [name, setName] = useState<string>('');
|
||||
const [difficulty, setDifficulty] = useState<number>(1);
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [tagInput, setTagInput] = useState<string>('');
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
|
||||
const status = useAppSelector((state) => state.missions.statuses.upload);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const addTag = () => {
|
||||
const newTag = tagInput.trim();
|
||||
if (newTag && !tags.includes(newTag)) {
|
||||
setTags([...tags, newTag]);
|
||||
setTagInput('');
|
||||
}
|
||||
};
|
||||
|
||||
const removeTag = (tagToRemove: string) => {
|
||||
setTags(tags.filter((tag) => tag !== tagToRemove));
|
||||
};
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files && e.target.files[0]) {
|
||||
setFile(e.target.files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!file) return alert('Выберите файл миссии!');
|
||||
dispatch(uploadMission({ file, name, difficulty, tags }));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'successful') {
|
||||
alert('Миссия успешно загружена!');
|
||||
setName('');
|
||||
setDifficulty(1);
|
||||
setTags([]);
|
||||
setFile(null);
|
||||
dispatch(setMissionsStatus({ key: 'upload', status: 'idle' }));
|
||||
setActive(false);
|
||||
}
|
||||
}, [status]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="bg-liquid-background border-liquid-lighter border-[2px] p-[25px] rounded-[20px] text-liquid-white"
|
||||
onOpenChange={setActive}
|
||||
open={active}
|
||||
backdrop="blur"
|
||||
>
|
||||
<div className="w-[500px]">
|
||||
<div className="font-bold text-[30px]">Добавить задачу</div>
|
||||
|
||||
<Input
|
||||
name="name"
|
||||
autocomplete="name"
|
||||
className="mt-[10px]"
|
||||
type="text"
|
||||
label="Название"
|
||||
defaultState={name}
|
||||
onChange={setName}
|
||||
placeholder="В яблочко"
|
||||
/>
|
||||
|
||||
<Input
|
||||
name="difficulty"
|
||||
autocomplete="difficulty"
|
||||
className="mt-[10px]"
|
||||
type="number"
|
||||
label="Сложность"
|
||||
defaultState={'' + difficulty}
|
||||
onChange={(v) => setDifficulty(Number(v))}
|
||||
placeholder="1"
|
||||
/>
|
||||
|
||||
<div className="mt-4">
|
||||
<label className="block mb-2">Файл задачи</label>
|
||||
<input
|
||||
type="file"
|
||||
onChange={handleFileChange}
|
||||
accept=".zip"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Теги */}
|
||||
<div className="mb-[50px] max-w-[600px]">
|
||||
<div className="grid grid-cols-[1fr,140px] items-end gap-2">
|
||||
<Input
|
||||
name="articleTag"
|
||||
autocomplete="articleTag"
|
||||
className="mt-[20px] max-w-[600px]"
|
||||
type="text"
|
||||
label="Теги"
|
||||
onChange={(v) => setTagInput(v)}
|
||||
defaultState={tagInput}
|
||||
placeholder="arrays"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') addTag();
|
||||
}}
|
||||
/>
|
||||
<PrimaryButton
|
||||
onClick={addTag}
|
||||
text="Добавить"
|
||||
className="h-[40px] w-[140px]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-[10px] mt-2">
|
||||
{tags.map((tag) => (
|
||||
<div
|
||||
key={tag}
|
||||
className="flex items-center gap-1 bg-liquid-lighter px-3 py-1 rounded-full"
|
||||
>
|
||||
<span>{tag}</span>
|
||||
<button
|
||||
onClick={() => removeTag(tag)}
|
||||
className="text-liquid-red font-bold ml-[5px]"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">
|
||||
<PrimaryButton
|
||||
onClick={handleSubmit}
|
||||
text={status === 'loading' ? 'Загрузка...' : 'Создать'}
|
||||
disabled={status === 'loading'}
|
||||
/>
|
||||
<SecondaryButton
|
||||
onClick={() => setActive(false)}
|
||||
text="Отмена"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalCreate;
|
||||
Reference in New Issue
Block a user