done edit/mods

This commit is contained in:
Cypro Freelance 2024-08-27 16:45:36 +05:30
parent 7fb098bc73
commit b6459b529e
7 changed files with 240 additions and 52 deletions

View file

@ -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,18 +105,18 @@ 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 {
const response = editMod
? await fetch(`/api/update/mods/${editMod._id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
: await fetch("/api/uploadmods", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -86,17 +125,28 @@ const SvrjsModsAdminPage = () => {
}); });
if (response.ok) { if (response.ok) {
form.reset(); mainForm.reset();
dialogForm.reset();
fetchMods(); fetchMods();
setLoading(false); setLoading(false);
setEditMod(null);
setDialogOpen(false); // Close dialog on successful submission
toast({ toast({
description: "Successfully Uploaded Mods", description: "Successfully Saved Changes",
}); });
} else { } else {
console.error("Upload failed"); console.error("Save failed");
setLoading(false); setLoading(false);
toast({ toast({
description: "Upload failed", description: "Save failed",
variant: "destructive",
});
}
} catch (error) {
console.error("Save failed", error);
setLoading(false);
toast({
description: "Save 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)}

View 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",
});
}
}

View file

@ -6,16 +6,10 @@ 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");
// return { userId: user.id };
// })
.onUploadComplete(async ({ metadata, file }) => {
// console.log("Upload complete for userId:", metadata.userId);
console.log("file url", file.url); console.log("file url", file.url);
// return { uploadedBy: metadata.userId };
}), }),
} satisfies FileRouter; } satisfies FileRouter;

View file

@ -1,7 +1,6 @@
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({

View file

@ -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";

View file

@ -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";

View file

@ -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",
], ],