feat: add collection action and release edit toasts

fix: misaligned posters in add release to collection modal
fix: collection releases reset when searching for new release to add
This commit is contained in:
Kentai Radiquum 2025-03-21 01:25:27 +05:00
parent b7661f47ef
commit 3aa71acad5
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
2 changed files with 140 additions and 22 deletions

View file

@ -1,9 +1,11 @@
"use client";
import { Card, Button } from "flowbite-react";
import { Card, Button, useThemeMode } from "flowbite-react";
import { useState } from "react";
import { useUserStore } from "#/store/auth";
import { ENDPOINTS } from "#/api/config";
import { useRouter } from "next/navigation";
import { tryCatchAPI } from "#/api/utils";
import { toast } from "react-toastify";
export const CollectionInfoControls = (props: {
isFavorite: boolean;
@ -12,36 +14,124 @@ export const CollectionInfoControls = (props: {
isPrivate: boolean;
}) => {
const [isFavorite, setIsFavorite] = useState(props.isFavorite);
const [isUpdating, setIsUpdating] = useState(false);
const theme = useThemeMode();
const userStore = useUserStore();
const router = useRouter();
async function _addToFavorite() {
if (userStore.user) {
setIsFavorite(!isFavorite);
if (isFavorite) {
fetch(
`${ENDPOINTS.collection.favoriteCollections}/delete/${props.id}?token=${userStore.token}`
);
} else {
fetch(
`${ENDPOINTS.collection.favoriteCollections}/add/${props.id}?token=${userStore.token}`
);
async function _FavCol(url: string) {
setIsUpdating(true);
const tid = toast.loading(
isFavorite ?
"Удаляем коллекцию из избранного..."
: "Добавляем коллекцию в избранное...",
{
position: "bottom-center",
hideProgressBar: true,
closeOnClick: false,
pauseOnHover: false,
draggable: false,
theme: theme.mode == "light" ? "light" : "dark",
}
);
const { data, error } = await tryCatchAPI(fetch(url));
if (error) {
toast.update(tid, {
render:
isFavorite ?
"Ошибка удаления коллекции из избранного"
: "Ошибка добавления коллекции в избранное",
type: "error",
autoClose: 2500,
isLoading: false,
closeOnClick: true,
draggable: true,
});
setIsUpdating(false);
return;
}
toast.update(tid, {
render:
isFavorite ?
"Коллекция удалена из избранного"
: "Коллекция добавлена в избранное",
type: "success",
autoClose: 2500,
isLoading: false,
closeOnClick: true,
draggable: true,
});
setIsUpdating(false);
setIsFavorite(!isFavorite);
}
if (userStore.token) {
let url = `${ENDPOINTS.collection.favoriteCollections}/add/${props.id}?token=${userStore.token}`;
if (isFavorite) {
url = `${ENDPOINTS.collection.favoriteCollections}/delete/${props.id}?token=${userStore.token}`;
}
_FavCol(url);
}
}
async function _deleteCollection() {
if (userStore.user) {
fetch(
async function _DelCol(url: string) {
setIsUpdating(true);
const tid = toast.loading("Удаляем коллекцию...", {
position: "bottom-center",
hideProgressBar: true,
closeOnClick: false,
pauseOnHover: false,
draggable: false,
theme: theme.mode == "light" ? "light" : "dark",
});
const { data, error } = await tryCatchAPI(fetch(url));
if (error) {
toast.update(tid, {
render: "Ошибка удаления коллекции",
type: "error",
autoClose: 2500,
isLoading: false,
closeOnClick: true,
draggable: true,
});
setIsUpdating(false);
return;
}
toast.update(tid, {
render: `Коллекция удалена`,
type: "success",
autoClose: 2500,
isLoading: false,
closeOnClick: true,
draggable: true,
});
setIsUpdating(false);
router.push("/collections");
}
if (userStore.token) {
_DelCol(
`${ENDPOINTS.collection.delete}/${props.id}?token=${userStore.token}`
);
router.push("/collections");
}
}
return (
<Card className="w-full h-fit ">
<Button color={"blue"} onClick={() => _addToFavorite()}>
<Button
color={"blue"}
onClick={() => _addToFavorite()}
disabled={isUpdating}
>
<span
className={`iconify w-6 h-6 mr-2 ${
isFavorite ? "mdi--heart" : "mdi--heart-outline"
@ -60,6 +150,7 @@ export const CollectionInfoControls = (props: {
onClick={() =>
router.push("/collections/create?mode=edit&id=" + props.id)
}
disabled={isUpdating}
>
<span className="w-6 h-6 mr-2 iconify mdi--pencil"></span>{" "}
Редактировать
@ -68,6 +159,7 @@ export const CollectionInfoControls = (props: {
color={"red"}
className="w-full sm:max-w-64"
onClick={() => _deleteCollection()}
disabled={isUpdating}
>
<span className="w-6 h-6 mr-2 iconify mdi--trash"></span> Удалить
</Button>

View file

@ -213,7 +213,10 @@ export const CreateCollectionPage = () => {
}
toast.update(tid, {
render: mode === "edit" ? `Коллекция ${collectionInfo.title} обновлена` : `Коллекция ${collectionInfo.title} создана`,
render:
mode === "edit" ?
`Коллекция ${collectionInfo.title} обновлена`
: `Коллекция ${collectionInfo.title} создана`,
type: "success",
autoClose: 2500,
isLoading: false,
@ -511,12 +514,31 @@ export const ReleasesEditModal = (props: {
function _addRelease(release: any) {
if (props.releasesIds.length == 100) {
alert("Достигнуто максимальное количество релизов в коллекции - 100");
toast.error(
"Достигнуто максимальное количество релизов в коллекции - 100",
{
position: "bottom-center",
hideProgressBar: true,
type: "error",
autoClose: 2500,
isLoading: false,
closeOnClick: true,
draggable: true,
}
);
return;
}
if (props.releasesIds.includes(release.id)) {
alert("Релиз уже добавлен в коллекцию");
toast.error("Релиз уже добавлен в коллекцию", {
position: "bottom-center",
hideProgressBar: true,
type: "error",
autoClose: 2500,
isLoading: false,
closeOnClick: true,
draggable: true,
});
return;
}
@ -541,7 +563,7 @@ export const ReleasesEditModal = (props: {
className="max-w-full mx-auto"
onSubmit={(e) => {
e.preventDefault();
props.setReleases([]);
setContent([]);
setQuery(e.target[0].value.trim());
}}
>
@ -586,12 +608,12 @@ export const ReleasesEditModal = (props: {
</div>
</form>
<div className="flex flex-wrap gap-1 mt-2">
<div className="grid grid-cols-2 gap-2 mt-2 md:grid-cols-4">
{content.map((release) => {
return (
<button
key={release.id}
className=""
className="overflow-hidden"
onClick={() => _addRelease(release)}
>
<ReleaseLink type="poster" {...release} isLinkDisabled={true} />
@ -600,7 +622,11 @@ export const ReleasesEditModal = (props: {
})}
{content.length == 1 && <div></div>}
</div>
{isLoading && <Spinner />}
{isLoading && (
<div className="flex items-center justify-center h-full min-h-24">
<Spinner />
</div>
)}
{error && <div>Произошла ошибка</div>}
</div>
</Modal>