upd
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ChangeEvent, useEffect, useState } from "react";
|
||||
import api from "../../utils/api";
|
||||
import Button from "../Button";
|
||||
import IProject from "../../types/IProject";
|
||||
import useModalStore from "../../stores/useModalStore";
|
||||
|
||||
interface EditProjectModalProps {
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
function EditProjectModal({ projectId }: EditProjectModalProps) {
|
||||
const [project, setProject] = useState<IProject>({
|
||||
name: "",
|
||||
company: "",
|
||||
city: "",
|
||||
image: "",
|
||||
devices: [],
|
||||
});
|
||||
|
||||
const [file, setFile] = useState<File>();
|
||||
const [previewFile, setPreviewFile] = useState<string>();
|
||||
const [setModal] = useModalStore((state) => [state.setModal]);
|
||||
|
||||
function handleChangeFile(e: ChangeEvent<HTMLInputElement>) {
|
||||
if (!e.target.files) return;
|
||||
|
||||
const targetFile = e.target.files[0];
|
||||
|
||||
setFile(targetFile);
|
||||
setPreviewFile(URL.createObjectURL(targetFile));
|
||||
}
|
||||
|
||||
async function uploadFile() {
|
||||
if (!file) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
try {
|
||||
const { file }: { file: string } = await api
|
||||
.post("upload", { body: formData })
|
||||
.json();
|
||||
|
||||
setProject((prev) => ({ ...prev, image: file }));
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(`Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateProject() {
|
||||
try {
|
||||
await api.put(`projects/${projectId}`, { json: { ...project } });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(`Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit(e: ChangeEvent<HTMLFormElement>) {
|
||||
e.preventDefault();
|
||||
|
||||
await updateProject();
|
||||
setModal(null);
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
async function getProject() {
|
||||
try {
|
||||
const project: IProject = await api.get(`projects/${projectId}`).json();
|
||||
|
||||
setProject(project);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(`Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
uploadFile();
|
||||
}, [file]);
|
||||
|
||||
useEffect(() => {
|
||||
getProject();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-white shadow-lg text-black p-8 rounded-xl flex flex-col gap-4">
|
||||
<p className="text-xl pb-4 border-b border-[#ccc]">
|
||||
Редактирование проекта
|
||||
</p>
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="grid grid-cols-2 gap-4 w-[512px]"
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-sm">Название</label>
|
||||
<input
|
||||
autoFocus
|
||||
required
|
||||
type="text"
|
||||
placeholder="Название"
|
||||
className="border border-neutral-500 px-3 py-2 rounded-lg outline-none"
|
||||
value={project.name}
|
||||
onChange={(e) =>
|
||||
setProject((prev) => ({ ...prev, name: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-sm">Компания</label>
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
placeholder="Компания"
|
||||
className="border border-neutral-500 px-3 py-2 rounded-lg outline-none"
|
||||
value={project.company}
|
||||
onChange={(e) =>
|
||||
setProject((prev) => ({ ...prev, company: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-sm">Город</label>
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
placeholder="Город"
|
||||
className="border border-neutral-500 px-3 py-2 rounded-lg outline-none"
|
||||
value={project.city}
|
||||
onChange={(e) =>
|
||||
setProject((prev) => ({ ...prev, city: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="relative border border-dashed border-neutral-500 px-3 py-2 hover:bg-opacity-10 hover:bg-black cursor-pointer rounded-lg flex flex-col gap-2">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
className="absolute opacity-0"
|
||||
onChange={handleChangeFile}
|
||||
/>
|
||||
<p>{file ? file.name : "Выберите изображение"}</p>
|
||||
|
||||
{project.image && <img src={project.image} alt="" />}
|
||||
{previewFile && <img src={previewFile} alt="" />}
|
||||
</label>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-sm">Стадия</label>
|
||||
<select
|
||||
required
|
||||
value={project.stage || ""}
|
||||
className="border border-neutral-500 px-3 py-2 rounded-lg outline-none"
|
||||
onChange={(e) =>
|
||||
setProject((prev) => ({ ...prev, stage: +e.target.value }))
|
||||
}
|
||||
>
|
||||
<option value="" disabled>
|
||||
Выберите стадию
|
||||
</option>
|
||||
<option value={1}>1</option>
|
||||
<option value={2}>2</option>
|
||||
<option value={3}>3</option>
|
||||
<option value={4}>4</option>
|
||||
<option value={5}>5</option>
|
||||
<option value={6}>6</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-sm">Год релиза</label>
|
||||
<select
|
||||
required
|
||||
value={project.releaseYear || ""}
|
||||
className="border border-neutral-500 px-3 py-2 rounded-lg outline-none"
|
||||
onChange={(e) =>
|
||||
setProject((prev) => ({ ...prev, releaseYear: +e.target.value }))
|
||||
}
|
||||
>
|
||||
<option value="" disabled>
|
||||
Выберите год релиза
|
||||
</option>
|
||||
<option value={2024}>2024</option>
|
||||
<option value={2023}>2023</option>
|
||||
<option value={2022}>2022</option>
|
||||
<option value={2021}>2021</option>
|
||||
<option value={2020}>2020</option>
|
||||
<option value={2019}>2019</option>
|
||||
<option value={2018}>2018</option>
|
||||
<option value={2017}>2017</option>
|
||||
<option value={2016}>2016</option>
|
||||
<option value={2015}>2015</option>
|
||||
<option value={2014}>2014</option>
|
||||
<option value={2013}>2013</option>
|
||||
<option value={2012}>2012</option>
|
||||
<option value={2011}>2011</option>
|
||||
<option value={2010}>2010</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm">Девайсы</p>
|
||||
<div className="">
|
||||
<label className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={project.devices!.includes("stream")}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setProject((prev) => ({
|
||||
...prev,
|
||||
devices: [...prev.devices!, "stream"],
|
||||
}));
|
||||
} else {
|
||||
setProject((prev) => ({
|
||||
...prev,
|
||||
devices: prev.devices!.filter(
|
||||
(device) => device !== "stream"
|
||||
),
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span>Stream</span>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={project.devices!.includes("touch")}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setProject((prev) => ({
|
||||
...prev,
|
||||
devices: [...prev.devices!, "touch"],
|
||||
}));
|
||||
} else {
|
||||
setProject((prev) => ({
|
||||
...prev,
|
||||
devices: prev.devices!.filter(
|
||||
(device) => device !== "touch"
|
||||
),
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span>Touch</span>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={project.devices!.includes("mobile")}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setProject((prev) => ({
|
||||
...prev,
|
||||
devices: [...prev.devices!, "mobile"],
|
||||
}));
|
||||
} else {
|
||||
setProject((prev) => ({
|
||||
...prev,
|
||||
devices: prev.devices!.filter(
|
||||
(device) => device !== "mobile"
|
||||
),
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span>Mobile</span>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={project.devices!.includes("vr")}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setProject((prev) => ({
|
||||
...prev,
|
||||
devices: [...prev.devices!, "vr"],
|
||||
}));
|
||||
} else {
|
||||
setProject((prev) => ({
|
||||
...prev,
|
||||
devices: prev.devices!.filter(
|
||||
(device) => device !== "vr"
|
||||
),
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span>VR</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-span-full flex justify-end">
|
||||
<Button className="text-white outline-none">
|
||||
Сохранить изменения
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditProjectModal;
|
||||
Reference in New Issue
Block a user