"use client"; import useSWRInfinite from "swr/infinite"; import { useUserStore } from "#/store/auth"; import { useEffect, useState, useCallback } from "react"; import { useSearchParams, useRouter } from "next/navigation"; import { ENDPOINTS } from "#/api/config"; import { Button, Card, Checkbox, FileInput, Label, Modal, ModalHeader, Textarea, TextInput, useThemeMode, } from "flowbite-react"; import { PosterWithStuff } from "#/components/ReleasePoster/PosterWithStuff"; import { CropModal } from "#/components/CropModal/CropModal"; import { b64toBlob, tryCatchAPI } from "#/api/utils"; import { useSWRfetcher } from "#/api/utils"; import { Spinner } from "#/components/Spinner/Spinner"; import { toast } from "react-toastify"; export const CreateCollectionPage = () => { const userStore = useUserStore(); const searchParams = useSearchParams(); const router = useRouter(); const theme = useThemeMode(); useEffect(() => { if (userStore.state === "finished" && !userStore.token) { router.push("/login?redirect=/collections/create"); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [userStore]); const [edit, setEdit] = useState(false); const [isPrivate, setIsPrivate] = useState(false); const [collectionInfo, setCollectionInfo] = useState({ title: "", description: "", }); const [stringLength, setStringLength] = useState({ title: 0, description: 0, }); const [addedReleases, setAddedReleases] = useState([]); const [addedReleasesIds, setAddedReleasesIds] = useState([]); const [releasesEditModalOpen, setReleasesEditModalOpen] = useState(false); const [imageModalProps, setImageModalProps] = useState({ isOpen: false, isActionsDisabled: false, selectedImage: null, croppedImage: null, }); const [imageUrl, setImageUrl] = useState(null); const collection_id = searchParams.get("id") || null; const mode = searchParams.get("mode") || null; const [isSending, setIsSending] = useState(false); useEffect(() => { async function _checkMode() { if (mode === "edit" && collection_id) { setIsSending(true); const res = await fetch( `${ENDPOINTS.collection.base}/${collection_id}?token=${userStore.token}` ); const data = await res.json(); let addedReleasesIdsArray = []; let addedReleasesArray = []; for (let i = 0; i < 4; i++) { const res = await fetch( `${ENDPOINTS.collection.base}/${collection_id}/releases/${i}?token=${userStore.token}` ); const data = await res.json(); if (data.content.length > 0) { data.content.forEach((release) => { if (!addedReleasesIds.includes(release.id)) { addedReleasesIdsArray.push(release.id); addedReleasesArray.push(release); } }); } else { setAddedReleases(addedReleasesArray); setAddedReleasesIds(addedReleasesIdsArray); break; } } if ( mode === "edit" && userStore.user.id == data.collection.creator.id ) { setEdit(true); setCollectionInfo({ title: data.collection.title, description: data.collection.description, }); setStringLength({ title: data.collection.title.length, description: data.collection.description.length, }); setIsPrivate(data.collection.is_private); setImageUrl(data.collection.image); setIsSending(false); } } } if (userStore.user) { _checkMode(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [userStore.user]); useEffect(() => { if (imageModalProps.croppedImage) { setImageUrl(imageModalProps.croppedImage); setImageModalProps({ isOpen: false, isActionsDisabled: false, selectedImage: null, croppedImage: null, }); } }, [imageModalProps.croppedImage]); const handleImagePreview = (e: any) => { const file = e.target.files[0]; const fileReader = new FileReader(); fileReader.onloadend = () => { const content = fileReader.result; setImageModalProps({ ...imageModalProps, isOpen: true, selectedImage: content, }); e.target.value = ""; }; fileReader.readAsDataURL(file); }; function handleInput(e) { const regex = /[^a-zA-Zа-яА-Я0-9_.,:()!? \[\]]/g; setCollectionInfo({ ...collectionInfo, [e.target.name]: e.target.value.replace(regex, ""), }); setStringLength({ ...stringLength, [e.target.name]: e.target.value.replace(regex, "").length, }); } function submit(e) { e.preventDefault(); async function _createCollection() { setIsSending(true); const tid = toast.loading( mode === "edit" ? "Редактируем коллекцию..." : "Создаём коллекцию...", { position: "bottom-center", hideProgressBar: true, closeOnClick: false, pauseOnHover: false, draggable: false, theme: theme.mode == "light" ? "light" : "dark", } ); const url = mode === "edit" ? `${ENDPOINTS.collection.edit}/${collection_id}?token=${userStore.token}` : `${ENDPOINTS.collection.create}?token=${userStore.token}`; const { data, error } = await tryCatchAPI( fetch(url, { method: "POST", body: JSON.stringify({ ...collectionInfo, is_private: isPrivate, private: isPrivate, releases: addedReleasesIds, }), }) ); if (error) { let message = `${error.message}, code: ${error.code}`; if (error.code == 5) { message = "Вы превысили допустимый еженедельный лимит создания коллекций"; } toast.update(tid, { render: message, type: "error", autoClose: 2500, isLoading: false, closeOnClick: true, draggable: true, }); setIsSending(false); return; } if (imageUrl && !imageUrl.startsWith("http")) { let block = imageUrl.split(";"); let contentType = block[0].split(":")[1]; let realData = block[1].split(",")[1]; const blob = b64toBlob(realData, contentType); const formData = new FormData(); formData.append("image", blob, "cropped.jpg"); formData.append("name", "image"); const tiid = toast.loading( `Обновление обложки коллекции ${collectionInfo.title}...`, { position: "bottom-center", hideProgressBar: true, closeOnClick: false, pauseOnHover: false, draggable: false, theme: theme.mode == "light" ? "light" : "dark", } ); const { data: imageData, error } = await tryCatchAPI( fetch( `${ENDPOINTS.collection.editImage}/${data.collection.id}?token=${userStore.token}`, { method: "POST", body: formData, } ) ); if (error) { toast.update(tiid, { render: "Не удалось обновить постер коллекции", type: "error", autoClose: 2500, isLoading: false, closeOnClick: true, draggable: true, }); } else { toast.update(tiid, { render: "Постер коллекции обновлён", type: "success", autoClose: 2500, isLoading: false, closeOnClick: true, draggable: true, }); } } toast.update(tid, { render: mode === "edit" ? `Коллекция ${collectionInfo.title} обновлена` : `Коллекция ${collectionInfo.title} создана`, type: "success", autoClose: 2500, isLoading: false, closeOnClick: true, draggable: true, }); router.push(`/collection/${data.collection.id}`); setIsSending(false); } if (collectionInfo.title.length < 10) { toast.error("Необходимо ввести название коллекции не менее 10 символов", { position: "bottom-center", hideProgressBar: true, type: "error", autoClose: 2500, isLoading: false, closeOnClick: true, draggable: true, }); return; } if (addedReleasesIds.length < 1) { toast.error("Необходимо добавить хотя бы один релиз в коллекцию", { position: "bottom-center", hideProgressBar: true, type: "error", autoClose: 2500, isLoading: false, closeOnClick: true, draggable: true, }); return; } _createCollection(); } function _deleteRelease(release: any) { let releasesArray = []; let idsArray = []; for (let i = 0; i < addedReleases.length; i++) { if (addedReleases[i].id != release.id) { releasesArray.push(addedReleases[i]); idsArray.push(addedReleasesIds[i]); } } setAddedReleases(releasesArray); setAddedReleasesIds(idsArray); } return ( <>

{edit ? "Редактирование коллекции" : "Создание коллекции"}

submit(e)} >
handleInput(e)} value={collectionInfo.title} maxLength={60} />

{stringLength.title}/60