maybe fixed
This commit is contained in:
parent
8db4d65295
commit
04af299887
21 changed files with 594 additions and 151 deletions
|
@ -1,4 +1,4 @@
|
||||||
MONGO_URI=
|
MONGODB_URI=
|
||||||
|
|
||||||
UPLOADTHING_SECRET=
|
UPLOADTHING_SECRET=
|
||||||
UPLOADTHING_APP_ID=
|
UPLOADTHING_APP_ID=
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
"use server";
|
// 'use server';
|
||||||
|
// import { NextApiRequest } from 'next';
|
||||||
|
// import { NextResponse } from 'next/server';
|
||||||
|
|
||||||
export function CheckLoggedIn(username: string, password: string) {
|
// export async function POST(req: NextApiRequest) {
|
||||||
if (
|
// const { username, password } = await req.body;
|
||||||
username === process.env.ADMIN_USERNAME &&
|
|
||||||
password === process.env.ADMIN_PASSWORD
|
// if (username === process.env.USERNAME && password === process.env.PASSWORD) {
|
||||||
) {
|
// return NextResponse.json({ success: true });
|
||||||
}
|
// } else {
|
||||||
}
|
// return NextResponse.json({ success: false });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
123
app/(auth)/admin/changelogs/page.tsx
Normal file
123
app/(auth)/admin/changelogs/page.tsx
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { useForm, SubmitHandler } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { UploadButton, UploadDropzone } from "@/lib/uploadthing";
|
||||||
|
import { logsSchema } from "@/lib/validations/validation";
|
||||||
|
|
||||||
|
const AdminPage = () => {
|
||||||
|
const form = useForm<z.infer<typeof logsSchema>>({
|
||||||
|
resolver: zodResolver(logsSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<z.infer<typeof logsSchema>> = async (data) => {
|
||||||
|
const response = await fetch("/api/uploadlogs", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
form.reset();
|
||||||
|
console.log("Upload successful");
|
||||||
|
alert("Uploaded");
|
||||||
|
} else {
|
||||||
|
console.error("Upload failed");
|
||||||
|
alert("Upload Failed");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="admin-page" className="wrapper container">
|
||||||
|
<h1 className="text-3xl font-bold py-6">Admin Upload Section</h1>
|
||||||
|
<Form {...form}>
|
||||||
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="fileName"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>File Name</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="version"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Version</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.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} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="fileSize"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>File Size</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className="w-full text-lg rounded-full"
|
||||||
|
size={"lg"}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdminPage;
|
123
app/(auth)/admin/mods/page.tsx
Normal file
123
app/(auth)/admin/mods/page.tsx
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { useForm, SubmitHandler } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { UploadButton, UploadDropzone } from "@/lib/uploadthing";
|
||||||
|
import { modsSchema } from "@/lib/validations/validation";
|
||||||
|
|
||||||
|
const AdminPage = () => {
|
||||||
|
const form = useForm<z.infer<typeof modsSchema>>({
|
||||||
|
resolver: zodResolver(modsSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<z.infer<typeof modsSchema>> = async (data) => {
|
||||||
|
const response = await fetch("/api/uploadmods", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
form.reset();
|
||||||
|
console.log("Upload successful");
|
||||||
|
alert("Uploaded");
|
||||||
|
} else {
|
||||||
|
console.error("Upload failed");
|
||||||
|
alert("Upload Failed");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="admin-page" className="wrapper container">
|
||||||
|
<h1 className="text-3xl font-bold py-6">Admin Upload Section</h1>
|
||||||
|
<Form {...form}>
|
||||||
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="fileName"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>File Name</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="version"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Version</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.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} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="fileSize"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>File Size</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className="w-full text-lg rounded-full"
|
||||||
|
size={"lg"}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdminPage;
|
|
@ -1,5 +1,9 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Blog - SVRJS",
|
||||||
|
};
|
||||||
const BlogPage = () => {
|
const BlogPage = () => {
|
||||||
return <div>BlogPage</div>;
|
return <div>BlogPage</div>;
|
||||||
};
|
};
|
||||||
|
|
92
app/(root)/changelogs/page.tsx
Normal file
92
app/(root)/changelogs/page.tsx
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import { Download } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
interface LOGS {
|
||||||
|
_id: string;
|
||||||
|
date: string;
|
||||||
|
fileName: string;
|
||||||
|
version: string;
|
||||||
|
fileSize: string;
|
||||||
|
downloadLink: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DownloadPage: React.FC = () => {
|
||||||
|
const [downloads, setDownloads] = useState<LOGS[]>([]);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
const fetchDownloads = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/logs", {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
const data: LOGS[] = await response.json();
|
||||||
|
setDownloads(data);
|
||||||
|
} else {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
setError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchDownloads();
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
fetchDownloads();
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="logs"
|
||||||
|
className="wrapper container py-24 md:py-28 gap-4 flex flex-col"
|
||||||
|
>
|
||||||
|
<h1 className="text-3xl md:text-5xl font-bold text-black dark:bg-clip-text dark:text-transparent dark:bg-gradient-to-b dark:from-white dark:to-neutral-400">
|
||||||
|
Server LOGS
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-muted-foreground text-start mb-4">
|
||||||
|
Get all the latest version of SVRJS download and compiled Files here!
|
||||||
|
</p>
|
||||||
|
{error && <p className="text-red-500">{error}</p>}
|
||||||
|
|
||||||
|
{downloads
|
||||||
|
.slice(0, 10)
|
||||||
|
.reverse()
|
||||||
|
.map((download) => (
|
||||||
|
<div key={download._id}>
|
||||||
|
<span className="font-medium">{download.date}</span>
|
||||||
|
<span>{download.fileName}</span>
|
||||||
|
<span>{download.version}</span>
|
||||||
|
<span className="text-left">{download.fileSize}</span>
|
||||||
|
<span className="flex items-center justify-end">
|
||||||
|
<Link href={download.downloadLink}>
|
||||||
|
<Button variant={"ghost"} className="">
|
||||||
|
<Download className="w-4 h-4 mr-2" />
|
||||||
|
Download
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DownloadPage;
|
|
@ -1,7 +1,15 @@
|
||||||
import React from "react";
|
import Sidebar from "@/components/shared/Sidebar";
|
||||||
|
|
||||||
const Docs = () => {
|
import { Metadata } from "next";
|
||||||
return <div>Docs</div>;
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Docs - SVRJS",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Docs;
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Sidebar />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
import Footer from "@/components/shared/Footer";
|
import Footer from "@/components/shared/Footer";
|
||||||
import Navbar from "@/components/shared/Navbar";
|
import Navbar from "@/components/shared/Navbar";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Home - SVRJS",
|
||||||
|
};
|
||||||
|
|
||||||
export default function PageLayout({
|
export default function PageLayout({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<main className="flex flex-col min-h-screen">
|
<main className="flex flex-col min-h-screen">
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<div className="flex-grow flex-1">{children}</div>
|
<div className="flex-grow flex-1">{children}</div>
|
||||||
<Footer />
|
<Footer />
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
11
app/(root)/mods/layout.tsx
Normal file
11
app/(root)/mods/layout.tsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "MOD - SVRJS",
|
||||||
|
};
|
||||||
|
|
||||||
|
const ModLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
return <main>{children}</main>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModLayout;
|
|
@ -1,3 +1,6 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
|
@ -11,38 +14,45 @@ import {
|
||||||
import { Download } from "lucide-react";
|
import { Download } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
const downloads = [
|
interface Mods {
|
||||||
{
|
_id: string;
|
||||||
date: "2024-06-01",
|
date: string;
|
||||||
fileName: "SVRJS_v1.0.0.zip",
|
fileName: string;
|
||||||
version: "1.0.0",
|
version: string;
|
||||||
fileSize: "15MB",
|
fileSize: string;
|
||||||
downloadLink: "/downloads/SVRJS_v1.0.0.zip",
|
downloadLink: string;
|
||||||
},
|
}
|
||||||
{
|
|
||||||
date: "2024-06-10",
|
const ModsPage: React.FC = () => {
|
||||||
fileName: "SVRJS_v1.1.0.zip",
|
const [downloads, setDownloads] = useState<Mods[]>([]);
|
||||||
version: "1.1.0",
|
const [error, setError] = useState("");
|
||||||
fileSize: "18MB",
|
|
||||||
downloadLink: "/downloads/SVRJS_v1.1.0.zip",
|
const fetchDownloads = async () => {
|
||||||
},
|
try {
|
||||||
{
|
const response = await fetch("/api/mods", {
|
||||||
date: "2024-06-15",
|
method: "GET",
|
||||||
fileName: "SVRJS_v1.2.0.zip",
|
});
|
||||||
version: "1.2.0",
|
if (response.ok) {
|
||||||
fileSize: "20MB",
|
const data: Mods[] = await response.json();
|
||||||
downloadLink: "/downloads/SVRJS_v1.2.0.zip",
|
setDownloads(data);
|
||||||
},
|
} else {
|
||||||
{
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
date: "2024-06-20",
|
}
|
||||||
fileName: "SVRJS_v1.3.0.zip",
|
} catch (error: any) {
|
||||||
version: "1.3.0",
|
setError(error);
|
||||||
fileSize: "22MB",
|
}
|
||||||
downloadLink: "/downloads/SVRJS_v1.3.0.zip",
|
};
|
||||||
},
|
|
||||||
];
|
useEffect(() => {
|
||||||
|
fetchDownloads();
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
fetchDownloads();
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const Mods = () => {
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
id="mods"
|
id="mods"
|
||||||
|
@ -52,8 +62,9 @@ const Mods = () => {
|
||||||
SvrJS Mods
|
SvrJS Mods
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-lg text-muted-foreground text-start mb-4">
|
<p className="text-lg text-muted-foreground text-start mb-4">
|
||||||
Get all the latest version of SVRJS Mods and compiled Files here!
|
Get all the latest version of SVRJS Mods and compiled Files here!{" "}
|
||||||
</p>
|
</p>
|
||||||
|
{error && <p className="text-red-500">{error}</p>}
|
||||||
<Table>
|
<Table>
|
||||||
<TableCaption>A list of all available downloads.</TableCaption>
|
<TableCaption>A list of all available downloads.</TableCaption>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
|
@ -66,26 +77,29 @@ const Mods = () => {
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{downloads.map((download) => (
|
{downloads
|
||||||
<TableRow key={download.fileName}>
|
.slice(0, 10)
|
||||||
<TableCell className="font-medium">{download.date}</TableCell>
|
.reverse()
|
||||||
<TableCell>{download.fileName}</TableCell>
|
.map((download) => (
|
||||||
<TableCell>{download.version}</TableCell>
|
<TableRow key={download._id}>
|
||||||
<TableCell className="text-left">{download.fileSize}</TableCell>
|
<TableCell className="font-medium">{download.date}</TableCell>
|
||||||
<TableCell className="flex items-center justify-end">
|
<TableCell>{download.fileName}</TableCell>
|
||||||
<Link href={download.downloadLink}>
|
<TableCell>{download.version}</TableCell>
|
||||||
<Button variant={"ghost"} className="">
|
<TableCell className="text-left">{download.fileSize}</TableCell>
|
||||||
<Download className="w-4 h-4 mr-2" />
|
<TableCell className="flex items-center justify-end">
|
||||||
Download
|
<Link href={download.downloadLink}>
|
||||||
</Button>
|
<Button variant={"ghost"} className="">
|
||||||
</Link>
|
<Download className="w-4 h-4 mr-2" />
|
||||||
</TableCell>
|
Download
|
||||||
</TableRow>
|
</Button>
|
||||||
))}
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Mods;
|
export default ModsPage;
|
||||||
|
|
|
@ -9,6 +9,7 @@ export async function GET(req: NextRequest) {
|
||||||
const downloads = await db.collection("downloads").find().toArray();
|
const downloads = await db.collection("downloads").find().toArray();
|
||||||
return NextResponse.json(downloads, { status: 200 });
|
return NextResponse.json(downloads, { status: 200 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(`Error Messge ${error}`);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Failed to fetch downloads" },
|
{ error: "Failed to fetch downloads" },
|
||||||
{ status: 500 }
|
{ status: 500 }
|
||||||
|
|
17
app/api/logs/route.ts
Normal file
17
app/api/logs/route.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import clientPromise from "@/lib/db";
|
||||||
|
|
||||||
|
// Handler for GET requests
|
||||||
|
export async function GET(req: NextRequest) {
|
||||||
|
try {
|
||||||
|
const client = await clientPromise;
|
||||||
|
const db = client.db("downloadsDatabase");
|
||||||
|
const downloads = await db.collection("logs").find().toArray();
|
||||||
|
return NextResponse.json(downloads, { status: 200 });
|
||||||
|
} catch (error) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Failed to fetch logs" },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
17
app/api/mods/route.ts
Normal file
17
app/api/mods/route.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import clientPromise from "@/lib/db";
|
||||||
|
|
||||||
|
// Handler for GET requests
|
||||||
|
export async function GET(req: NextRequest) {
|
||||||
|
try {
|
||||||
|
const client = await clientPromise;
|
||||||
|
const db = client.db("downloadsDatabase");
|
||||||
|
const downloads = await db.collection("mods").find().toArray();
|
||||||
|
return NextResponse.json(downloads, { status: 200 });
|
||||||
|
} catch (error) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Failed to fetch mods" },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
20
app/api/uploadlogs/route.ts
Normal file
20
app/api/uploadlogs/route.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import clientPromise from "@/lib/db";
|
||||||
|
|
||||||
|
export async function POST(request: Request) {
|
||||||
|
const body = await request.json();
|
||||||
|
const { fileName, version, downloadLink, fileSize } = body;
|
||||||
|
|
||||||
|
const client = await clientPromise;
|
||||||
|
const db = client.db("downloadsDatabase");
|
||||||
|
|
||||||
|
const result = await db.collection("logs").insertOne({
|
||||||
|
date: new Date().toISOString().split("T")[0],
|
||||||
|
fileName,
|
||||||
|
version,
|
||||||
|
downloadLink,
|
||||||
|
fileSize,
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json({ success: true, id: result.insertedId });
|
||||||
|
}
|
20
app/api/uploadmods/route.ts
Normal file
20
app/api/uploadmods/route.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import clientPromise from "@/lib/db";
|
||||||
|
|
||||||
|
export async function POST(request: Request) {
|
||||||
|
const body = await request.json();
|
||||||
|
const { fileName, version, downloadLink, fileSize } = body;
|
||||||
|
|
||||||
|
const client = await clientPromise;
|
||||||
|
const db = client.db("downloadsDatabase");
|
||||||
|
|
||||||
|
const result = await db.collection("mods").insertOne({
|
||||||
|
date: new Date().toISOString().split("T")[0],
|
||||||
|
fileName,
|
||||||
|
version,
|
||||||
|
downloadLink,
|
||||||
|
fileSize,
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json({ success: true, id: result.insertedId });
|
||||||
|
}
|
24
components/shared/Sidebar.tsx
Normal file
24
components/shared/Sidebar.tsx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const Sidebar = () => {
|
||||||
|
return (
|
||||||
|
<div className="w-[250px] h-[100vh] border-r dark:border-r-slate-800 pl-4 pt-2">
|
||||||
|
<span className="flex flex-col gap-2">
|
||||||
|
<h2 className="text-2xl font-bold">First use</h2>
|
||||||
|
<ul className="pl-4 flex flex-col gap-2">
|
||||||
|
<li>System requirements</li>
|
||||||
|
<li>Installation</li>
|
||||||
|
<li>Features</li>
|
||||||
|
<li>SVR.JS files</li>
|
||||||
|
<li>SVR.JS utilities</li>
|
||||||
|
<li>SVR.JS commands</li>
|
||||||
|
<li>Updating SVR.JS</li>
|
||||||
|
<li>Common problems</li>
|
||||||
|
<li>Bun support</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Sidebar;
|
33
lib/db.ts
33
lib/db.ts
|
@ -1,24 +1,35 @@
|
||||||
import { MongoClient } from "mongodb";
|
import { MongoClient } from "mongodb";
|
||||||
|
|
||||||
|
// Ensure the environment variable is set
|
||||||
if (!process.env.MONGODB_URI) {
|
if (!process.env.MONGODB_URI) {
|
||||||
throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
|
throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
|
||||||
}
|
}
|
||||||
|
|
||||||
const uri = process.env.MONGODB_URI;
|
const uri = process.env.MONGODB_URI;
|
||||||
const options = {};
|
const options = {
|
||||||
|
// Add any SSL/TLS options if needed, for example:
|
||||||
|
// ssl: true,
|
||||||
|
// tlsAllowInvalidCertificates: true,
|
||||||
|
};
|
||||||
|
|
||||||
let client;
|
let client: MongoClient;
|
||||||
let clientPromise: Promise<MongoClient>;
|
let clientPromise: Promise<MongoClient>;
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
declare global {
|
||||||
if (!(global as any)._mongoClientPromise) {
|
var _mongoClientPromise: Promise<MongoClient> | undefined;
|
||||||
client = new MongoClient(uri!, options);
|
|
||||||
(global as any)._mongoClientPromise = client.connect();
|
|
||||||
}
|
|
||||||
clientPromise = (global as any)._mongoClientPromise;
|
|
||||||
} else {
|
|
||||||
client = new MongoClient(uri!, options);
|
|
||||||
clientPromise = client.connect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (process.env.NODE_ENV === "development") {
|
||||||
|
// // In development mode, use a global variable to ensure the client is not recreated
|
||||||
|
// if (!global._mongoClientPromise) {
|
||||||
|
// client = new MongoClient(uri, options);
|
||||||
|
// global._mongoClientPromise = client.connect();
|
||||||
|
// }
|
||||||
|
// clientPromise = global._mongoClientPromise;
|
||||||
|
// } else {
|
||||||
|
// In production mode, create a new client for each request
|
||||||
|
client = new MongoClient(uri, options);
|
||||||
|
clientPromise = client.connect();
|
||||||
|
// }
|
||||||
|
|
||||||
export default clientPromise;
|
export default clientPromise;
|
||||||
|
|
|
@ -6,3 +6,17 @@ export const downloadSchema = z.object({
|
||||||
downloadLink: z.string().url().nonempty(),
|
downloadLink: z.string().url().nonempty(),
|
||||||
fileSize: z.string().nonempty(),
|
fileSize: z.string().nonempty(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const modsSchema = z.object({
|
||||||
|
fileName: z.string().nonempty(),
|
||||||
|
version: z.string().nonempty(),
|
||||||
|
downloadLink: z.string().url().nonempty(),
|
||||||
|
fileSize: z.string().nonempty(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const logsSchema = z.object({
|
||||||
|
fileName: z.string().nonempty(),
|
||||||
|
version: z.string().nonempty(),
|
||||||
|
downloadLink: z.string().url().nonempty(),
|
||||||
|
fileSize: z.string().nonempty(),
|
||||||
|
});
|
||||||
|
|
67
package-lock.json
generated
67
package-lock.json
generated
|
@ -8,9 +8,6 @@
|
||||||
"name": "svrjs",
|
"name": "svrjs",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.5.2",
|
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
|
||||||
"@hookform/resolvers": "^3.6.0",
|
"@hookform/resolvers": "^3.6.0",
|
||||||
"@radix-ui/react-accordion": "^1.1.2",
|
"@radix-ui/react-accordion": "^1.1.2",
|
||||||
"@radix-ui/react-dialog": "^1.0.5",
|
"@radix-ui/react-dialog": "^1.0.5",
|
||||||
|
@ -32,7 +29,6 @@
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-fontawesome": "^1.7.1",
|
|
||||||
"react-hook-form": "^7.52.0",
|
"react-hook-form": "^7.52.0",
|
||||||
"tailwind-merge": "^2.3.0",
|
"tailwind-merge": "^2.3.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
@ -172,51 +168,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
|
||||||
"integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
|
"integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
|
||||||
},
|
},
|
||||||
"node_modules/@fortawesome/fontawesome-common-types": {
|
|
||||||
"version": "6.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz",
|
|
||||||
"integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@fortawesome/fontawesome-svg-core": {
|
|
||||||
"version": "6.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz",
|
|
||||||
"integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@fortawesome/fontawesome-common-types": "6.5.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@fortawesome/free-regular-svg-icons": {
|
|
||||||
"version": "6.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.2.tgz",
|
|
||||||
"integrity": "sha512-iabw/f5f8Uy2nTRtJ13XZTS1O5+t+anvlamJ3zJGLEVE2pKsAWhPv2lq01uQlfgCX7VaveT3EVs515cCN9jRbw==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@fortawesome/fontawesome-common-types": "6.5.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@fortawesome/react-fontawesome": {
|
|
||||||
"version": "0.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz",
|
|
||||||
"integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==",
|
|
||||||
"dependencies": {
|
|
||||||
"prop-types": "^15.8.1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
|
|
||||||
"react": ">=16.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@hookform/resolvers": {
|
"node_modules/@hookform/resolvers": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.6.0.tgz",
|
||||||
|
@ -5704,6 +5655,7 @@
|
||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
|
@ -5776,20 +5728,6 @@
|
||||||
"react": "^18.3.1"
|
"react": "^18.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-fontawesome": {
|
|
||||||
"version": "1.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-fontawesome/-/react-fontawesome-1.7.1.tgz",
|
|
||||||
"integrity": "sha512-kottReWW1I9Uupub6A5YX4VK7qfpFnEjAcm5zB4Aepst7iofONT27GJYdTcRsj7q5uQu9PXBL7GsxAFKANNUVg==",
|
|
||||||
"dependencies": {
|
|
||||||
"prop-types": "^15.5.6"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">=0.12.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-hook-form": {
|
"node_modules/react-hook-form": {
|
||||||
"version": "7.52.0",
|
"version": "7.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.0.tgz",
|
||||||
|
@ -5809,7 +5747,8 @@
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/react-remove-scroll": {
|
"node_modules/react-remove-scroll": {
|
||||||
"version": "2.5.5",
|
"version": "2.5.5",
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.5.2",
|
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
|
||||||
"@hookform/resolvers": "^3.6.0",
|
"@hookform/resolvers": "^3.6.0",
|
||||||
"@radix-ui/react-accordion": "^1.1.2",
|
"@radix-ui/react-accordion": "^1.1.2",
|
||||||
"@radix-ui/react-dialog": "^1.0.5",
|
"@radix-ui/react-dialog": "^1.0.5",
|
||||||
|
@ -33,7 +30,6 @@
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-fontawesome": "^1.7.1",
|
|
||||||
"react-hook-form": "^7.52.0",
|
"react-hook-form": "^7.52.0",
|
||||||
"tailwind-merge": "^2.3.0",
|
"tailwind-merge": "^2.3.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
|
|
@ -21,6 +21,6 @@
|
||||||
"@/*": ["./*"]
|
"@/*": ["./*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "lib/Hoc/withAuth.jsx"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue