diff --git a/.eslintrc.json b/.eslintrc.json index 3722418..e0fedbd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,6 @@ { - "extends": ["next/core-web-vitals", "next/typescript"] + "extends": ["next/core-web-vitals", "next/typescript"], + "rules": { + "@typescript-eslint/no-empty-object-type": "off" + } } diff --git a/app/api/auth/[...nextauth]/options.ts b/app/api/auth/[...nextauth]/options.ts new file mode 100644 index 0000000..e6f7cdb --- /dev/null +++ b/app/api/auth/[...nextauth]/options.ts @@ -0,0 +1,38 @@ +import { NextAuthOptions, Session, User } from "next-auth"; +import GoogleProvider from "next-auth/providers/google"; +import { PrismaAdapter } from "@next-auth/prisma-adapter"; +import prisma from "@/lib/db"; +import { JWT } from "next-auth/jwt"; + + + +export const authOption : NextAuthOptions= { + providers: [ + GoogleProvider({ + clientId: process.env.GOOGLE_CLIENT_ID!, + clientSecret: process.env.GOOGLE_CLIENT_SECRET!, + }), + ], + adapter: PrismaAdapter(prisma), + callbacks: { + session: async ({ session, token }: { session: Session; token: JWT }) => { + if (token && session.user) { + session.user.id = token.sub; + session.user.email = token.email; + } + return session; + }, + signIn: async ({ user }: { user: User; }) => { + if(user.email === "devsharmasoe@gmail.com" || user.email?.includes("@iilm.edu")){ + return true; + }else{ + return false; + } + }, + + }, + session: { + strategy: "jwt" + } + + }; \ No newline at end of file diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index 42d28b4..f50e728 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -1,31 +1,5 @@ -import NextAuth, { Session, AuthOptions } from "next-auth"; -import GoogleProvider from "next-auth/providers/google"; -import { PrismaAdapter } from "@next-auth/prisma-adapter"; -import prisma from "@/lib/db"; -import { JWT } from "next-auth/jwt"; - -export const authOption: AuthOptions = { - providers: [ - GoogleProvider({ - clientId: process.env.GOOGLE_CLIENT_ID!, - clientSecret: process.env.GOOGLE_CLIENT_SECRET!, - }), - ], - secret: process.env.NEXTAUTH_SECRET!, - session: { - strategy: "jwt", // This ensures TypeScript recognizes this as a valid strategy - }, - adapter: PrismaAdapter(prisma), - callbacks: { - session: async ({ session, token }: { session: Session; token: JWT }) => { - if (token && session.user) { - session.user.id = token.sub; - session.user.email = token.email; - } - return session; - }, - }, -}; +import NextAuth from "next-auth"; +import { authOption } from "./options"; const handler = NextAuth(authOption); diff --git a/app/api/test/route.ts b/app/api/test/route.ts deleted file mode 100644 index 621395a..0000000 --- a/app/api/test/route.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { addCategoriesToDB } from "@/lib/db/addData" -import { NextResponse } from "next/server" - -export const GET = async ()=>{ - await addCategoriesToDB() - return NextResponse.json({ - message: "everything worked fine" - }) -} \ No newline at end of file diff --git a/app/category/[categoryId]/[documentId]/loading.tsx b/app/category/[categoryId]/[documentId]/loading.tsx new file mode 100644 index 0000000..a918df1 --- /dev/null +++ b/app/category/[categoryId]/[documentId]/loading.tsx @@ -0,0 +1,13 @@ +import { Loader } from 'lucide-react' +import React from 'react' + + +const loading = () => { + return ( +
+ +
+ ) +} + +export default loading diff --git a/app/document/[documentId]/page.tsx b/app/category/[categoryId]/[documentId]/page.tsx similarity index 51% rename from app/document/[documentId]/page.tsx rename to app/category/[categoryId]/[documentId]/page.tsx index bab0e04..c777838 100644 --- a/app/document/[documentId]/page.tsx +++ b/app/category/[categoryId]/[documentId]/page.tsx @@ -1,6 +1,14 @@ import Document from '@/components/Document' +import prisma from '@/lib/db' import React from 'react' +export async function generateStaticParams() { + const documents = await prisma.document.findMany() + return documents.map((post) => ({ + documentId: post.id, + })) +} + const Page = ({params : {documentId}} : {params:{documentId: string}}) => { return (
@@ -9,4 +17,4 @@ const Page = ({params : {documentId}} : {params:{documentId: string}}) => { ) } -export default Page +export default Page \ No newline at end of file diff --git a/app/category/[categoryId]/loading.tsx b/app/category/[categoryId]/loading.tsx new file mode 100644 index 0000000..ee2fa96 --- /dev/null +++ b/app/category/[categoryId]/loading.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import { Skeleton } from "@/components/ui/skeleton"; +import { AppBreadCrumb } from "@/components/AppBreadCrumb"; +import { Separator } from "@/components/ui/separator"; + + +const loading = () => { + return ( +
+
+ +
+
+ +
+
+ +
+ {[0, 1, 2, 3, 4, 5, 6].map((id) => { + return ; + })} +
+ ); +}; + +export default loading; diff --git a/app/category/[categoryId]/page.tsx b/app/category/[categoryId]/page.tsx index a21daa9..650f853 100644 --- a/app/category/[categoryId]/page.tsx +++ b/app/category/[categoryId]/page.tsx @@ -1,6 +1,13 @@ import Category from '@/components/Category' +import prisma from '@/lib/db' import React from 'react' +export async function generateStaticParams() { + const categories = await prisma.category.findMany() + return categories.map((post) => ({ + categoryId: post.id, + })) +} const Page = ({params : {categoryId}} : {params:{categoryId: string}}) => { diff --git a/app/layout.tsx b/app/layout.tsx index 7b2024d..f854bc8 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -18,8 +18,8 @@ const geistMono = localFont({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "CMS | AI/ML", + description: "ALL notes of AI ML", }; export default function RootLayout({ @@ -29,6 +29,7 @@ export default function RootLayout({ }>) { return ( + diff --git a/app/loading.tsx b/app/loading.tsx new file mode 100644 index 0000000..5ac7937 --- /dev/null +++ b/app/loading.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { Skeleton } from "@/components/ui/skeleton"; +import { AppBreadCrumb } from "@/components/AppBreadCrumb"; + +const loading = () => { + return ( +
+
+ + +
+
+ +
+ {[0, 1, 2, 3, 4, 5, 6].map((id) => { + return ; + })} +
+ ); +}; + +export default loading; diff --git a/app/login/page.tsx b/app/login/page.tsx index 9745761..48a1fe5 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -1,33 +1,45 @@ -"use client" -import React from 'react'; -import Image from 'next/image'; -import { signIn } from 'next-auth/react'; +"use client"; +import React from "react"; +import Image from "next/image"; +import { signIn } from "next-auth/react"; +import { Boxes } from "@/components/ui/background-boxes"; -const page = () => { - - const handleClick = ()=>{ - signIn("google") - } +const Page = () => { + const handleClick = () => { + try { + signIn("google"); + } catch (error) { + console.log(error); + } + }; return ( -
-
-

- CMS - AI/ML -

-

+

+
+ +
+

CMS - AI/ML

+

A single place for all AI/ML notes.

-
-goole -

- Continue with Google. -

+
+ goole +

+ Continue with Google. +

- ) -} + ); +}; -export default page +export default Page; diff --git a/app/page.tsx b/app/page.tsx index ec99431..c08cc30 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,27 +1,28 @@ - -import { Upload } from "lucide-react" import prisma from "@/lib/db"; import Categories from "@/components/CategoryGroup"; +import { AppBreadCrumb } from "@/components/AppBreadCrumb"; +import SearchBar from "@/components/SearchBar"; - -const getAllCategories = async ()=>{ -return await prisma.category.findMany() -} - +const getAllCategories = async () => { + return await prisma.category.findMany(); +}; export default async function Home() { - -const result = await getAllCategories() + const result = await getAllCategories(); return (
-
- -

- Uplaod Document! -

+
+

All Topics

+

Total topics : {result.length}

+
+
+ +
+
+
- +
); } diff --git a/components/AddDocument.tsx b/components/AddDocument.tsx index 19ece7a..c2cc7ce 100644 --- a/components/AddDocument.tsx +++ b/components/AddDocument.tsx @@ -1,5 +1,5 @@ "use client"; -import React from "react"; +import React, { useState } from "react"; import { Dialog, DialogContent, @@ -9,7 +9,7 @@ import { DialogTrigger, } from "@/components/ui/dialog"; import { Button } from "./ui/button"; -import { Upload } from "lucide-react"; +import { Loader, Upload } from "lucide-react"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; @@ -35,6 +35,10 @@ const formSchema = z.object({ }); const AddDocument = ({ categoryId }: { categoryId: string }) => { + +const [isOpen,setIsOpen] = useState(false) +const [isLoading,setIsLoading] = useState(false) + const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { @@ -44,20 +48,32 @@ const AddDocument = ({ categoryId }: { categoryId: string }) => { }, }); - function onSubmit(values: z.infer) { - const formData = new FormData - formData.append("documentName", values.documentName) - formData.append("categoryId", values.categoryId) - formData.append("file", values.file) - uploadDocument(formData) + async function onSubmit(values: z.infer) { + try { + setIsLoading(true) + const formData = new FormData + formData.append("documentName", values.documentName) + formData.append("categoryId", values.categoryId) + formData.append("file", values.file) + const result = await uploadDocument(formData) + if(result){ + setIsOpen(false) + } + } catch (error) { + console.log(error) + setIsOpen(false) + }finally{ + setIsLoading(false) + } + } return ( - + + diff --git a/components/AppBreadCrumb.tsx b/components/AppBreadCrumb.tsx new file mode 100644 index 0000000..4630b96 --- /dev/null +++ b/components/AppBreadCrumb.tsx @@ -0,0 +1,47 @@ +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb"; + +interface BreadCrumbPropType { + links: { + title: string; + link: string; + }[]; +} + +export function AppBreadCrumb({ links }: BreadCrumbPropType) { + return ( + + + + Home + + {links.map(({ link, title }, index) => { + if (index + 1 === links.length) { + return ( + <> + + + {title} + + + ); + } + return ( + <> + + + {title} + + + ); + })} + + + ); +} diff --git a/components/Category.tsx b/components/Category.tsx index e2947bf..542c811 100644 --- a/components/Category.tsx +++ b/components/Category.tsx @@ -1,46 +1,62 @@ -import React from 'react' -import prisma from '@/lib/db' -import { Separator } from "@/components/ui/separator" -import AddDocument from './AddDocument' -import DocumentGroup from './DocumentGroup' - - -const getDocumentsOfCategory = async(id : string)=>{ -return await prisma.category.findFirst({where: {id: id}, include: {documents: {include: {user: {select: {email: true, image: true}}}}}}) -} - -const Category = async ({categoryId}: {categoryId : string}) => { - - const result = await getDocumentsOfCategory(categoryId) - console.log(result) - const count = result?.documents.length +import React from "react"; +import prisma from "@/lib/db"; +import { Separator } from "@/components/ui/separator"; +import AddDocument from "./AddDocument"; +import DocumentGroup from "./DocumentGroup"; +import { AppBreadCrumb } from "./AppBreadCrumb"; +import { getServerSession } from "next-auth"; +import { authOption } from "@/app/api/auth/[...nextauth]/options"; + +const getDocumentsOfCategory = async (id: string) => { + return await prisma.category.findFirst({ + where: { id: id }, + include: { + documents: { + include: { user: { select: { email: true, image: true } } }, + }, + }, + }); +}; + +const Category = async ({ categoryId }: { categoryId: string }) => { + const result = await getDocumentsOfCategory(categoryId); + const count = result?.documents.length; + const session = await getServerSession(authOption); return (
-
-
-

- {result?.name} -

-
- +
+
+
+
+

+ {result?.name} +

+
+ {session?.user.email === "devsharmasoe@gmail.com" && ( + + )} +
- - +
-
-

{count === 0 && "No document find. Click on the button to add."}

+
+

+ {count === 0 && "No document find. Click on the button to add."} +

-
- {result && - - } -
+ {result && ( + + )}
- ) -} + ); +}; -export default Category +export default Category; diff --git a/components/CategoryGroup.tsx b/components/CategoryGroup.tsx index e0e0cd5..425866d 100644 --- a/components/CategoryGroup.tsx +++ b/components/CategoryGroup.tsx @@ -3,15 +3,19 @@ import React from "react"; import { Category } from "@/lib/types"; import { Card, CardHeader, CardTitle } from "@/components/ui/card"; import Link from "next/link"; +import { Folder } from "lucide-react"; const Categories = ({ categories }: { categories: Category[] }) => { return ( <> {categories.map(({ name, id }) => { - return ( - - - {name} + return ( + + + + + {name} + diff --git a/components/Document.tsx b/components/Document.tsx index 8192091..b0fa8a0 100644 --- a/components/Document.tsx +++ b/components/Document.tsx @@ -1,18 +1,37 @@ -import prisma from '@/lib/db' -import React from 'react' +import prisma from "@/lib/db"; +import React from "react"; +import { AppBreadCrumb } from "./AppBreadCrumb"; -const getDocument = async(id: string)=>{ -return await prisma.document.findFirst({where: {id: id}}) -} -const Document = async ({documentId}: {documentId: string}) => { - - const result = await getDocument(documentId) +const getDocument = async (id: string) => { + return await prisma.document.findFirst({ + where: { id: id }, + include: { categories: true }, + }); +}; +const Document = async ({ documentId }: { documentId: string }) => { + const result = await getDocument(documentId); return ( -
-