Skip to content

Instantly share code, notes, and snippets.

@adrianhajdin
Created May 5, 2023 13:13
Show Gist options
  • Save adrianhajdin/6df61c6cd5ed052dce814a765bff9032 to your computer and use it in GitHub Desktop.
Save adrianhajdin/6df61c6cd5ed052dce814a765bff9032 to your computer and use it in GitHub Desktop.
Next.js 13 Full Course 2023 | Build and Deploy a Full Stack App Using the Official React Framework
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap");
@tailwind base;
@tailwind components;
@tailwind utilities;
/*
Note: The styles for this gradient grid background is heavily inspired by the creator of this amazing site (https://dub.sh) – all credits go to them!
*/
.main {
width: 100vw;
min-height: 100vh;
position: fixed;
display: flex;
justify-content: center;
padding: 120px 24px 160px 24px;
pointer-events: none;
}
.main:before {
background: radial-gradient(circle, rgba(2, 0, 36, 0) 0, #fafafa 100%);
position: absolute;
content: "";
z-index: 2;
width: 100%;
height: 100%;
top: 0;
}
.main:after {
content: "";
background-image: url("/assets/images/grid.svg");
z-index: 1;
position: absolute;
width: 100%;
height: 100%;
top: 0;
opacity: 0.4;
filter: invert(1);
}
.gradient {
height: fit-content;
z-index: 3;
width: 100%;
max-width: 640px;
background-image: radial-gradient(
at 27% 37%,
hsla(215, 98%, 61%, 1) 0px,
transparent 0%
),
radial-gradient(at 97% 21%, hsla(125, 98%, 72%, 1) 0px, transparent 50%),
radial-gradient(at 52% 99%, hsla(354, 98%, 61%, 1) 0px, transparent 50%),
radial-gradient(at 10% 29%, hsla(256, 96%, 67%, 1) 0px, transparent 50%),
radial-gradient(at 97% 96%, hsla(38, 60%, 74%, 1) 0px, transparent 50%),
radial-gradient(at 33% 50%, hsla(222, 67%, 73%, 1) 0px, transparent 50%),
radial-gradient(at 79% 53%, hsla(343, 68%, 79%, 1) 0px, transparent 50%);
position: absolute;
content: "";
width: 100%;
height: 100%;
filter: blur(100px) saturate(150%);
top: 80px;
opacity: 0.15;
}
@media screen and (max-width: 640px) {
.main {
padding: 0;
}
}
/* Tailwind Styles */
.app {
@apply relative z-10 flex justify-center items-center flex-col max-w-7xl mx-auto sm:px-16 px-6;
}
.black_btn {
@apply rounded-full border border-black bg-black py-1.5 px-5 text-white transition-all hover:bg-white hover:text-black text-center text-sm font-inter flex items-center justify-center;
}
.outline_btn {
@apply rounded-full border border-black bg-transparent py-1.5 px-5 text-black transition-all hover:bg-black hover:text-white text-center text-sm font-inter flex items-center justify-center;
}
.head_text {
@apply mt-5 text-5xl font-extrabold leading-[1.15] text-black sm:text-6xl;
}
.orange_gradient {
@apply bg-gradient-to-r from-amber-500 via-orange-600 to-yellow-500 bg-clip-text text-transparent;
}
.green_gradient {
@apply bg-gradient-to-r from-green-400 to-green-500 bg-clip-text text-transparent;
}
.blue_gradient {
@apply bg-gradient-to-r from-blue-600 to-cyan-600 bg-clip-text text-transparent;
}
.desc {
@apply mt-5 text-lg text-gray-600 sm:text-xl max-w-2xl;
}
.search_input {
@apply block w-full rounded-md border border-gray-200 bg-white py-2.5 font-satoshi pl-5 pr-12 text-sm shadow-lg font-medium focus:border-black focus:outline-none focus:ring-0;
}
.copy_btn {
@apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199,199,199,0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
}
.glassmorphism {
@apply rounded-xl border border-gray-200 bg-white/20 shadow-[inset_10px_-50px_94px_0_rgb(199,199,199,0.2)] backdrop-blur p-5;
}
.prompt_layout {
@apply space-y-6 py-8 sm:columns-2 sm:gap-6 xl:columns-3;
}
/* Feed Component */
.feed {
@apply mt-16 mx-auto w-full max-w-xl flex justify-center items-center flex-col gap-2;
}
/* Form Component */
.form_textarea {
@apply w-full flex rounded-lg h-[200px] mt-2 p-3 text-sm text-gray-500 outline-0;
}
.form_input {
@apply w-full flex rounded-lg mt-2 p-3 text-sm text-gray-500 outline-0;
}
/* Nav Component */
.logo_text {
@apply max-sm:hidden font-satoshi font-semibold text-lg text-black tracking-wide;
}
.dropdown {
@apply absolute right-0 top-full mt-3 w-full p-5 rounded-lg bg-white min-w-[210px] flex flex-col gap-2 justify-end items-end;
}
.dropdown_link {
@apply text-sm font-inter text-gray-700 hover:text-gray-500 font-medium;
}
/* PromptCard Component */
.prompt_card {
@apply flex-1 break-inside-avoid rounded-lg border border-gray-300 bg-white/20 bg-clip-padding p-6 pb-4 backdrop-blur-lg backdrop-filter md:w-[360px] w-full h-fit;
}
.flex-center {
@apply flex justify-center items-center;
}
.flex-start {
@apply flex justify-start items-start;
}
.flex-end {
@apply flex justify-end items-center;
}
.flex-between {
@apply flex justify-between items-center;
}
{
"compilerOptions": {
"paths": {
"@*": ["./*"]
}
}
}
import Prompt from "@models/prompt";
import { connectToDB } from "@utils/database";
export const GET = async (request, { params }) => {
try {
await connectToDB()
const prompt = await Prompt.findById(params.id).populate("creator")
if (!prompt) return new Response("Prompt Not Found", { status: 404 });
return new Response(JSON.stringify(prompt), { status: 200 })
} catch (error) {
return new Response("Internal Server Error", { status: 500 });
}
}
export const PATCH = async (request, { params }) => {
const { prompt, tag } = await request.json();
try {
await connectToDB();
// Find the existing prompt by ID
const existingPrompt = await Prompt.findById(params.id);
if (!existingPrompt) {
return new Response("Prompt not found", { status: 404 });
}
// Update the prompt with new data
existingPrompt.prompt = prompt;
existingPrompt.tag = tag;
await existingPrompt.save();
return new Response("Successfully updated the Prompts", { status: 200 });
} catch (error) {
return new Response("Error Updating Prompt", { status: 500 });
}
};
export const DELETE = async (request, { params }) => {
try {
await connectToDB();
// Find the prompt by ID and remove it
await Prompt.findByIdAndRemove(params.id);
return new Response("Prompt deleted successfully", { status: 200 });
} catch (error) {
return new Response("Error deleting prompt", { status: 500 });
}
};
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
fontFamily: {
satoshi: ['Satoshi', 'sans-serif'],
inter: ['Inter', 'sans-serif'],
},
colors: {
'primary-orange': '#FF5722',
}
},
},
plugins: [],
}
username: {
type: String,
required: [true, 'Username is required!'],
match: [/^(?=.{8,20}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(?<![_.])$/, "Username invalid, it should contain 8-20 alphanumeric letters and be unique!"]
},
@prajapatibhaskar
Copy link

prajapatibhaskar commented Jun 11, 2024

The database share_prompts is not getting created.
My URI and PASSWORD are also exactly correct.

database.js

let isConnected = false; // track connection status
const connectToDB = async () => {
    mongoose.set('strictQuery', true);

    if(isConnected) {
        console.log('MongoDB is already connected.');
        return;
    }
    try {
        await mongoose.connect(process.env.MONGODB_URI, {
            dbName: 'share_prompt',
            useNewUrlParser: true,
            useUnifiedTopology: true,
        })

        isConnected = true;
        console.log('MongoDB connected.');
    } catch (error) {
        console.log(error);
    }
}

export default connectToDB;

route.js:

import NextAuth from "next-auth/next";
import GoogleProvider from "next-auth/providers/google";

import connectToDB from "@utils/database";
import User from "@models/user";

console.log({
  clientId: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
});

const handler = NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],

  callback: {
    async session({ session }) {
      const sessionUser = await User.findOne({
        email: session.user.email,
      });

      session.user.id = sessionUser._id.toString();

      return session;
    },

    async signIn({ profile }) {
      try {
        await connectToDB();

        // check if user already exists
        const userExists = await User.findOne({
          email: profile.email,
        });

        // if not, create a new user and save it to database
        if (!userExists) {
          await User.create({
            email: profile.email,
            username: profile.name.replace(" ", "").toLowerCase(),
            image: profile.picture,
          });
        }
        return true;

      } catch (err) {
        console.log(error);
        return false;
      }
    },
  },
});

export { handler as GET, handler as POST };

@prajapatibhaskar
Copy link

The database share_prompts is not getting created. My URI and PASSWORD are also exactly correct.

database.js

let isConnected = false; // track connection status
const connectToDB = async () => {
    mongoose.set('strictQuery', true);

    if(isConnected) {
        console.log('MongoDB is already connected.');
        return;
    }
    try {
        await mongoose.connect(process.env.MONGODB_URI, {
            dbName: 'share_prompt',
            useNewUrlParser: true,
            useUnifiedTopology: true,
        })

        isConnected = true;
        console.log('MongoDB connected.');
    } catch (error) {
        console.log(error);
    }
}

export default connectToDB;

route.js:

import NextAuth from "next-auth/next";
import GoogleProvider from "next-auth/providers/google";

import connectToDB from "@utils/database";
import User from "@models/user";

console.log({
  clientId: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
});

const handler = NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],

  callback: {
    async session({ session }) {
      const sessionUser = await User.findOne({
        email: session.user.email,
      });

      session.user.id = sessionUser._id.toString();

      return session;
    },

    async signIn({ profile }) {
      try {
        await connectToDB();

        // check if user already exists
        const userExists = await User.findOne({
          email: profile.email,
        });

        // if not, create a new user and save it to database
        if (!userExists) {
          await User.create({
            email: profile.email,
            username: profile.name.replace(" ", "").toLowerCase(),
            image: profile.picture,
          });
        }
        return true;

      } catch (err) {
        console.log(error);
        return false;
      }
    },
  },
});

export { handler as GET, handler as POST };

OK, it seems that changing from callback to callbacks worked for me.
In the video he said callbacks, but sometime ago it was not working for me, then i changed to callback, then it worked but, was not able to create database in MongoDB.

@i-oo
Copy link

i-oo commented Jun 14, 2024

I followed the youTube video until the end of the 'Homepage' section. After signing in with google, I got the error below

image

The culprit was with 'next/image' and src={session?.user.image} in the tag.

To resolve this I created a new next.config.js with

/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: "lh3.googleusercontent.com",
},
],
},
};

module.exports = nextConfig;

ref: https://nextjs.org/docs/pages/api-reference/components/image#remotepatterns

Resolved issue

@AbhayWakle
Copy link

Screenshot 2024-06-21 130936

how to solve this error

@brotherSI
Copy link

Hi all,

I get the following error when I try to deploy on Vercel. I have wrapped the useSearchParams() function with suspense boundary but it hasn't worked. Please Help

useSearchParams() should be wrapped in a suspense boundary at page "/update-prompt". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout

@Abdul073
Copy link

Guys i'm stuck with this error.anybody have a solution to this ⨯ Error: [next-auth]: useSession must be wrapped in a at Nav (./components/Nav.jsx:19:90) session

So if you watch the video, you need to add the following code inside Provider.jsx file inside your component folder.

"use client";
import React from "react";
import { SessionProvider } from "next-auth/react";

const Provider = ({ children, session }) => {
  return <SessionProvider session={session}>{children}</SessionProvider>;
};

export default Provider;

and after that inside layout.jsx file inside your create-prompt folder you need to wrap everything inside the body tag with the Provider component as follows.

import React from "react";
import "@styles/globals.css";
import Nav from "@components/Nav";
import Provider from "@components/Provider";

export const metadata = {
  title: "Promptopia",
  description: "Discover & Share prompts",
};

const RootLayout = ({ children }) => {
  return (
    <html lang="en">
      <body>
        <Provider>
          <div className="main">
            <div className="gradient" />
          </div>
          <main className="app">
            <Nav />
            {children}
          </main>
        </Provider>
      </body>
    </html>
  );
};

export default RootLayout;

Hope this solves your issue.

i got some issues in page loading its 404 page not found can you solve this

@Sidharth1327
Copy link

✓ Starting...
✓ Ready in 3.1s
○ Compiling / ...
⨯ ./styles/globals.css
Syntax error: D:\Full STack Developer\full-stack-next-js-app\styles\globals.css The shadow-[inset_10px_-50px_94px_0_rgb(199, class does not exist. If shadow-[inset_10px_-50px_94px_0_rgb(199, is a custom class, make sure it is defined within a @layer directive. (111:3)

109 |
110 | .copy_btn {

111 | @apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199, 199, 199, 0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
| ^
112 | }
113 |
-- inner error --
Syntax error: D:\Full STack Developer\full-stack-next-js-app\styles\globals.css The shadow-[inset_10px_-50px_94px_0_rgb(199, class does not exist. If shadow-[inset_10px_-50px_94px_0_rgb(199, is a custom class, make sure it is defined within a @layer directive. (111:3)

109 |
110 | .copy_btn {

111 | @apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199, 199, 199, 0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
| ^
112 | }
113 |
Generated code for D:\Full STack Developer\full-stack-next-js-app\node_modules\next\dist\build\webpack\loaders\css-loader\src\index.js??ruleSet[1].rules[13].oneOf[12].use[2]!D:\Full STack Developer\full-stack-next-js-app\node_modules\next\dist\build\webpack\loaders\postcss-loader\src\index.js??ruleSet[1].rules[13].oneOf[12].use[3]!D:\Full STack Developer\full-stack-next-js-app\styles\globals.css

Import trace for requested module:
./styles/globals.css
GET / 500 in 1702ms
⨯ ./styles/globals.css
Syntax error: D:\Full STack Developer\full-stack-next-js-app\styles\globals.css The shadow-[inset_10px_-50px_94px_0_rgb(199, class does not exist. If shadow-[inset_10px_-50px_94px_0_rgb(199, is a custom class, make sure it is defined within a @layer directive. (111:3)

109 |
110 | .copy_btn {

111 | @apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199, 199, 199, 0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
| ^
112 | }
113 |
-- inner error --
Syntax error: D:\Full STack Developer\full-stack-next-js-app\styles\globals.css The shadow-[inset_10px_-50px_94px_0_rgb(199, class does not exist. If shadow-[inset_10px_-50px_94px_0_rgb(199, is a custom class, make sure it is defined within a @layer directive. (111:3)

109 |
110 | .copy_btn {

111 | @apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199, 199, 199, 0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
| ^
112 | }
113 |
Generated code for D:\Full STack Developer\full-stack-next-js-app\node_modules\next\dist\build\webpack\loaders\css-loader\src\index.js??ruleSet[1].rules[13].oneOf[12].use[2]!D:\Full STack Developer\full-stack-next-js-app\node_modules\next\dist\build\webpack\loaders\postcss-loader\src\index.js??ruleSet[1].rules[13].oneOf[12].use[3]!D:\Full STack Developer\full-stack-next-js-app\styles\globals.css

Import trace for requested module:
./styles/globals.css
GET /_next/static/webpack/2c117a266159ffbc.webpack.hot-update.json 500 in 2265ms
⚠ Fast Refresh had to perform a full reload due to a runtime error.
GET / 200 in 537ms
GET / 500 in 13ms

Guys, anybody have any idea , whats wrong ?? Please help me

@Sidharth1327
Copy link

✓ Starting... ✓ Ready in 3.1s ○ Compiling / ... ⨯ ./styles/globals.css Syntax error: D:\Full STack Developer\full-stack-next-js-app\styles\globals.css The shadow-[inset_10px_-50px_94px_0_rgb(199, class does not exist. If shadow-[inset_10px_-50px_94px_0_rgb(199, is a custom class, make sure it is defined within a @layer directive. (111:3)

109 | 110 | .copy_btn {

111 | @apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199, 199, 199, 0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
| ^
112 | }
113 |
-- inner error --
Syntax error: D:\Full STack Developer\full-stack-next-js-app\styles\globals.css The shadow-[inset_10px_-50px_94px_0_rgb(199, class does not exist. If shadow-[inset_10px_-50px_94px_0_rgb(199, is a custom class, make sure it is defined within a @layer directive. (111:3)

109 | 110 | .copy_btn {

111 | @apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199, 199, 199, 0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
| ^
112 | }
113 |
Generated code for D:\Full STack Developer\full-stack-next-js-app\node_modules\next\dist\build\webpack\loaders\css-loader\src\index.js??ruleSet[1].rules[13].oneOf[12].use[2]!D:\Full STack Developer\full-stack-next-js-app\node_modules\next\dist\build\webpack\loaders\postcss-loader\src\index.js??ruleSet[1].rules[13].oneOf[12].use[3]!D:\Full STack Developer\full-stack-next-js-app\styles\globals.css

Import trace for requested module: ./styles/globals.css GET / 500 in 1702ms ⨯ ./styles/globals.css Syntax error: D:\Full STack Developer\full-stack-next-js-app\styles\globals.css The shadow-[inset_10px_-50px_94px_0_rgb(199, class does not exist. If shadow-[inset_10px_-50px_94px_0_rgb(199, is a custom class, make sure it is defined within a @layer directive. (111:3)

109 | 110 | .copy_btn {

111 | @apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199, 199, 199, 0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
| ^
112 | }
113 |
-- inner error --
Syntax error: D:\Full STack Developer\full-stack-next-js-app\styles\globals.css The shadow-[inset_10px_-50px_94px_0_rgb(199, class does not exist. If shadow-[inset_10px_-50px_94px_0_rgb(199, is a custom class, make sure it is defined within a @layer directive. (111:3)

109 | 110 | .copy_btn {

111 | @apply w-7 h-7 rounded-full bg-white/10 shadow-[inset_10px_-50px_94px_0_rgb(199, 199, 199, 0.2)] backdrop-blur flex justify-center items-center cursor-pointer;
| ^
112 | }
113 |
Generated code for D:\Full STack Developer\full-stack-next-js-app\node_modules\next\dist\build\webpack\loaders\css-loader\src\index.js??ruleSet[1].rules[13].oneOf[12].use[2]!D:\Full STack Developer\full-stack-next-js-app\node_modules\next\dist\build\webpack\loaders\postcss-loader\src\index.js??ruleSet[1].rules[13].oneOf[12].use[3]!D:\Full STack Developer\full-stack-next-js-app\styles\globals.css

Import trace for requested module: ./styles/globals.css GET /_next/static/webpack/2c117a266159ffbc.webpack.hot-update.json 500 in 2265ms ⚠ Fast Refresh had to perform a full reload due to a runtime error. GET / 200 in 537ms GET / 500 in 13ms

Guys, anybody have any idea , whats wrong ?? Please help me

I even tried to comment out this code and again executed npm run dev , still it shows the error

@cahyo988
Copy link

findByIdAndDelete
thank you its resolve my problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment