mirror of
https://github.com/Radiquum/AniX.git
synced 2025-04-05 07:44:38 +00:00
feat: add collection create\edit api request
This commit is contained in:
parent
5cde53c1d3
commit
9f3ca2e6d9
4 changed files with 140 additions and 48 deletions
|
@ -1,6 +1,7 @@
|
|||
import { NextResponse, NextRequest } from "next/server";
|
||||
import { fetchDataViaGet, fetchDataViaPost } from "../utils";
|
||||
import { API_URL } from "../config";
|
||||
import { buffer } from "stream/consumers";
|
||||
|
||||
export async function GET(
|
||||
req: NextRequest,
|
||||
|
@ -25,14 +26,24 @@ export async function POST(
|
|||
) {
|
||||
const { endpoint } = params;
|
||||
let API_V2: boolean | string =
|
||||
req.nextUrl.searchParams.get("API_V2") || false;
|
||||
req.nextUrl.searchParams.get("API_V2") || false;
|
||||
if (API_V2 === "true") {
|
||||
req.nextUrl.searchParams.delete("API_V2");
|
||||
}
|
||||
const query = req.nextUrl.searchParams.toString();
|
||||
const url = `${API_URL}/${endpoint.join("/")}${query ? `?${query}` : ""}`;
|
||||
const body = JSON.stringify( await req.json());
|
||||
let body;
|
||||
const ReqContentTypeHeader = req.headers.get("Content-Type") || "";
|
||||
let ResContentTypeHeader = "";
|
||||
|
||||
const response = await fetchDataViaPost(url, body, API_V2);
|
||||
if (ReqContentTypeHeader.split(";")[0] == "multipart/form-data") {
|
||||
ResContentTypeHeader = ReqContentTypeHeader;
|
||||
body = await req.arrayBuffer();
|
||||
} else {
|
||||
ResContentTypeHeader = "application/json; charset=UTF-8";
|
||||
body = JSON.stringify(await req.json());
|
||||
}
|
||||
|
||||
const response = await fetchDataViaPost(url, body, API_V2, ResContentTypeHeader);
|
||||
return NextResponse.json(response);
|
||||
}
|
||||
|
|
|
@ -28,11 +28,16 @@ export const fetchDataViaGet = async (
|
|||
export const fetchDataViaPost = async (
|
||||
url: string,
|
||||
body: string,
|
||||
API_V2: string | boolean = false
|
||||
API_V2: string | boolean = false,
|
||||
contentType: string = ""
|
||||
) => {
|
||||
if (API_V2) {
|
||||
HEADERS["API-Version"] = "v2";
|
||||
}
|
||||
if (contentType != "") {
|
||||
HEADERS["Content-Type"] = contentType;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
|
|
|
@ -2,13 +2,11 @@ import React, { useRef } from "react";
|
|||
import Cropper, { ReactCropperElement } from "react-cropper";
|
||||
import "cropperjs/dist/cropper.css";
|
||||
import { Button, Modal } from "flowbite-react";
|
||||
import { b64toBlob } from "#/api/utils";
|
||||
|
||||
type Props = {
|
||||
src: string;
|
||||
setSrc: (src: string) => void;
|
||||
setTempSrc: (src: string) => void;
|
||||
setImageData: (src: string) => void;
|
||||
isOpen: boolean;
|
||||
setIsOpen: (isOpen: boolean) => void;
|
||||
height: number;
|
||||
|
@ -24,36 +22,16 @@ export const CropModal: React.FC<Props> = (props) => {
|
|||
|
||||
const getCropData = () => {
|
||||
if (typeof cropperRef.current?.cropper !== "undefined") {
|
||||
props.setSrc(cropperRef.current?.cropper.getCroppedCanvas().toDataURL());
|
||||
|
||||
let block = cropperRef.current?.cropper
|
||||
.getCroppedCanvas({
|
||||
width: props.width,
|
||||
height: props.height,
|
||||
maxWidth: props.width,
|
||||
maxHeight: props.height,
|
||||
})
|
||||
.toDataURL("image/jpeg", props.quality)
|
||||
.split(";");
|
||||
let contentType = block[0].split(":")[1];
|
||||
let realData = block[1].split(",")[1];
|
||||
|
||||
const blob = b64toBlob(realData, contentType);
|
||||
|
||||
const handleFileRead = (e, fileReader) => {
|
||||
const content = fileReader.result;
|
||||
props.setImageData(content);
|
||||
};
|
||||
|
||||
const handleFileText = (file) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onloadend = (e) => {
|
||||
handleFileRead(e, fileReader);
|
||||
};
|
||||
fileReader.readAsText(file);
|
||||
};
|
||||
|
||||
handleFileText(blob);
|
||||
props.setSrc(
|
||||
cropperRef.current?.cropper
|
||||
.getCroppedCanvas({
|
||||
width: props.width,
|
||||
height: props.height,
|
||||
maxWidth: props.width,
|
||||
maxHeight: props.height,
|
||||
})
|
||||
.toDataURL("image/jpeg", props.quality)
|
||||
);
|
||||
props.setTempSrc("");
|
||||
}
|
||||
};
|
||||
|
@ -103,7 +81,7 @@ export const CropModal: React.FC<Props> = (props) => {
|
|||
onClick={() => {
|
||||
props.setSrc(null);
|
||||
props.setTempSrc(null);
|
||||
props.setImageData(null);
|
||||
// props.setImageData(null);
|
||||
props.setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"use client";
|
||||
import useSWR from "swr";
|
||||
import useSWRInfinite from "swr/infinite";
|
||||
import { useUserStore } from "#/store/auth";
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
|
@ -17,6 +16,7 @@ import {
|
|||
} from "flowbite-react";
|
||||
import { ReleaseLink } from "#/components/ReleaseLink/ReleaseLink";
|
||||
import { CropModal } from "#/components/CropModal/CropModal";
|
||||
import { b64toBlob } from "#/api/utils";
|
||||
|
||||
const fetcher = async (url: string) => {
|
||||
const res = await fetch(url);
|
||||
|
@ -39,7 +39,7 @@ export const CreateCollectionPage = () => {
|
|||
|
||||
const [edit, setEdit] = useState(false);
|
||||
|
||||
const [imageData, setImageData] = useState<string>(null);
|
||||
// const [imageData, setImageData] = useState<File | Blob>(null);
|
||||
const [imageUrl, setImageUrl] = useState<string>(null);
|
||||
const [tempImageUrl, setTempImageUrl] = useState<string>(null);
|
||||
const [isPrivate, setIsPrivate] = useState(false);
|
||||
|
@ -59,19 +59,59 @@ export const CreateCollectionPage = () => {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,13 +148,65 @@ export const CreateCollectionPage = () => {
|
|||
function submit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
console.log(collectionInfo.title.length);
|
||||
async function _createCollection() {
|
||||
const url =
|
||||
mode === "edit"
|
||||
? `${ENDPOINTS.collection.edit}/${collection_id}?token=${userStore.token}`
|
||||
: `${ENDPOINTS.collection.create}?token=${userStore.token}`;
|
||||
|
||||
console.log({
|
||||
...collectionInfo,
|
||||
private: isPrivate,
|
||||
image: imageData,
|
||||
});
|
||||
const res = await fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
...collectionInfo,
|
||||
is_private: isPrivate,
|
||||
private: isPrivate,
|
||||
releases: addedReleasesIds,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (data.code == 5) {
|
||||
alert("Вы превысили допустимый еженедельный лимит создания коллекций!");
|
||||
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 uploadRes = await fetch(
|
||||
`${ENDPOINTS.collection.editImage}/${data.collection.id}?token=${userStore.token}`,
|
||||
{
|
||||
method: "POST",
|
||||
body: formData,
|
||||
}
|
||||
);
|
||||
const uploadData = await uploadRes.json();
|
||||
}
|
||||
|
||||
router.push(`/collection/${data.collection.id}`);
|
||||
}
|
||||
|
||||
if (
|
||||
collectionInfo.title.length >= 10 &&
|
||||
addedReleasesIds.length >= 1 &&
|
||||
userStore.token
|
||||
) {
|
||||
// setIsSending(true);
|
||||
_createCollection();
|
||||
} else if (collectionInfo.title.length < 10) {
|
||||
alert("Необходимо ввести название коллекции не менее 10 символов");
|
||||
} else if (!userStore.token) {
|
||||
alert("Для создания коллекции необходимо войти в аккаунт");
|
||||
} else if (addedReleasesIds.length < 1) {
|
||||
alert("Необходимо добавить хотя бы один релиз в коллекцию");
|
||||
}
|
||||
}
|
||||
|
||||
function _deleteRelease(release: any) {
|
||||
|
@ -233,13 +325,19 @@ export const CreateCollectionPage = () => {
|
|||
<Checkbox
|
||||
id="private"
|
||||
name="private"
|
||||
color="blue"
|
||||
checked={isPrivate}
|
||||
onChange={(e) => setIsPrivate(e.target.checked)}
|
||||
/>
|
||||
<Label htmlFor="private" value="Приватная коллекция" />
|
||||
</div>
|
||||
</div>
|
||||
<Button color={"blue"} className="mt-4" type="submit">
|
||||
<Button
|
||||
color={"blue"}
|
||||
className="mt-4"
|
||||
type="submit"
|
||||
disabled={isSending}
|
||||
>
|
||||
{edit ? "Обновить" : "Создать"}
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -292,10 +390,10 @@ export const CreateCollectionPage = () => {
|
|||
src={tempImageUrl}
|
||||
setSrc={setImageUrl}
|
||||
setTempSrc={setTempImageUrl}
|
||||
setImageData={setImageData}
|
||||
// setImageData={setImageData}
|
||||
aspectRatio={600 / 337}
|
||||
guides={false}
|
||||
quality={0.9}
|
||||
quality={100}
|
||||
isOpen={cropModalOpen}
|
||||
setIsOpen={setCropModalOpen}
|
||||
forceAspect={true}
|
||||
|
|
Loading…
Add table
Reference in a new issue