some minor changes

This commit is contained in:
Cypro Freelance 2024-07-18 00:03:43 +05:30
parent 092dbd504a
commit 1d217133ab
7 changed files with 353 additions and 58 deletions

View file

@ -6,60 +6,60 @@ import { usePathname } from "next/navigation";
import { AdminLinks } from "@/constants"; import { AdminLinks } from "@/constants";
const Sidebar = () => { const Sidebar = () => {
const pathname = usePathname(); const pathname = usePathname();
return ( return (
<> <>
<aside className="sidebar"> <aside className="sidebar">
<div className="flex size-full flex-col gap-4"> <div className="flex size-full flex-col gap-4">
<Link href="/" className="sidebar-logo"> <Link href="/" className="sidebar-logo">
<Image src="/logo.svg" alt="" width={180} height={28} /> <Image src="/logo.svg" alt="" width={180} height={28} />
</Link> </Link>
<nav className="sidebar-nav"> <nav className="sidebar-nav">
<ul className="sidebar-nav_elements"> <ul className="sidebar-nav_elements">
{AdminLinks.slice(0, 4).map((link) => { {AdminLinks.slice(0, 4).map((link) => {
const isActive = link.url === pathname; const isActive = link.url === pathname;
return ( return (
<li <li
key={link.url} key={link.url}
className={`sidebar-nav_element group ${ className={`sidebar-nav_element group ${
isActive ? "bg-white/5" : "text-gray-700" isActive ? "bg-white/5" : "text-muted-foreground"
}`} }`}
> >
<Link className="sidebar-link" href={link.url}> <Link className="sidebar-link" href={link.url}>
<link.icon /> <link.icon />
{link.name} {link.name}
</Link> </Link>
</li> </li>
); );
})} })}
</ul> </ul>
<ul className="sidebar-nav_elements"> <ul className="sidebar-nav_elements">
{AdminLinks.slice(4).map((link) => { {AdminLinks.slice(4).map((link) => {
const isActive = link.url === pathname; const isActive = link.url === pathname;
return ( return (
<li <li
key={link.url} key={link.url}
className={`sidebar-nav_element group ${ className={`sidebar-nav_element group ${
isActive ? "bg-purple-gradient" : "text-gray-700" isActive ? "bg-purple-gradient" : "text-muted-foreground"
}`} }`}
> >
<Link className="sidebar-link" href={link.url}> <Link className="sidebar-link" href={link.url}>
<link.icon /> <link.icon />
{link.name} {link.name}
</Link> </Link>
</li> </li>
); );
})} })}
</ul> </ul>
</nav> </nav>
</div> </div>
</aside> </aside>
</> </>
); );
}; };
export default Sidebar; export default Sidebar;

View file

@ -105,7 +105,7 @@ const AdminLogPage = () => {
const deleteLog = async (id: string) => { const deleteLog = async (id: string) => {
try { try {
const response = await fetch(`/api/delete/${id}`, { const response = await fetch(`/api/delete/logs/${id}`, {
method: "DELETE", method: "DELETE",
}); });
if (response.ok) { if (response.ok) {

View file

@ -1,6 +1,6 @@
"use client"; "use client";
import React from "react"; import React, { useEffect, useState } from "react";
import { useForm, SubmitHandler } from "react-hook-form"; import { useForm, SubmitHandler } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
@ -14,12 +14,31 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { UploadButton, UploadDropzone } from "@/lib/uploadthing"; import { UploadButton } from "@/lib/uploadthing";
import { downloadSchema } from "@/lib/validations/validation"; import { downloadSchema } from "@/lib/validations/validation";
import { useToast } from "@/components/ui/use-toast"; import { useToast } from "@/components/ui/use-toast";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
interface DownloadEntry {
_id: string;
fileName: string;
version: string;
downloadLink: string;
fileSize: string;
}
const DownloadsPage = () => { const DownloadsPage = () => {
const { toast } = useToast(); const { toast } = useToast();
const [downloads, setDownloads] = useState<DownloadEntry[]>([]);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const form = useForm<z.infer<typeof downloadSchema>>({ const form = useForm<z.infer<typeof downloadSchema>>({
resolver: zodResolver(downloadSchema), resolver: zodResolver(downloadSchema),
@ -31,9 +50,35 @@ const DownloadsPage = () => {
}, },
}); });
const fetchDownloads = async () => {
try {
const response = await fetch("/api/downloads", {
method: "GET",
});
if (response.ok) {
const data: DownloadEntry[] = await response.json();
setDownloads(data);
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
} catch (error: any) {
setError(error.message || "Failed to fetch downloads");
}
};
useEffect(() => {
fetchDownloads();
const interval = setInterval(() => {
fetchDownloads();
}, 10000);
return () => clearInterval(interval);
}, []);
const onSubmit: SubmitHandler<z.infer<typeof downloadSchema>> = async ( const onSubmit: SubmitHandler<z.infer<typeof downloadSchema>> = async (
data data
) => { ) => {
setLoading(true);
const response = await fetch("/api/upload", { const response = await fetch("/api/upload", {
method: "POST", method: "POST",
headers: { headers: {
@ -44,14 +89,31 @@ const DownloadsPage = () => {
if (response.ok) { if (response.ok) {
form.reset(); form.reset();
toast({ description: "Download Sucessfully Updated" }); fetchDownloads();
console.log("Upload successful"); setLoading(false);
toast({ description: "Download Successfully Updated" });
} else { } else {
console.error("Upload failed"); console.error("Upload failed");
setLoading(false);
toast({ description: "Uploading Failed", variant: "destructive" }); toast({ description: "Uploading Failed", variant: "destructive" });
} }
}; };
const deleteDownload = async (id: string) => {
try {
const response = await fetch(`/api/delete/downloads/${id}`, {
method: "DELETE",
});
if (response.ok) {
fetchDownloads();
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
} catch (error: any) {
setError(error.message || "Failed to delete download");
}
};
return ( return (
<section id="downloads-page" className="wrapper container"> <section id="downloads-page" className="wrapper container">
<h1 className="text-3xl font-bold py-6">Downloads Form</h1> <h1 className="text-3xl font-bold py-6">Downloads Form</h1>
@ -122,11 +184,66 @@ const DownloadsPage = () => {
type="submit" type="submit"
className="w-full text-lg rounded-full" className="w-full text-lg rounded-full"
size={"lg"} size={"lg"}
disabled={loading}
> >
Submit Submit
</Button> </Button>
</form> </form>
</Form> </Form>
{/* Section to list and delete downloads */}
<section id="downloads-list" className="py-16 md:py-24">
<h2 className="text-3xl md:text-4xl font-bold">Existing Downloads</h2>
{error && <p className="text-red-500">{error}</p>}
<Table className="w-full mt-4 border-muted">
<TableHeader>
<TableRow>
<TableHead className="border-b px-4 py-2">File Name</TableHead>
<TableHead className="border-b px-4 py-2">Version</TableHead>
<TableHead className="border-b px-4 py-2">
Download Link
</TableHead>
<TableHead className="border-b px-4 py-2">File Size</TableHead>
<TableHead className="border-b px-4 py-2">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{downloads
.slice()
.reverse()
.map((download) => (
<TableRow key={download._id}>
<TableCell className="border-b px-4 py-2">
{download.fileName}
</TableCell>
<TableCell className="border-b px-4 py-2">
{download.version}
</TableCell>
<TableCell className="border-b px-4 py-2">
<a
href={download.downloadLink}
target="_blank"
rel="noopener noreferrer"
>
{download.downloadLink}
</a>
</TableCell>
<TableCell className="border-b px-4 py-2">
{download.fileSize}
</TableCell>
<TableCell className="border-b px-4 py-2">
<Button
variant={"destructive"}
onClick={() => deleteDownload(download._id)}
>
Delete
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</section>
</section> </section>
); );
}; };

View file

@ -1,6 +1,6 @@
"use client"; "use client";
import React from "react"; import React, { useEffect, useState } from "react";
import { useForm, SubmitHandler } from "react-hook-form"; import { useForm, SubmitHandler } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
@ -14,12 +14,32 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { UploadButton, UploadDropzone } from "@/lib/uploadthing"; import { UploadButton } from "@/lib/uploadthing";
import { modsSchema } from "@/lib/validations/validation"; import { modsSchema } from "@/lib/validations/validation";
import { useToast } from "@/components/ui/use-toast"; import { useToast } from "@/components/ui/use-toast";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
interface ModEntry {
_id: string;
fileName: string;
version: string;
downloadLink: string;
fileSize: string;
}
const SvrjsModsAdminPage = () => { const SvrjsModsAdminPage = () => {
const { toast } = useToast(); const { toast } = useToast();
const [mods, setMods] = useState<ModEntry[]>([]);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const form = useForm<z.infer<typeof modsSchema>>({ const form = useForm<z.infer<typeof modsSchema>>({
resolver: zodResolver(modsSchema), resolver: zodResolver(modsSchema),
defaultValues: { defaultValues: {
@ -30,7 +50,33 @@ const SvrjsModsAdminPage = () => {
}, },
}); });
const fetchMods = async () => {
try {
const response = await fetch("/api/mods", {
method: "GET",
});
if (response.ok) {
const data: ModEntry[] = await response.json();
setMods(data);
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
} catch (error: any) {
setError(error.message || "Failed to fetch mods");
}
};
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);
const response = await fetch("/api/uploadmods", { const response = await fetch("/api/uploadmods", {
method: "POST", method: "POST",
headers: { headers: {
@ -41,12 +87,14 @@ const SvrjsModsAdminPage = () => {
if (response.ok) { if (response.ok) {
form.reset(); form.reset();
fetchMods();
setLoading(false);
toast({ toast({
description: "Successfully Uploaded Mods", description: "Successfully Uploaded Mods",
}); });
console.log("Upload successful");
} else { } else {
console.error("Upload failed"); console.error("Upload failed");
setLoading(false);
toast({ toast({
description: "Upload failed", description: "Upload failed",
variant: "destructive", variant: "destructive",
@ -54,6 +102,21 @@ const SvrjsModsAdminPage = () => {
} }
}; };
const deleteMod = async (id: string) => {
try {
const response = await fetch(`/api/delete/mods/${id}`, {
method: "DELETE",
});
if (response.ok) {
fetchMods();
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
} catch (error: any) {
setError(error.message || "Failed to delete mod");
}
};
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>
@ -124,11 +187,66 @@ const SvrjsModsAdminPage = () => {
type="submit" type="submit"
className="w-full text-lg rounded-full" className="w-full text-lg rounded-full"
size={"lg"} size={"lg"}
disabled={loading}
> >
Submit Submit
</Button> </Button>
</form> </form>
</Form> </Form>
{/* Section to list and delete mods */}
<section id="mods-list" className="py-16 md:py-24">
<h2 className="text-3xl md:text-4xl font-bold">Existing Mods</h2>
{error && <p className="text-red-500">{error}</p>}
<Table className="w-full mt-4 border-muted">
<TableHeader>
<TableRow>
<TableHead className="border-b px-4 py-2">File Name</TableHead>
<TableHead className="border-b px-4 py-2">Version</TableHead>
<TableHead className="border-b px-4 py-2">
Download Link
</TableHead>
<TableHead className="border-b px-4 py-2">File Size</TableHead>
<TableHead className="border-b px-4 py-2">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{mods
.slice()
.reverse()
.map((mod) => (
<TableRow key={mod._id}>
<TableCell className="border-b px-4 py-2">
{mod.fileName}
</TableCell>
<TableCell className="border-b px-4 py-2">
{mod.version}
</TableCell>
<TableCell className="border-b px-4 py-2">
<a
href={mod.downloadLink}
target="_blank"
rel="noopener noreferrer"
>
{mod.downloadLink}
</a>
</TableCell>
<TableCell className="border-b px-4 py-2">
{mod.fileSize}
</TableCell>
<TableCell className="border-b px-4 py-2">
<Button
variant={"destructive"}
onClick={() => deleteMod(mod._id)}
>
Delete
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</section>
</section> </section>
); );
}; };

View file

@ -0,0 +1,30 @@
// app/api/delete/[id]/route.ts
import clientPromise from "@/lib/db";
import { ObjectId } from "mongodb";
import { NextResponse } from "next/server";
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
const { id } = params;
try {
const client = await clientPromise;
const db = client.db("downloadsDatabase");
const collection = db.collection("downloads");
const result = await collection.deleteOne({ _id: new ObjectId(id) });
if (result.deletedCount === 1) {
return NextResponse.json({ message: "Log deleted successfully" });
} else {
return NextResponse.json({ message: "Log not found" }, { status: 404 });
}
} catch (error) {
return NextResponse.json(
{ message: "Failed to delete log", error: error },
{ status: 500 }
);
}
}

View file

@ -0,0 +1,30 @@
// app/api/delete/[id]/route.ts
import clientPromise from "@/lib/db";
import { ObjectId } from "mongodb";
import { NextResponse } from "next/server";
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
const { id } = params;
try {
const client = await clientPromise;
const db = client.db("downloadsDatabase");
const collection = db.collection("mods");
const result = await collection.deleteOne({ _id: new ObjectId(id) });
if (result.deletedCount === 1) {
return NextResponse.json({ message: "Log deleted successfully" });
} else {
return NextResponse.json({ message: "Log not found" }, { status: 404 });
}
} catch (error) {
return NextResponse.json(
{ message: "Failed to delete log", error: error },
{ status: 500 }
);
}
}