You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// It's very important to follow proper Next.js naming conventions; otherwise, Next.js may not compile correctly, and you may run into unwanted performance issues.// If you run into any issues, remember to restart your development server and review the names and issues.
// If you ever get stuck on hydration, watch Timestamp 01:58// "use client";importImagefrom"next/image";importstylesfrom"./contact.module.css";// import dynamic from "next/dynamic";// import HydrationTest from "@/components/hydrationTest";// const HydrationTestNoSSR = dynamic(()=>import("@/components/hydrationTest"), {ssr: false})exportconstmetadata={title: "Contact Page",description: "Contact description",};constContactPage=()=>{// const a = Math.random();// console.log(a);return(<divclassName={styles.container}><divclassName={styles.imgContainer}><Imagesrc="/contact.png"alt=""fillclassName={styles.img}/></div><divclassName={styles.formContainer}>{/* <HydrationTestNoSSR/> */}{/* <div suppressHydrationWarning>{a}</div> */}<formaction=""className={styles.form}><inputtype="text"placeholder="Name and Surname"/><inputtype="text"placeholder="Email Address"/><inputtype="text"placeholder="Phone Number (Optional)"/><textareaname=""id=""cols="30"rows="10"placeholder="Message"></textarea><button>Send</button></form></div></div>);};exportdefaultContactPage;
// It's like using Navigate("/Auth") in React via react-router-dom, but it's better in Next.js because of its flexibility and simple functionality. Timestamp: 2:08 (watch the section; it's pretty interesting, forcing users to shift routes and querying and its pretty simple code )."use client"importLinkfrom"next/link"import{usePathname,useRouter,useSearchParams}from"next/navigation"//updated and higher vir import don't forget Next/<import> is always recommendconstNavigationTestPage=()=>{// CLIENT SIDE NAVIGATIONconstrouter=useRouter()constpathname=usePathname()constsearchParams=useSearchParams()constq=searchParams.get("q")console.log(q)// The URL is "/navigation?q=test". Basically, he's just getting the query, which is great for filtering and searching within your site.consthandleClick=()=>{console.log("clicked")router.forward()}return(<div><Linkhref="/"prefetch={false}>Click here</Link><buttononClick={handleClick}>Write and Redirect</button></div>)}exportdefaultNavigationTestPage
API Fetching
//don't use {cache: "no-store"} when you have large amounts fo data changing, but if your data is relatively constant with minor changes then use it,constres=awaitfetch("https://jsonplaceholder.typicode.com/posts",{cache: "no-store",});//{revalidate:3600} will refresh your data every 1 hour = 3600constres=awaitfetch("https://jsonplaceholder.typicode.com/posts",{next: {revalidate: 3600},});
// cool concept:// since the each blog holds all of the json place holder inc the user id and id, by linking }href={`/blog/${post.id}`}// we can get the id from each post and travel inside of it//THIS IS ONLY POSSIBLE BECAUSE OF THE WAY THE BLONDE FILES ARE STORED, AND THE SLUG//this will take in dynamic id giving by the blog from the api<LinkclassName={styles.link}href={`/blog/${post.id}`}>
READ MORE
</Link>
// In Next.js, when using dynamic routes, you can access the route parameters (like the slug or post ID) through the params object in the page component's props. This is part of Next.js's built-in functionality for handling dynamic routes.constSinglePostPage=async({ params })=>{// using params, slug is passed as a parameter its a built in function in nextjsconst{slug}=paramsconstposts=awaitgetData(slug)//passing slug as a parameter in side getdata (fetch func), slug's raw value is /blog/[slug]// The params object allows you to access the dynamic route parameters passed to the page component in Next.js.
importImagefrom"next/image";importReact,{Suspense}from"react";importstylesfrom"./singlePost.module.css";importPostUserfrom"@/components/postUser/PostUser";constgetData=async(slug)=>{constres=awaitfetch(`https://jsonplaceholder.typicode.com/posts/${slug}`);// using slug as a parameter// THIS WHOLE API IS STRUCTURED AROUND USER, POST'S AND OTHER DATA YOU WOULD SEE IN SOCIAL MEDIAif(!res.ok){thrownewError("Something went wrong");}returnres.json();};constSinglePostPage=async({ params })=>{// using params, slug is passed as a parameter its a buit in function in nextjsconst{ slug }=params;constposts=awaitgetData(slug);//passing slug as a parameter in side getdata, slug's raw value is /blog/[slug]return(<divclassName={styles.container}><divclassName={styles.imgContainer}><Imagesrc="https://images.pexels.com/photos/19294343/pexels-photo-19294343/free-photo-of-pink-car.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"alt=""fillclassName={styles.img}/></div><divclassName={styles.textContainer}><h1className={styles.title}>{posts.title}</h1><divclassName={styles.detail}><Suspensefallback={<div>Loading...</div>}><PostUseruserId={posts.userId}/></Suspense>{/* passing userId from `https://jsonplaceholder.typicode.com/posts/` allowing me to access a single post from the api */}<divclassName={styles.detailText}><spanclassName={styles.detailTitle}>aUTHOR</span><spanclassName={styles.detailValue}>detailValue</span></div><divclassName={styles.detailText}><spanclassName={styles.detailTitle}>Published</span><spanclassName={styles.detailValue}>detailValue</span></div></div><divclassName={styles.content}>{posts.body}</div></div></div>);};exportdefaultSinglePostPage;
// Don't pay attention to this code too much; it's just an example of how you can communicate code between data (node) to next.js + App and Components , rather than using fetching an API within the page's .jsx. It's cleaner to put all functional code in your lib/data.js.// Fetching all the posts from the mock APIexportconstgetPosts=async()=>{returnposts;// returning all the posts};// Fetching a single post from the mock APIexportconstgetPost=async(id)=>{// finding the post based on the idconstpost=posts.find((post)=>post.id===parseInt(id));// returning the found postreturnpost;};// Fetching a user from the mock APIexportconstgetUser=async(id)=>{// finding the user based on the idconstuser=users.find((user)=>user.id===parseInt(id));// returning the found userreturnuser;};// Sample dataconstusers=[{id: 1,name: "John"},{id: 2,name: "Jane"},];constposts=[{id: 1,title: "Post 1",body: "......",userId: 1},{id: 2,title: "Post 2",body: "......",userId: 1},{id: 3,title: "Post 3",body: "......",userId: 2},{id: 4,title: "Post 4",body: "......",userId: 2},];
// After logging in and creating a project, and creating a cluster, you need to press "Connect" and follow the instructions.// - npm install mongodb// - mongodb+srv://bhattaraianjesh123:<password>@cluster0.l7tduy7.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0// simple boilerplate code: boilerplate code means you don't have to memorize itconstmongoose=require("mongoose");constconnection={};exportconstconnectToDb=async()=>{try{if(connection.isConnected){console.log("using an existing connection");return;}constdb=awaitmongoose.connect(process.env.MONGO_URI);connection.isConnected=db.connections[0].readyState;}catch(error){console.log(error);thrownewError("Failed to connect to MongoDB: `"+error+"`");}};
// So, I found out that your .env file must not contain white spaces. My mistake was having a space between '=' because I assumed it was a normal variable declaration.MONGO_URI="";// correctMONGO_URI="";// incorrect
//common tut miskate//he keeps reandeirng{post?.desc;}//and at time i forget to add ? and my whole program falls into errors
// For a better SEO//When the title is generated, the %s placeholder will be replaced with a specific value. For example, if you have a page with the title "About Us", the %s will be replaced with "About Us", resulting in the title "About Us | Next.js 14".exportconstmetadata={//layout.jsxtitle: {default: "Next.js 14 Homepage",template: "%s | Next.js 14",// it seems like a place holder, like a template `%{pageTitle}`},description: "Next.js starter app description",};//-----------------------exportconstmetadata={// about/page.jsxtitle: "About Page",description: "About description",};//---------------------// src\app\blog\[slug]\page.jsxexportconstgenerateMetadata=async({ params })=>{const{ slug }=params;constpost=awaitgetData(slug);return{title: post.title,description: post.desc,};};
API Fetching VS Server Actions
// Server actions in Next.js typically involve operations that occur on the server side,// such as fetching data or performing computations, before the page is rendered.// These actions are executed within the Next.js server environment.// API fetching, on the other hand, involves making requests to external APIs to retrieve data// for use in client-side rendering. This fetching usually happens on the client side,// allowing for dynamic updates without full page reloads.//exmaples below// pages/serverData.jsexportasyncfunctiongetServerSideProps(context){// Fetch data from an API or perform server-side computationsconstdata=awaitfetchDataFromServer();// Pass data to the page component as propsreturn{props: {
data,},};}functionServerData({ data }){// Render the page with server-side datareturn(<div><h1>Server-side Data</h1><p>{data}</p></div>);}exportdefaultServerData;// pages/clientData.jsimport{useEffect,useState}from'react';functionClientData(){const[data,setData]=useState('');useEffect(()=>{// Fetch data from an API or perform client-side computationsconstfetchData=async()=>{constresponse=awaitfetch('https://api.example.com/data');constresult=awaitresponse.json();setData(result);};fetchData();},[]);// Render the page with client-side datareturn(<div><h1>Client-side Data</h1><p>{data}</p></div>);}exportdefaultClientData;
Server Action's Example
//lib/actionconstsayHello=async()=>{// when use server it has to be async"use server";console.log("hello");}//serveractiontest/page.jsximportReactfrom'react'import{sayHello}from"@/lib/action"// I forgot the function name was sayHello and not say(h)ello (lower case "h"). Make sure you always have a good naming convention to stop these types of stupid errors, and actually read the code. Maybe TypeScript is good, but then again I didn't read the error correctly. Maybe I should have hovered over 'i' and read it.constServerActionTest=()=>{// Yeah, so action outputs anything as long as a button is present, basically like a form submit, but without the type="submit".return(<div><formaction={sayHello}><button> test </button></form></div>)}exportdefaultServerActionTest// If "use server" is included, your function will be executed on the server// and it needs to be an async function.// If it is not intended to be a server component, you can leave it as it is.// You can remove "async" if its not intended to bt asynchronous. In the page.jsx, you must add "use client"// to tell the renderer it is a client component, so render it in the client, please.//----------------------------------------------------------------------------------// By removing "use server" from a function in Next.js, it becomes a regular JavaScript function not bound by Next.js's rendering rules. It can execute both on the server and the client.// If you use "use client" on a function, it indicates that this function should only execute on the client-side, meaning it won't run during server-side rendering but will run in the browser once the page is loaded.// However, removing "use server" doesn't prevent the function from rendering on the server; it simply means the function can execute on both the server and the client, depending on the context in which it's called.exportconstsayHello=()=>{console.log("hello");}"use client"importReactfrom'react'import{sayHello}from"@/lib/action"constServerActionTest=()=>{return(<div><formaction={sayHello}><button> test </button></form></div>)}exportdefaultServerActionTest
action is for use server and handle submit is for use client
//works well and has no issues, it and handel submit is not that far apartconsthandleInputLog=async(e)=>{//you still need to pass in event// he dose need a the event, it is automatically passed to the event handler function"use server";const{ text }=Object.fromEntries(e);// since you don't have a state connected to your input with onChange// you have to destructrue it, and your event is an object tooconsole.log(text);//logging text, normally you can log state};return(<div>{/* extracts the event and auto passing it to the function within {} */}<formonSubmit={handleInputLog}><inputtype="text"placeholder="text"name="text"/><button>click</button>{/* form auto assign's this a type="submit" */}</form></div>);};//READ THE STUFF I WROTE AND BACK CHECKED BELOW
Server Side Input's with "action={}" and name
importReactfrom"react";import{addPost}from"@/lib/action";return(<div>{/* //so when i use Action, i am directing the location of where the data event will be sent to. BTW: React automatically passes the event object to the event handler function */}{/*onSubmit is a client-side event handler for form submissions, while action is an HTMLattribute that defines the server-side endpoint where form data should be sent. */}<formaction={addPost}><inputtype="text"placeholder="title"name="title"/>{" "}{/* The "name" attribute is primarily used to identify form data on the server-side or when accessing form data via JavaScript on the client-side. */}<inputtype="text"placeholder="desc"name="desc"/><inputtype="text"placeholder="slug"name="slug"/><inputtype="text"placeholder="userId"name="userId"/><buttontype="submit"> test </button>{" "}</form></div>);};exportdefaultServerActionTest;
Grasping Server Side input concepts and Other
/* In React, when you define a form with an onSubmit event handler, React automatically passes the event object to the event handler function when the form is submitted. Therefore, in your addPost function, you can access the event object if needed. */import{Post}from"./models";import{connectToDb}from"./utils";/* //so when i use Action, i am directing the location of where the event will be sent to. BTW: React automatically passes the event object to the event handler function */// action attribute: Specifies the URL for form data processing.// It directs the browser to send a request to this URL when the form is submitted.// This traditional HTML attribute predates React and defines where the form data should be submitted.// onSubmit attribute: Specifies a JavaScript function to handle form submissions in React.// When the form is submitted, React calls the specified function (e.g., handleSubmit)// with the event object as its argument (if included).// Using event.preventDefault() within this function prevents default submission behavior,// enabling form submission handling within your React component./* onSubmit is a client-side event handler for form submissions, while action is an HTML attribute that defines the server-side endpoint where form data should be sent. */exportconstaddPost=async(formData)=>{"use server";// he get() method of FormData allows you to retrieve the value associated with a specific//name/key. So, when you call formData.get("title"), it retrieves the value entered into// the input field with the name "title". Similarly, you use the other names to retrieve the respective values entered into the input fields.// const title = formData.get("title");// const desc = formData.get("desc");// const slug = formData.get("slug");// const userId = formData.get("userId");const{ title, desc, slug, userId }=Object.fromEntries(formData);// this line above essentially converts the FormData object into a regular JavaScript// object and then extracts specific properties from it, making them available// as variables in the current scope. This approach is often used to simplify// accessing form data in JavaScript.try{connectToDb();constnewPost=newPost({ title, desc, slug, userId });awaitnewPost.save();//const newPost = new Post({ title, desc, slug, userId });://This line creates a new instance of a Post object.//await newPost.save();: This line saves the newly created Post object to the database.console.log("new post added");}catch(err){console.log(err);}console.log(title,desc,slug,userId);};// If "use server" is included, your function will be executed on the server// and it needs to be an async function.// If it is not intended to be a server component, you can leave it as it is.// You can remove "async" if its not intended to bt asynchronous. In the page.jsx, you must add "use client"// to tell the renderer it is a client component, so render it in the client, please.
POST to MongoDB (adding data to collection)
import{Post}from"./models";import{connectToDb}from"./utils";exportconstaddPost=async(formData)=>{"use server";// //creates a "new" instance of post then with the destrued elemenst from const { title, desc, slug, userId } = Object.fromEntries(formData),const{ title, desc, slug, userId }=Object.fromEntries(formData);try{// After connecting to DB, new Post (imported from the model, takes in all { title, desc, slug, userId }connectToDb();constnewPost=newPost({ title, desc, slug, userId });awaitnewPost.save();// awiat then saves await newPost.save();console.log("new post added");}catch(err){console.log(err);}console.log(title,desc,slug,userId);};
revalidatePath(`/blog`);// The revalidate option in Next.js refreshes the content//of the page on the server-side, not in the browser.// Since SSR renders static HTML pages at build time,// without revalidate, these pages would remain static until the next build.// The revalidate option ensures that the page content is periodically updated,// allowing clients to see new data, such as posts, without requiring a full rebuild// of the site.
deletePost via findByIdAndDelete(id)
//serveractiontest/page.jsx//its juts a input tag form that asks the user for an Id, and you type in the id you want then the event gets directed (REACT auto grabs the event) to @/lib/action by the action={deletePost}import{deletePost}from"@/lib/action";<formaction={deletePost}><inputtype="text"placeholder="id"name="id"/><button> test </button>{" "}</form>;//lib/action.js// export const deletePost = async (formData) Tt takes in in the event from the input given by the action={deletePost} and destructrue's the idexportconstdeletePost=async(formData)=>{const{ id }=Object.fromEntries(formData);try{connectToDb();//then it connects to the DB, try/catch to find and errorsawaitPost.findByIdAndDelete(id);//removing post via Id from form dataconsole.log(" post deleted");revalidatePath(`/blog`);// lastly it revalidatePath, (already explained = crt+F)}catch(err){console.log(err);}console.log(id);};
RestFul API
// Conceptually, it's easy to understand because I have some experience in Node.js/Express.js, and we already went through server actions and already did some API fetching to JSON placeholder a few hours before, and the code is still there just commented out. The fields are the same anyways, like post, posts, slug, params, and such.// Restful API and server actions code are not that far off because they both use MongoDB connection and other built-in functions from MongoDB. To say which one is better is hard because I like both, but Restful API wins in cases because I already have some level of experience with it, and I plan to expand on it more. However, Next.js server actions are still pretty good, and I realize I've been doing some server actions when I was using Firebase unknowingly. But I really do want to expand on my restfulness and hopefully get better at using MongoDB, a real DB. I mean Firebase is also a real DB too and has way more built-in stuff like AUTH and stuff, so maybe using them both in conjunction would be a win-win.
Using RESTFUL API, GET via Route
//src\app\api\blog\route.jsimport{Post}from"@/lib/models";import{connectToDb}from"@/lib/utils";import{NextResponse}from"next/server";exportconstGET=async(req)=>{try{connectToDb();constposts=awaitPost.find();returnNextResponse.json(posts);//NextResponse: This represents the response object that will be sent back to the client.// .json(): This is a method that converts the data passed to it (in this case, posts) into JSON format.}catch(err){console.log(err);thrownewError(err);}};//-------------------------------------// src\app\blog\page.jsximportPostCardfrom"@/components/postCard/PostCard";importstylesfrom"./blog.module.css";import{getPosts}from"@/lib/data";// FETCH DATA WITH AN APIconstgetData=async()=>{constres=awaitfetch("http://localhost:3000/api/blog",{next: {revalidate: 3600},});if(!res.ok){thrownewError("Something went wrong");}returnres.json();};constBlogPage=async()=>{// FETCH DATA WITH API (RESTFUL API)constposts=awaitgetData();// FETCH DATA WITHOUT API (SERVER ACTIONS)// const posts = await getPosts();return(<divclassName={styles.container}>{posts.map((post)=>(<PostCardkey={post.id}post={post}/>))}</div>);};exportdefaultBlogPage;
Allow Api request to access [slug] and GET via route
// src\app\api\blog\[slug]\route.jsimport{Post}from"@/lib/models";import{connectToDb}from"@/lib/utils";import{NextResponse}from"next/server";exportconstGET=async(req,{ prams })=>{const{ slug }=prams;try{connectToDb();constpost=awaitPost.findOne({ slug });//just like in src\lib\data.jsreturnNextResponse.json(post);//NextResponse: This represents the response object that will be sent back to the client.// .json(): This is a method that converts the data passed to it (in this case, posts) into JSON format.}catch(err){console.log(err);thrownewError(err);}};//-------------------------------------// src\app\blog\[slug]\page.jsx// Define an asynchronous function named getData that takes a 'slug' parameterconstgetData=async(slug)=>{// Fetch data from the specified API endpoint using the provided 'slug'constres=awaitfetch(`http://localhost:3000/api/blog/${slug}`,{// Optional: Provide configuration for Next.js Incremental Static Regenerationnext: {revalidate: 3600},// Revalidate data every 3600 seconds (1 hour)});// Check if the response is not okay (HTTP status code other than 200)if(!res.ok){// Throw an error if something went wrong with the requestthrownewError("Something went wrong");}// Return the response body as JSONreturnres.json();};constSinglePostPage=async({ params })=>{// using params, slug is passed as a parameter its a buit in function in nextjsconst{ slug }=params;constpost=awaitgetData(slug);// const post = await getPost(slug); //passing slug as a parameter in side getdata, slug's raw value is /blog/[slug]};exportdefaultSinglePostPage;
DELETE via route
exportconstDELETE=async(req,{ prams })=>{const{ slug }=prams;try{connectToDb();constpost=awaitPost.findByIdAndDelete({ slug });//just like in src\lib\data.jsreturnNextResponse.json("deleted");//NextResponse: This represents the response object that will be sent back to the client.}catch(err){console.log(err);thrownewError(err);}};
Auth
// Using Next-Auth from Auth.js//In this case we are using Github as a Auth methodimportNextAuthfrom"next-auth";// Import the NextAuth libraryimportGitHubfrom"next-auth/providers/github";// Import the GitHub provider// Initialize NextAuth with the desired authentication providersexportconst{handlers: {GET,POST},
auth,
signIn,
signOut,}=NextAuth({providers: [GitHub({clientId: process.env.GITHUB_ID,// GitHub OAuth client IDclientSecret: process.env.GITHUB_SECRET,// GitHub OAuth client secret}),],});
Console.log'ing our Auth session and logging in via github
// src\app\api\auth\[...nextauth]//this file name allows us to to map over all the auth function, within nextauth, so you don't have to make sigin-In, siginout, login session and such and such.//using Auth.js you don't have to worry about cookies and session and what not, firebase auth is teh same too i believe//-------------------------------------//src\app\api\auth\[...nextauth]\route.jsconst{GET,POST}=require("@/lib/auth");// from "handlers: {GET, POST}" aboveexport{GET,POST};//-------------------------------------// src\app\(auth)\login\page.jsximport{auth,signIn}from"@/lib/auth";importReactfrom"react";constLoginPage=async()=>{constsession=awaitauth();console.log(session);consthandleLogin=async(e)=>{"use server";const{ text }=Object.fromEntries(e);awaitsignIn("github");console.log(text);};return(<div><formaction={handleLogin}><inputtype="text"placeholder="text"name="text"/><button>cLick</button></form></div>);};exportdefaultLoginPage;
handleGithubLogin to action.js and signIn("github"); via Auth.js
exportconsthandleGithubLogin=async()=>{// its best practice to put all your serve actions/function's/component's in one fileawaitsignIn("github");};
handleLogout via signOut("github") via Auth.js
exportconsthandleLogout=async()=>{awaitsignOut("github");// pretty rudimentary, naming convention, although i would of perrfed logot, not signoutconsole.log(session);};
When a button is clicked inside a form, it auto refresh's, its a default behavior
constLoginPage=async()=>{constsession=awaitauth();console.log(session);return(<div><formaction={handleGithubLogin}>{/* When a button is clicked inside a form, it automatically refreshes the page because handleGithubLogin does not have an e.preventDefault(), so the page will refresh, meaning it reruns the page again, that's why it's logging session. */}{/* //acts like an onClick for now, until we expand the login form */}<button>cLick</button></form></div>);};exportdefaultLoginPage;
Server and Client, async and useState conflict
//constLinks=async()=>{//Async cant be assigned because its a server function, and below you are using useState, wish is a client functionconst[open,setOpen]=useState(false);constsession=awaitauth();// if you are using await, your top function must be async
Passed Session as a prop to negate conflict above
// Passed Session as a prop to negative conflict aboveconstsession=awaitauth();// you could create a function that does this in the lib//folder to reduce repetition and make it more organized// src\components\navbar\Navbar.jsxconstNavbar=async()=>{constsession=awaitauth();return(<Linkssession={session}/>// I can do this because Navbar.jsx does not have any client functions; it is static and not dynamic. It does not take any user input. However, the components inside do. It makes sense that certain components inside Navbar.jsx are client-based, while the overall Navbar.jsx that holds the client is server-based. It feels optimized, and Next.js only renders what it needs.)//---------------------------------------------// src\components\navbar\links\Links.jsxconstLinks=({ session })=>{const[open,setOpen]=useState(false);
?. operator, great for true checking: session.user?.isAdmin
//Using session.user.isAdmin without the optional chaining operator ?. assumes that session.user always exists and has an isAdmin property. If session.user were to be null or undefined, accessing the isAdmin property directly would result in a runtime error, typically causing your application to crash.{session?.user ? (// if session is true, and it contain's user and if that statement is true again then => , if session.user is also true, and it contains isAdmin and thats also true (&&) then render <><>{session.user?.isAdmin&&<NavLinkitem={{title: "Admin",path: "/admin"}}/>}{" "}
junior vs senior diffenace in code quilty (i think)
Weird CSS Code, Either, high lvl css or bad code idk
constNavLink=({ item })=>{constpathName=usePathname();return(// Click on the overlay links; they will all become rounded.// If the pathname === item path, and if that's true,// then change the class to active, which just changes// the color of the background and font. It was always rounded// and had a block around it, just not no bg color; that's why it didn't show.<LinkclassName={`${styles.container}${// just read the func its simplepathName===item.path&&styles.active// is pathname "url/ur" is equal to item.title then active class will}`}href={item.path}>{" "}{item.title}</Link>);};
My session Checker session?.user ? :
{session?.user
? console.log(session.user?.name)
: console.log("no user, value: "+session);}//if session ture, and it conatains user, and if that statement is true then console log session.user.name else console log no user
Creating new User via the Github Auth, via Auth.js and NextAuth "next-auth"
// src\lib\auth.js
callbacks: {asyncsignIn({ user, account, profile }){console.log(user,account,profile);if(account.provider==="github"){connectToDb();try{constuser=awaitUser.findOne({email: profile.email});// retieving the user email from dbif(!user){// if user email is not found/falseconstnewUser=newUser({//create new username: profile.name,username: profile.login,email: profile.email,img: profile.avatar_url,});awaitnewUser.save();// saving the new user to db}}catch(err){console.log(err);returnfalse;// end the auth function with a false// if there is an error (no lingering sessions)}}returntrue;},},// Github Singin profile console.logconsole.log(profile);// i removed some sensitive information
login: 'AdminForIinRange',id: 91888685,node_id: 'U_kgDOBXocLQ',avatar_url: 'https://avatars.githubusercontent.com/u/91888685?v=4'type: 'User',site_admin: false,name: 'Anjesh',location: ' ',email: '',}
Cheak if user's Login matches the DB
constlogin=async(credentials)=>{// Login: This function checks if the user's login email and password match the database.//You're not creating a new user, you are simply checking if they exist in the user collection.try{connectToDb();// Connecting to the databaseconstuser=awaitUser.findOne({username: credentials.username});// Finding user by username// If user not found, throw an errorif(!user){thrownewError("Wrong credentials!");}// Comparing passwordsconstisPasswordCorrect=awaitbcryptjs.compare(credentials.password,user.password);// If password is incorrect, throw an errorif(!isPasswordCorrect){thrownewError("Wrong credentials!");}// If everything is correct, return the userreturnuser;}catch(err){console.log(err);// Log any errorsthrownewError("Failed to login!");// Throw error for failed login attempt}};CredentialsProvider({// This is an async function defined within CredentialsProvider. It takes credentials as an argument,// representing the credentials entered by the user during the authentication process.asyncauthorize(credentials){try{// Attempt to log in the user using the provided credentialsconstuser=awaitlogin(credentials);// If login is successful, return the user objectreturnuser;}catch(err){// If login fails due to incorrect credentials or any other error, return nullreturnnull;}},}),
Copy of old action.js code
"use server";// don't forget this is Server Side Renderedimport{revalidatePath}from"next/cache";import{Post}from"./models";import{connectToDb}from"./utils";import{auth,signIn,signOut}from"./auth";importbcryptjsfrom"bcryptjs";exportconstaddPost=async(formData)=>{// formData is an object containing data from the formconst{ title, desc, slug, userId }=Object.fromEntries(formData);try{connectToDb();constnewPost=newPost({ title, desc, slug, userId });awaitnewPost.save();console.log("new post added");revalidatePath(`/blog`);// The revalidate option in Next.js refreshes the content//of the page on the server-side, not in the browser.}catch(err){console.log(err);}console.log(title,desc,slug,userId);};exportconstdeletePost=async(formData)=>{const{ id }=Object.fromEntries(formData);try{connectToDb();awaitPost.findByIdAndDelete(id);//removing post via Id from form dataconsole.log(" post deleted");revalidatePath(`/blog`);}catch(err){console.log(err);}console.log(id);};exportconsthandleGithubLogin=async()=>{// its best practice to put all your serve actions/function's/component's in one fileawaitsignIn("github");};exportconsthandleLogout=async()=>{awaitsignOut("github");// pretty rudimentary, naming convention, although i would of perrfed logot, not signout};exportconstregister=async(formData)=>{const{ username, email, password, passwordRepeat }=Object.fromEntries(formData);if(password!==passwordRepeat){return{error: "Passwords do not match"};}try{connectToDb();constuser=awaitauth.getUserByEmail({ username });if(user){return{error: "Username already taken"};// if user email is not found/false, teh return data sets sent to teh useFormState,// and becomes the new state}constsalt=awaitbcryptjs.genSalt(10);consthashedPassword=awaitbcryptjs.hash(password,salt);// this hasing, bcryptjs thing is pretty cool, maybe i can use it in other project, not just about AuthconstnewUser=newUser({ username, email,password: hashedPassword});// making password hashed via "bcryptjs"awaitnewUser.save();console.log("new user created");}catch(err){console.log(err);return{error: err.message};}};exportconstlogin=async(formData)=>{const{ username, password }=Object.fromEntries(formData);try{awaitsignIn("credentials",{ username, password });console.log("new user created");}catch(err){console.log(err);return{error: err.message};}};
// Importing necessary modules and packagesimportNextAuthfrom"next-auth";importGitHubfrom"next-auth/providers/github";importCredentialsProviderfrom"next-auth/providers/credentials";import{connectToDb}from"./utils";import{User}from"./models";importbcryptjsfrom"bcryptjs";// Function to handle login processconstlogin=async(credentials)=>{// Login: This function checks if the user's login email and password match the database.//You're not creating a new user, you are simply checking if they exist in the user collection.try{connectToDb();// Connecting to the databaseconstuser=awaitUser.findOne({username: credentials.username});// Finding user by username// If user not found, throw an errorif(!user){thrownewError("Wrong credentials!");}// Comparing passwordsconstisPasswordCorrect=awaitbcryptjs.compare(credentials.password,user.password,);// If password is incorrect, throw an errorif(!isPasswordCorrect){thrownewError("Wrong credentials!");}// If everything is correct, return the userreturnuser;}catch(err){console.log(err);// Log any errorsthrownewError("Failed to login!");// Throw error for failed login attempt}};// Exporting handlers and authentication functionsexportconst{handlers: {GET,POST},// Handlers for GET and POST requests
auth,// Authentication function
signIn,// Function to sign in
signOut,// Function to sign out}=NextAuth({providers: [GitHub({clientId: process.env.GITHUB_ID,// GitHub client IDclientSecret: process.env.GITHUB_SECRET,// GitHub client secret}),CredentialsProvider({// This is an async function defined within CredentialsProvider. It takes credentials as an argument,// representing the credentials entered by the user during the authentication process.asyncauthorize(credentials){try{// Attempt to log in the user using the provided credentialsconstuser=awaitlogin(credentials);// If login is successful, return the user objectreturnuser;}catch(err){// If login fails due to incorrect credentials or any other error, return nullreturnnull;}},}),],callbacks: {asyncsignIn({ user, account, profile }){console.log(user,account,profile);// Log user, account, and profile informationif(account.provider==="github"){// If the authentication provider is GitHubconnectToDb();// Connect to the databasetry{constuser=awaitUser.findOne({email: profile.email});// Find user by email// If user not found, create a new userif(!user){constnewUser=newUser({username: profile.login,// Set usernameemail: profile.email,// Set emailimg: profile.avatar_url,// Set profile image});awaitnewUser.save();// Save new user to the database}}catch(err){console.log(err);// Log any errorsreturnfalse;// Return false if there is an error}}returntrue;// Return true if authentication is successful},authorized({auth, request}){}},});