From 5a2c2d2e693a36bb5b433a17d0821379cbc04277 Mon Sep 17 00:00:00 2001 From: NerfedJabolo Date: Sat, 22 Jun 2024 05:50:53 +0300 Subject: [PATCH] Co-authored-by: Abhijit Bhattacharjee --- .env | 7 +- app/(auth)/admin/mods/page.tsx | 123 +++++++++++++++++++++++++++ app/(root)/add-download/page.tsx | 7 -- app/(root)/blog/page.tsx | 7 +- app/(root)/docs/page.tsx | 6 ++ app/(root)/downloads/layout.tsx | 11 +++ app/(root)/forum/page.tsx | 7 +- app/(root)/layout.tsx | 27 +++--- app/(root)/login/page.tsx | 52 ------------ app/(root)/mods/layout.tsx | 11 +++ app/(root)/mods/page.tsx | 128 +++++++++++++++------------- app/api/mods/route.ts | 17 ++++ app/api/uploadmods/route.ts | 20 +++++ constants/index.tsx | 140 +++++++++++++++---------------- lib/validations/validation.ts | 9 +- 15 files changed, 370 insertions(+), 202 deletions(-) create mode 100644 app/(auth)/admin/mods/page.tsx delete mode 100644 app/(root)/add-download/page.tsx create mode 100644 app/(root)/downloads/layout.tsx delete mode 100644 app/(root)/login/page.tsx create mode 100644 app/(root)/mods/layout.tsx create mode 100644 app/api/mods/route.ts create mode 100644 app/api/uploadmods/route.ts diff --git a/.env b/.env index 58ea260..962f00e 100644 --- a/.env +++ b/.env @@ -1,2 +1,5 @@ -USERNAME="Svr_admin" -PASSWORD="YP6t1kV6rmviuQG" \ No newline at end of file +ADMIN_USERNAME=Svr_admin +ADMIN_PASSWORD=temppass +MONGODB_URI=mongodb+srv://euler:0f61VcV5UWozRWxp@learning-mongo.jcsdeht.mongodb.net/node-tuts +UPLOADTHING_SECRET=sk_live_0c456ce4a8366c64660dbf057bf8dd8bbe9db3d4bf7a70766855c04c09ba0aa9 +UPLOADTHING_APP_ID=6no1s7ob1p diff --git a/app/(auth)/admin/mods/page.tsx b/app/(auth)/admin/mods/page.tsx new file mode 100644 index 0000000..66325aa --- /dev/null +++ b/app/(auth)/admin/mods/page.tsx @@ -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>({ + resolver: zodResolver(modsSchema), + }); + + const onSubmit: SubmitHandler> = 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 ( +
+

Admin Upload Section

+
+ + ( + + File Name + + + + + + )} + /> + ( + + Version + + + + + + )} + /> + ( + + Download Link + { + field.onChange(res[0].url); + }} + onUploadError={(error: Error) => { + alert(`ERROR! ${error.message}`); + }} + /> + + + + + + )} + /> + ( + + File Size + + + + + + )} + /> + + + +
+ ); +}; + +export default AdminPage; diff --git a/app/(root)/add-download/page.tsx b/app/(root)/add-download/page.tsx deleted file mode 100644 index 5bf4dc3..0000000 --- a/app/(root)/add-download/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -const AddDownload = () => { - return
Welcome to downloads
; -}; - -export default AddDownload; diff --git a/app/(root)/blog/page.tsx b/app/(root)/blog/page.tsx index 96f2896..17cd3a8 100644 --- a/app/(root)/blog/page.tsx +++ b/app/(root)/blog/page.tsx @@ -1,4 +1,9 @@ -import React from "react"; +import React from 'react'; +import { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Blog - SVRJS', +}; const BlogPage = () => { return
BlogPage
; diff --git a/app/(root)/docs/page.tsx b/app/(root)/docs/page.tsx index 0a57e9f..144071b 100644 --- a/app/(root)/docs/page.tsx +++ b/app/(root)/docs/page.tsx @@ -1,5 +1,11 @@ import Sidebar from '@/components/shared/Sidebar'; +import { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Docs - SVRJS', +}; + export default function Page() { return ( <> diff --git a/app/(root)/downloads/layout.tsx b/app/(root)/downloads/layout.tsx new file mode 100644 index 0000000..2840e60 --- /dev/null +++ b/app/(root)/downloads/layout.tsx @@ -0,0 +1,11 @@ +import { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Downloads - SVRJS', +}; + +const ModLayout = ({ children }: { children: React.ReactNode }) => { + return
{children}
; +}; + +export default ModLayout; diff --git a/app/(root)/forum/page.tsx b/app/(root)/forum/page.tsx index 755fa7f..2effb06 100644 --- a/app/(root)/forum/page.tsx +++ b/app/(root)/forum/page.tsx @@ -1,4 +1,9 @@ -import React from "react"; +import React from 'react'; +import { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Forum - SVRJS', +}; const Forum = () => { return
Forum
; diff --git a/app/(root)/layout.tsx b/app/(root)/layout.tsx index 1776783..78be397 100644 --- a/app/(root)/layout.tsx +++ b/app/(root)/layout.tsx @@ -1,16 +1,21 @@ -import Footer from "@/components/shared/Footer"; -import Navbar from "@/components/shared/Navbar"; +import Footer from '@/components/shared/Footer'; +import Navbar from '@/components/shared/Navbar'; +import { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Home - SVRJS', +}; export default function PageLayout({ - children, + children, }: { - children: React.ReactNode; + children: React.ReactNode; }) { - return ( -
- -
{children}
-
-
- ); + return ( +
+ +
{children}
+
+
+ ); } diff --git a/app/(root)/login/page.tsx b/app/(root)/login/page.tsx deleted file mode 100644 index 2d9d1aa..0000000 --- a/app/(root)/login/page.tsx +++ /dev/null @@ -1,52 +0,0 @@ -'use client'; -import React, { useState } from 'react'; -import { useRouter } from 'next/navigation'; - -const Login = () => { - const [username, setUsername] = useState(''); - const [password, setPassword] = useState(''); - const router = useRouter(); - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - const res = await fetch('/api/login', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ username, password }), - }); - - if (res.ok) { - router.push('/add-download'); - } else { - alert(res.status); - } - }; - return ( -
-
- - ) => { - setUsername(e.target.value); - }} - /> -
-
- - ) => { - setPassword(e.target.value); - }} - /> -
- -
- ); -}; - -export default Login; diff --git a/app/(root)/mods/layout.tsx b/app/(root)/mods/layout.tsx new file mode 100644 index 0000000..47afa8d --- /dev/null +++ b/app/(root)/mods/layout.tsx @@ -0,0 +1,11 @@ +import { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'MOD - SVRJS', +}; + +const ModLayout = ({ children }: { children: React.ReactNode }) => { + return
{children}
; +}; + +export default ModLayout; diff --git a/app/(root)/mods/page.tsx b/app/(root)/mods/page.tsx index b83bb73..c05815e 100644 --- a/app/(root)/mods/page.tsx +++ b/app/(root)/mods/page.tsx @@ -1,4 +1,7 @@ -import { Button } from "@/components/ui/button"; +'use client'; + +import { useEffect, useState } from 'react'; +import { Button } from '@/components/ui/button'; import { Table, TableBody, @@ -7,53 +10,61 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { Download } from "lucide-react"; -import Link from "next/link"; +} from '@/components/ui/table'; +import { Download } from 'lucide-react'; +import Link from 'next/link'; -const downloads = [ - { - date: "2024-06-01", - fileName: "SVRJS_v1.0.0.zip", - version: "1.0.0", - fileSize: "15MB", - downloadLink: "/downloads/SVRJS_v1.0.0.zip", - }, - { - date: "2024-06-10", - fileName: "SVRJS_v1.1.0.zip", - version: "1.1.0", - fileSize: "18MB", - downloadLink: "/downloads/SVRJS_v1.1.0.zip", - }, - { - date: "2024-06-15", - fileName: "SVRJS_v1.2.0.zip", - version: "1.2.0", - fileSize: "20MB", - downloadLink: "/downloads/SVRJS_v1.2.0.zip", - }, - { - date: "2024-06-20", - fileName: "SVRJS_v1.3.0.zip", - version: "1.3.0", - fileSize: "22MB", - downloadLink: "/downloads/SVRJS_v1.3.0.zip", - }, -]; +interface Download { + _id: string; + date: string; + fileName: string; + version: string; + fileSize: string; + downloadLink: string; +} + +const DownloadPage: React.FC = () => { + const [downloads, setDownloads] = useState([]); + const [error, setError] = useState(''); + + const fetchDownloads = async () => { + try { + const response = await fetch('/api/mods', { + method: 'GET', + }); + if (response.ok) { + const data: Download[] = 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); + }, []); -const Mods = () => { return (

- SvrJS Mods + Downloads

- Get all the latest version of SVRJS Mods and compiled Files here! + Get all the latest version of SVRJS download and compiled Files here!

+ {error &&

{error}

} A list of all available downloads. @@ -61,31 +72,34 @@ const Mods = () => { Date File Name Version - Download Link - File Size + File Size + Download Link - {downloads.map((download) => ( - - {download.date} - {download.fileName} - {download.version} - {download.fileSize} - - - - - - - ))} + {downloads + .slice(0, 10) + .reverse() + .map((download) => ( + + {download.date} + {download.fileName} + {download.version} + {download.fileSize} + + + + + + + ))}
); }; -export default Mods; +export default DownloadPage; diff --git a/app/api/mods/route.ts b/app/api/mods/route.ts new file mode 100644 index 0000000..93000f0 --- /dev/null +++ b/app/api/mods/route.ts @@ -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 } + ); + } +} diff --git a/app/api/uploadmods/route.ts b/app/api/uploadmods/route.ts new file mode 100644 index 0000000..143dbad --- /dev/null +++ b/app/api/uploadmods/route.ts @@ -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 }); +} diff --git a/constants/index.tsx b/constants/index.tsx index c6e72d7..7d8e143 100644 --- a/constants/index.tsx +++ b/constants/index.tsx @@ -1,53 +1,53 @@ -import { BadgeAlert, BarChart4, Cog, ShieldCheck } from "lucide-react"; -import { Download, Home, Settings, User } from "lucide-react"; +import { BadgeAlert, BarChart4, Cog, ShieldCheck } from 'lucide-react'; +import { Download, Home, Settings, User } from 'lucide-react'; export const NAVBAR = { centerLinks: [ { - href: "/", - target: "_self", - label: "Home", + href: '/', + target: '_self', + label: 'Home', }, { - href: "/docs", - target: "_self", - label: "Docs", + href: '/docs', + target: '_self', + label: 'Docs', }, { - href: "/forum", - target: "_self", - label: "Forum", + href: '/forum', + target: '_self', + label: 'Forum', }, { - href: "/blog", - target: "_self", - label: "Blog", + href: '/blog', + target: '_self', + label: 'Blog', }, ], rightLinks: [ { - label: "Git", - target: "_blank", - href: "https://git.svrjs.org/", + label: 'Git', + target: '_blank', + href: 'https://git.svrjs.org/', }, ], }; export const stats = [ { - title: "Downloads", + title: 'Downloads', count: 69, }, { - title: "Users", + title: 'Users', count: 42, }, { - title: "Stars", + title: 'Stars', count: 6, }, { - title: "Products", + title: 'Products', count: 2, }, ]; @@ -55,121 +55,121 @@ export const stats = [ export const Features = [ { icon: , - title: "Complete Secured ", + title: 'Completely Secured ', description: - "lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor", + 'lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor', }, { icon: , - title: "Best Support", + title: 'Best Support', description: - "lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor", + 'lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor', }, { icon: , - title: "Most Scalable ", + title: 'Most Scalable ', description: - "lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor", + 'lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor', }, { icon: , - title: "Fully Configurable ", + title: 'Fully Configurable ', description: - "lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor", + 'lorem ipsum dolor sit amet, consectetur adip lorem ipsum dolor lorem ipsum dolor', }, ]; export const questions = [ { - key: "item-1", - question: "What is a web server?", + key: 'item-1', + question: 'What is a web server?', answer: - "A web server is computer software that accepts HTTP requests and serves websites. Web servers can also be underlying hardware running web server software.", + 'A web server is computer software that accepts HTTP requests and serves websites. Web servers can also be underlying hardware running web server software.', }, { - key: "item-2", - question: "What is SVR.JS?", + key: 'item-2', + question: 'What is SVR.JS?', answer: - "SVR.JS is web server software running on Node.JS that can host both static and dynamic content. With additional mods, SVR.JS can be used for different types of dynamic content and can even be used as a forward or reverse proxy. SVR.JS is licensed under a permissive MIT/X11 license", + 'SVR.JS is web server software running on Node.JS that can host both static and dynamic content. With additional mods, SVR.JS can be used for different types of dynamic content and can even be used as a forward or reverse proxy. SVR.JS is licensed under a permissive MIT/X11 license', }, { - key: "item-3", - question: "How was SVR.JS created?", + key: 'item-3', + question: 'How was SVR.JS created?', answer: - "Someone in 2018 wanted to create a website, but he didnt know about setting up popular web server software like Apache httpd, NGINX, or IIS... So he created his own web server in Node.JS to serve his website! And he saved it in a file called svr.js. Since then, this web server has been gradually turned from a web server intended for one website into a general-purpose web server, which is what SVR.JS is today!", + 'Someone in 2018 wanted to create a website, but he didnt know about setting up popular web server software like Apache httpd, NGINX, or IIS... So he created his own web server in Node.JS to serve his website! And he saved it in a file called svr.js. Since then, this web server has been gradually turned from a web server intended for one website into a general-purpose web server, which is what SVR.JS is today!', }, { - key: "item-4", - question: "How did SVR.JS get its name?", + key: 'item-4', + question: 'How did SVR.JS get its name?', answer: - "SVR.JS got its name from the original name of the server script: svr.js, one of many generic file names for a server written in JavaScript.", + 'SVR.JS got its name from the original name of the server script: svr.js, one of many generic file names for a server written in JavaScript.', }, { - key: "item-5", - question: "What is Node.JS?", + key: 'item-5', + question: 'What is Node.JS?', answer: - "Node.JS is an asynchronous event-driven JavaScript runtime built on Chromiums V8 engine. Node.JS is designed to build scalable network applications.", + 'Node.JS is an asynchronous event-driven JavaScript runtime built on Chromiums V8 engine. Node.JS is designed to build scalable network applications.', }, { - key: "item-6", - question: "How can I use SVR.JS?", + key: 'item-6', + question: 'How can I use SVR.JS?', answer: - "You can read the documents to learn how to use the SVR.JS web server.", + 'You can read the documents to learn how to use the SVR.JS web server.', }, ]; export const FOOTERLINKS = { otherPages: [ - { href: "/", label: "Home" }, - { href: "/contact", label: "Contact" }, - { href: "/blog", label: "Blog" }, - { href: "/forum", label: "Forum" }, + { href: '/', label: 'Home' }, + { href: '/contact', label: 'Contact' }, + { href: '/blog', label: 'Blog' }, + { href: '/forum', label: 'Forum' }, ], plans: [ - { href: "/docs", label: "Docs" }, - { href: "/downloads", label: "Downloads" }, - { href: "/tos", label: "Terms of Serivce" }, - { href: "/privacy-policy", label: "Privacy Policy" }, + { href: '/docs', label: 'Docs' }, + { href: '/downloads', label: 'Downloads' }, + { href: '/tos', label: 'Terms of Serivce' }, + { href: '/privacy-policy', label: 'Privacy Policy' }, ], social: { - supportText: "Support Us on Socials", + supportText: 'Support Us on Socials', }, footerBottom: { designedBy: { - href: "https://abhijee.com", - label: "Proxy", + href: 'https://abhijee.com', + label: 'Proxy', }, rightsReserved: { - href: "https://cyprostudio.com", - label: "SVRJS", + href: 'https://cyprostudio.com', + label: 'SVRJS', }, }, }; export const AdminLinks = [ { - name: "Dashboard", - url: "/admin", + name: 'Dashboard', + url: '/admin', icon: Home, }, { - name: "Downloads", - url: "/admin/downloads", + name: 'Downloads', + url: '/admin/downloads', icon: Download, }, { - name: "Mods", - url: "/admin/mods", + name: 'Mods', + url: '/admin/mods', icon: User, }, { - name: "Logs", - url: "/admin/changelogs", + name: 'Logs', + url: '/admin/changelogs', icon: Settings, }, { - name: "Back Home", - url: "/", + name: 'Back Home', + url: '/', icon: Home, }, ]; diff --git a/lib/validations/validation.ts b/lib/validations/validation.ts index 4cbcaab..d795ead 100644 --- a/lib/validations/validation.ts +++ b/lib/validations/validation.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from 'zod'; export const downloadSchema = z.object({ fileName: z.string().nonempty(), @@ -6,3 +6,10 @@ export const downloadSchema = z.object({ downloadLink: z.string().url().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(), +});