done edit/mods
This commit is contained in:
parent
7fb098bc73
commit
b6459b529e
7 changed files with 240 additions and 52 deletions
|
@ -25,6 +25,12 @@ import {
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
|
||||||
interface ModEntry {
|
interface ModEntry {
|
||||||
_id: string;
|
_id: string;
|
||||||
|
@ -37,10 +43,12 @@ interface ModEntry {
|
||||||
const SvrjsModsAdminPage = () => {
|
const SvrjsModsAdminPage = () => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [mods, setMods] = useState<ModEntry[]>([]);
|
const [mods, setMods] = useState<ModEntry[]>([]);
|
||||||
|
const [editMod, setEditMod] = useState<ModEntry | null>(null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof modsSchema>>({
|
const mainForm = useForm<z.infer<typeof modsSchema>>({
|
||||||
resolver: zodResolver(modsSchema),
|
resolver: zodResolver(modsSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
fileName: "",
|
fileName: "",
|
||||||
|
@ -50,6 +58,37 @@ const SvrjsModsAdminPage = () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const dialogForm = useForm<z.infer<typeof modsSchema>>({
|
||||||
|
resolver: zodResolver(modsSchema),
|
||||||
|
defaultValues: {
|
||||||
|
fileName: "",
|
||||||
|
version: "",
|
||||||
|
downloadLink: "",
|
||||||
|
fileSize: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchMods();
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
fetchMods();
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (editMod) {
|
||||||
|
dialogForm.reset({
|
||||||
|
fileName: editMod.fileName,
|
||||||
|
version: editMod.version,
|
||||||
|
downloadLink: editMod.downloadLink,
|
||||||
|
fileSize: editMod.fileSize,
|
||||||
|
});
|
||||||
|
setDialogOpen(true); // Open dialog when a mod is being edited
|
||||||
|
}
|
||||||
|
}, [editMod]);
|
||||||
|
|
||||||
const fetchMods = async () => {
|
const fetchMods = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/mods", {
|
const response = await fetch("/api/mods", {
|
||||||
|
@ -66,37 +105,48 @@ const SvrjsModsAdminPage = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchMods();
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
fetchMods();
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<z.infer<typeof modsSchema>> = async (data) => {
|
const onSubmit: SubmitHandler<z.infer<typeof modsSchema>> = async (data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await fetch("/api/uploadmods", {
|
try {
|
||||||
method: "POST",
|
const response = editMod
|
||||||
headers: {
|
? await fetch(`/api/update/mods/${editMod._id}`, {
|
||||||
"Content-Type": "application/json",
|
method: "PUT",
|
||||||
},
|
headers: {
|
||||||
body: JSON.stringify(data),
|
"Content-Type": "application/json",
|
||||||
});
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
})
|
||||||
|
: await fetch("/api/uploadmods", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
form.reset();
|
mainForm.reset();
|
||||||
fetchMods();
|
dialogForm.reset();
|
||||||
|
fetchMods();
|
||||||
|
setLoading(false);
|
||||||
|
setEditMod(null);
|
||||||
|
setDialogOpen(false); // Close dialog on successful submission
|
||||||
|
toast({
|
||||||
|
description: "Successfully Saved Changes",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("Save failed");
|
||||||
|
setLoading(false);
|
||||||
|
toast({
|
||||||
|
description: "Save failed",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Save failed", error);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
toast({
|
toast({
|
||||||
description: "Successfully Uploaded Mods",
|
description: "Save failed",
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.error("Upload failed");
|
|
||||||
setLoading(false);
|
|
||||||
toast({
|
|
||||||
description: "Upload failed",
|
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -120,10 +170,10 @@ const SvrjsModsAdminPage = () => {
|
||||||
return (
|
return (
|
||||||
<section id="mods-page" className="wrapper container">
|
<section id="mods-page" className="wrapper container">
|
||||||
<h1 className="text-3xl font-bold py-6">Mods Form</h1>
|
<h1 className="text-3xl font-bold py-6">Mods Form</h1>
|
||||||
<Form {...form}>
|
<Form {...mainForm}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
<form onSubmit={mainForm.handleSubmit(onSubmit)} className="space-y-4">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={mainForm.control}
|
||||||
name="fileName"
|
name="fileName"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
|
@ -136,7 +186,7 @@ const SvrjsModsAdminPage = () => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={mainForm.control}
|
||||||
name="version"
|
name="version"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
|
@ -149,7 +199,7 @@ const SvrjsModsAdminPage = () => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={mainForm.control}
|
||||||
name="downloadLink"
|
name="downloadLink"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
|
@ -171,7 +221,7 @@ const SvrjsModsAdminPage = () => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={mainForm.control}
|
||||||
name="fileSize"
|
name="fileSize"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
|
@ -189,7 +239,7 @@ const SvrjsModsAdminPage = () => {
|
||||||
size={"lg"}
|
size={"lg"}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
Submit
|
{editMod ? "Save Changes" : "Submit"}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -234,7 +284,109 @@ const SvrjsModsAdminPage = () => {
|
||||||
<TableCell className="border-b px-4 py-2">
|
<TableCell className="border-b px-4 py-2">
|
||||||
{mod.fileSize}
|
{mod.fileSize}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="border-b px-4 py-2">
|
<TableCell className="border-b px-4 py-2 gap-2 flex-center">
|
||||||
|
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||||
|
<DialogTrigger>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setEditMod(mod)}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogTitle>Edit Content</DialogTitle>
|
||||||
|
|
||||||
|
<Form {...dialogForm}>
|
||||||
|
<form
|
||||||
|
onSubmit={dialogForm.handleSubmit(onSubmit)}
|
||||||
|
className="space-y-4"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
control={dialogForm.control}
|
||||||
|
name="fileName"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>File Name</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
defaultValue={editMod?.fileName}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={dialogForm.control}
|
||||||
|
name="version"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Version</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
defaultValue={editMod?.version}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={dialogForm.control}
|
||||||
|
name="downloadLink"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Download Link</FormLabel>
|
||||||
|
<UploadButton
|
||||||
|
endpoint="imageUploader"
|
||||||
|
onClientUploadComplete={(res) => {
|
||||||
|
field.onChange(res[0].url);
|
||||||
|
}}
|
||||||
|
onUploadError={(error: Error) => {
|
||||||
|
alert(`ERROR! ${error.message}`);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
defaultValue={editMod?.downloadLink}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={dialogForm.control}
|
||||||
|
name="fileSize"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>File Size</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
defaultValue={editMod?.fileSize}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className="w-full text-lg rounded-full"
|
||||||
|
size={"lg"}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
Save Changes
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
<Button
|
<Button
|
||||||
variant={"destructive"}
|
variant={"destructive"}
|
||||||
onClick={() => deleteMod(mod._id)}
|
onClick={() => deleteMod(mod._id)}
|
||||||
|
|
46
app/api/update/mods/[id]/route.ts
Normal file
46
app/api/update/mods/[id]/route.ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import clientPromise from "@/lib/db";
|
||||||
|
import { ObjectId } from "mongodb";
|
||||||
|
|
||||||
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
export async function PUT(
|
||||||
|
request: Request,
|
||||||
|
{ params }: { params: { id: string } }
|
||||||
|
) {
|
||||||
|
const { id } = params;
|
||||||
|
const body = await request.json();
|
||||||
|
const { fileName, version, downloadLink, fileSize } = body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const client = await clientPromise;
|
||||||
|
const db = client.db("downloadsDatabase");
|
||||||
|
|
||||||
|
const result = await db.collection("mods").updateOne(
|
||||||
|
{ _id: new ObjectId(id) },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
fileName,
|
||||||
|
version,
|
||||||
|
downloadLink,
|
||||||
|
fileSize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.modifiedCount > 0) {
|
||||||
|
return NextResponse.json({ success: true });
|
||||||
|
} else {
|
||||||
|
return NextResponse.json({
|
||||||
|
success: false,
|
||||||
|
message: "No document updated",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Update failed", error);
|
||||||
|
return NextResponse.json({
|
||||||
|
success: false,
|
||||||
|
message: "Failed to update mod",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,17 +6,11 @@ const f = createUploadthing();
|
||||||
// const auth = (req: Request) => ({ id: "fakeId" });
|
// const auth = (req: Request) => ({ id: "fakeId" });
|
||||||
|
|
||||||
export const ourFileRouter = {
|
export const ourFileRouter = {
|
||||||
imageUploader: f({ "application/zip": { maxFileSize: "8MB" } })
|
imageUploader: f({
|
||||||
// .middleware(async ({ req }) => {
|
"application/zip": { maxFileSize: "8MB" },
|
||||||
// const user = await auth(req);
|
}).onUploadComplete(async ({ metadata, file }) => {
|
||||||
// if (!user) throw new UploadThingError("Unauthorized");
|
console.log("file url", file.url);
|
||||||
// return { userId: user.id };
|
}),
|
||||||
// })
|
|
||||||
.onUploadComplete(async ({ metadata, file }) => {
|
|
||||||
// console.log("Upload complete for userId:", metadata.userId);
|
|
||||||
console.log("file url", file.url);
|
|
||||||
// return { uploadedBy: metadata.userId };
|
|
||||||
}),
|
|
||||||
} satisfies FileRouter;
|
} satisfies FileRouter;
|
||||||
|
|
||||||
export type OurFileRouter = typeof ourFileRouter;
|
export type OurFileRouter = typeof ourFileRouter;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { createRouteHandler } from "uploadthing/next";
|
import { createRouteHandler } from "uploadthing/next";
|
||||||
import { ourFileRouter } from "./core";
|
import { ourFileRouter } from "./core";
|
||||||
|
|
||||||
// Force the API to use SSR instead of static generation
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export const { GET, POST } = createRouteHandler({
|
export const { GET, POST } = createRouteHandler({
|
||||||
router: ourFileRouter,
|
router: ourFileRouter,
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,11 +5,9 @@ import "prismjs/themes/prism-okaidia.css";
|
||||||
import "prismjs/components/prism-javascript";
|
import "prismjs/components/prism-javascript";
|
||||||
import "prismjs/components/prism-python";
|
import "prismjs/components/prism-python";
|
||||||
import "prismjs/components/prism-php";
|
import "prismjs/components/prism-php";
|
||||||
// Import the languages and their dependencies
|
|
||||||
import "prismjs/components/prism-javascript";
|
import "prismjs/components/prism-javascript";
|
||||||
import "prismjs/components/prism-python";
|
import "prismjs/components/prism-python";
|
||||||
import "prismjs/components/prism-php";
|
import "prismjs/components/prism-php";
|
||||||
// Import additional dependencies for Handlebars if needed
|
|
||||||
import "prismjs/components/prism-markup";
|
import "prismjs/components/prism-markup";
|
||||||
import "prismjs/components/prism-markup-templating";
|
import "prismjs/components/prism-markup-templating";
|
||||||
import "prismjs/components/prism-handlebars";
|
import "prismjs/components/prism-handlebars";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
"use client"; // This directive indicates that the component is client-side
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
|
|
@ -35,7 +35,6 @@ export const config = {
|
||||||
"/api/upload",
|
"/api/upload",
|
||||||
"/api/uploadlogs",
|
"/api/uploadlogs",
|
||||||
"/api/uploadmods",
|
"/api/uploadmods",
|
||||||
"/api/uploadthing",
|
|
||||||
"/api/uploadvulnerabilities",
|
"/api/uploadvulnerabilities",
|
||||||
"/email-editor",
|
"/email-editor",
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue