mirror of
https://github.com/Radiquum/YAMPD.git
synced 2025-05-20 15:49:34 +05:00
feat: pack creating
This commit is contained in:
parent
5be021789b
commit
af7b8a6fea
27 changed files with 677 additions and 130 deletions
221
gui/app/pack/new/page.tsx
Normal file
221
gui/app/pack/new/page.tsx
Normal file
|
@ -0,0 +1,221 @@
|
|||
"use client";
|
||||
|
||||
import { Card, FileInput } from "flowbite-react";
|
||||
import { Label, TextInput, Select } from "flowbite-react";
|
||||
import { useState } from "react";
|
||||
import { HiUser, HiAnnotation } from "react-icons/hi";
|
||||
import { Button } from "flowbite-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import mc from "../../../api/mc_version.json";
|
||||
import { ENDPOINTS, PACK_IMG_ENDPOINTS } from "@/api/ENDPOINTS";
|
||||
import { toast } from "react-toastify";
|
||||
const mcr = mc.reverse();
|
||||
|
||||
export default function PackNew() {
|
||||
const router = useRouter()
|
||||
const [image, setImage] = useState<null | string>(null);
|
||||
const [imageMime, setImageMime] = useState<null | string>(null);
|
||||
const [packInfo, setPackInfo] = useState({
|
||||
title: "",
|
||||
author: "",
|
||||
modloader: "Forge",
|
||||
version: "1.21.5",
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const handleImagePreview = (e: any) => {
|
||||
const file = e.target.files[0];
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onloadend = () => {
|
||||
const content = fileReader.result;
|
||||
setImage(content as string);
|
||||
setImageMime(file.type);
|
||||
e.target.value = "";
|
||||
};
|
||||
fileReader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function handleInput(e: any) {
|
||||
const regex = /[^a-zA-Zа-яА-Я0-9_.()\- \[\]]/g;
|
||||
setPackInfo({
|
||||
...packInfo,
|
||||
[e.target.name]: e.target.value.replace(regex, ""),
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function submit(e: any) {
|
||||
e.preventDefault();
|
||||
|
||||
async function _submit() {
|
||||
const tid = toast.loading(`Creating Pack "${packInfo.title}"`)
|
||||
|
||||
const res = await fetch(`${ENDPOINTS.createPack}`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(packInfo),
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
accept: "application/json",
|
||||
},
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
if (data.status != "ok") {
|
||||
toast.update(tid, {render: data.message, type: "error", isLoading: false})
|
||||
return;
|
||||
}
|
||||
|
||||
if (image) {
|
||||
await fetch(`${PACK_IMG_ENDPOINTS("editPackImage", data.id)}`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
image: image,
|
||||
mimetype: imageMime
|
||||
}),
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
accept: "application/json",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
toast.update(tid, {render: data.message, type: "success", isLoading: false})
|
||||
router.push(`/pack/${data.id}`)
|
||||
}
|
||||
|
||||
_submit();
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="w-full">
|
||||
<form
|
||||
className="flex flex-col gap-4"
|
||||
encType="multipart/form-data"
|
||||
onSubmit={(e) => submit(e)}
|
||||
>
|
||||
<div className="flex w-full items-center justify-center">
|
||||
<Label
|
||||
htmlFor="dropzone-file"
|
||||
className="flex h-64 w-full cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:hover:border-gray-500 dark:hover:bg-gray-600"
|
||||
>
|
||||
{image ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img src={image} alt="preview" className="overflow-hidden" />
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center pb-6 pt-5">
|
||||
<svg
|
||||
className="mb-4 h-8 w-8 text-gray-500 dark:text-gray-400"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 20 16"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"
|
||||
/>
|
||||
</svg>
|
||||
<p className="mb-2 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span className="font-semibold">Click to upload</span> or drag
|
||||
and drop
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
PNG or JPG
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<FileInput
|
||||
id="dropzone-file"
|
||||
className="hidden"
|
||||
name="image"
|
||||
onChange={(e) => handleImagePreview(e)}
|
||||
/>
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="mb-2 block">
|
||||
<Label htmlFor="base" className="text-lg">
|
||||
Title
|
||||
</Label>
|
||||
</div>
|
||||
<TextInput
|
||||
id="base"
|
||||
type="text"
|
||||
sizing="md"
|
||||
name="title"
|
||||
onChange={(e) => handleInput(e)}
|
||||
value={packInfo.title}
|
||||
icon={HiAnnotation}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="mb-2 block">
|
||||
<Label htmlFor="base" className="text-lg">
|
||||
Author
|
||||
</Label>
|
||||
</div>
|
||||
<TextInput
|
||||
id="base"
|
||||
type="text"
|
||||
sizing="md"
|
||||
name="author"
|
||||
onChange={(e) => handleInput(e)}
|
||||
value={packInfo.author}
|
||||
icon={HiUser}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="mb-2 block">
|
||||
<Label htmlFor="base" className="text-lg">
|
||||
Mod Loader
|
||||
</Label>
|
||||
</div>
|
||||
<Select
|
||||
id="modloader"
|
||||
name="modloader"
|
||||
required
|
||||
onChange={(e) => handleInput(e)}
|
||||
>
|
||||
<option value="Forge">Forge</option>
|
||||
<option value="Fabric">Fabric</option>
|
||||
<option value="NeoForge">NeoForge</option>
|
||||
<option value="Quilt">Quilt</option>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="mb-2 block">
|
||||
<Label htmlFor="base" className="text-lg">
|
||||
Game Version
|
||||
</Label>
|
||||
</div>
|
||||
<Select
|
||||
id="version"
|
||||
name="version"
|
||||
required
|
||||
onChange={(e) => handleInput(e)}
|
||||
>
|
||||
{mcr.map((version) => (
|
||||
<option key={version} value={version}>
|
||||
{version}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">Create</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Card>
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue