Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .env
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Public Environment Variables
NEXT_PUBLIC_CURRENCY=$
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=''
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_dHJ1c3RlZC1vc3ByZXktMjMuY2xlcmsuYWNjb3VudHMuZGV2JA
CLERK_SECRET_KEY=sk_test_m6MXkTutrcCpoGxAVYs742QSZU7vMnCEreLrmNkbvE

# Private Environment Variables
CLERK_SECRET_KEY=''
MONGODB_URI=''
INNGEST_SIGNING_KEY=''
INNGEST_EVENT_KEY=''
CLERK_SECRET_KEY=sk_test_m6MXkTutrcCpoGxAVYs742QSZU7vMnCEreLrmNkbvE
MONGODB_URI='mongodb+srv://swatimatre:swati123@cluster0.u1szadl.mongodb.net'
INNGEST_SIGNING_KEY='signkey-prod-28f28f2c875ffa7c174b81a672c0557ba272d577d621acc8dfde67e526a01c3a'
INNGEST_EVENT_KEY='XFjzTr0ydwQVaD9o5fqzzPTLwHp0bCQMaAz0hsbIJiJfQ4Hu7w4GZVY_ncFk01yoscIVMHwOjJnqe1hH0YbpgA'
# Cloudinary
CLOUDINARY_CLOUD_NAME =''
CLOUDINARY_API_KEY =''
Expand Down
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
legacy-peer-deps=true
14 changes: 14 additions & 0 deletions app/api/inngest/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { serve } from "inngest/next";
import { inngest, syncUserCreation, syncUserDeletion, syncUserUpdation } from "@/config/inngest";


export const { GET, POST, PUT } = serve({
client: inngest,
functions: [
syncUserCreation,
syncUserDeletion,
syncUserUpdation


],
});
4 changes: 4 additions & 0 deletions app/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Outfit } from "next/font/google";
import "./globals.css";
import { AppContextProvider } from "@/context/AppContext";
import { Toaster } from "react-hot-toast";
import { ClerkProvider } from "@clerk/nextjs";

const outfit = Outfit({ subsets: ['latin'], weight: ["300", "400", "500"] })

Expand All @@ -12,6 +13,8 @@ export const metadata = {

export default function RootLayout({ children }) {
return (
<ClerkProvider>

<html lang="en">
<body className={`${outfit.className} antialiased text-gray-700`} >
<Toaster />
Expand All @@ -20,5 +23,6 @@ export default function RootLayout({ children }) {
</AppContextProvider>
</body>
</html>
</ClerkProvider>
);
}
102 changes: 84 additions & 18 deletions components/Navbar.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
"use client"
"use client";
import React from "react";
import { assets} from "@/assets/assets";
import Link from "next/link"
import { assets, BagIcon, BoxIcon, CartIcon, HomeIcon } from "@/assets/assets";
import Link from "next/link";
import { useAppContext } from "@/context/AppContext";
import Image from "next/image";
import { useClerk, UserButton } from "@clerk/nextjs";
import Cart from "@/app/cart/page";

const Navbar = () => {

const { isSeller, router } = useAppContext();
const { isSeller, router, user } = useAppContext();
const { openSignIn } = useClerk();

return (
<nav className="flex items-center justify-between px-6 md:px-16 lg:px-32 py-3 border-b border-gray-300 text-gray-700">
<Image
className="cursor-pointer w-28 md:w-32"
onClick={() => router.push('/')}
onClick={() => router.push("/")}
src={assets.logo}
alt="logo"
/>
Expand All @@ -31,27 +33,91 @@ const Navbar = () => {
Contact
</Link>

{isSeller && <button onClick={() => router.push('/seller')} className="text-xs border px-4 py-1.5 rounded-full">Seller Dashboard</button>}

{isSeller && (
<button
onClick={() => router.push("/seller")}
className="text-xs border px-4 py-1.5 rounded-full"
>
Seller Dashboard
</button>
)}
</div>

<ul className="hidden md:flex items-center gap-4 ">
<Image className="w-4 h-4" src={assets.search_icon} alt="search icon" />
<button className="flex items-center gap-2 hover:text-gray-900 transition">
<Image src={assets.user_icon} alt="user icon" />
Account
</button>
{user ? (
<>
<UserButton>
<UserButton.MenuItems>
<UserButton.Action label="Home" labelIcon={<HomeIcon />} onClick={() => router.push("/")} />
</UserButton.MenuItems>
<UserButton.MenuItems>
<UserButton.Action label="Products" labelIcon={<BoxIcon />} onClick={() => router.push("/all-products")} />
</UserButton.MenuItems>
<UserButton.MenuItems>
<UserButton.Action label="Cart" labelIcon={<CartIcon />} onClick={() => router.push("/cart")} />
</UserButton.MenuItems>
<UserButton.MenuItems>
<UserButton.Action label="My Orders" labelIcon={<BagIcon />} onClick={() => router.push("/my-orders")} />
</UserButton.MenuItems>


</UserButton>

</>
) : (
<button
onClick={openSignIn}
className="flex items-center gap-2 hover:text-gray-900 transition"
>
<Image src={assets.user_icon} alt="user icon" />
Account
</button>
)}
</ul>

<div className="flex items-center md:hidden gap-3">
{isSeller && <button onClick={() => router.push('/seller')} className="text-xs border px-4 py-1.5 rounded-full">Seller Dashboard</button>}
<button className="flex items-center gap-2 hover:text-gray-900 transition">
<Image src={assets.user_icon} alt="user icon" />
Account
</button>
{isSeller && (
<button
onClick={() => router.push("/seller")}
className="text-xs border px-4 py-1.5 rounded-full"
>
Seller Dashboard
</button>
)}
{user ? (
<>
<UserButton>
<UserButton.MenuItems>
<UserButton.Action label="Home" labelIcon={<HomeIcon />} onClick={() => router.push("/")} />
</UserButton.MenuItems>
<UserButton.MenuItems>
<UserButton.Action label="Products" labelIcon={<BoxIcon />} onClick={() => router.push("/all-products")} />
</UserButton.MenuItems>

<UserButton.MenuItems>
<UserButton.Action label="Cart" labelIcon={<CartIcon />} onClick={() => router.push("/cart")} />
</UserButton.MenuItems>
<UserButton.MenuItems>
<UserButton.Action label="My Orders" labelIcon={<BagIcon />} onClick={() => router.push("/my-orders")} />
</UserButton.MenuItems>


</UserButton>

</>
) : (
<button
onClick={openSignIn}
className="flex items-center gap-2 hover:text-gray-900 transition"
>
<Image src={assets.user_icon} alt="user icon" />
Account
</button>
)}
</div>
</nav>
);
};

export default Navbar;
export default Navbar;
27 changes: 27 additions & 0 deletions config/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import mongoose from "mongoose";

let cached = global.mongoose;

if (!cached) {
cached=global.mongoose={conn:null,Promise:null}
}

async function connectDB(){

if(cached.conn){
return cached.conn
}

if(!cached.Promise){
const opts={
bufferCommands:false
}
cached.Promise=mongoose.connect(`${process.env.MONGODB_URI}/quickcart`,opts).then(mongoose=>{

return mongoose
})
}
cached.conn=await cached.Promise
return cached.conn
}
export default connectDB;
64 changes: 64 additions & 0 deletions config/inngest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Inngest } from "inngest";
import connectDB from "./db";
import User from "@/models/User";

// Create a client to send and receive events
export const inngest = new Inngest({ id: "quickcart-next" });


//inngest fuction to save user data to a database
export const syncUserCreation=inngest.createFunction(
{
id:'sync-user-from-clerk'
},
{event:'clerk/user.created'},
async({event})=>{
const {id,first_name,last_name,email_addresses,image_url}=event.data
const userData={
_id:id,
email:email_addresses[0].email_address,
name:first_name+' '+last_name,
imageUrl:image_url,

}
await connectDB()
await User.create(userData)
}
)

//inngest function to update user data in database
export const syncUserUpdation=inngest.createFunction(
{
id:'sync-user-update-from-clerk'
},
{event:'clerk/user.updated'},
async({event})=>{
const {id,first_name,last_name,email_addresses,image_url}=event.data
const userData={
_id:id,
email:email_addresses[0].email_address,
name:first_name+' '+last_name,
imageUrl:image_url,

}
await connectDB()
await User.findByIdAndUpdate(id,userData)

}
)

//inngest function to delete user data from database

export const syncUserDeletion=inngest.createFunction(
{
id:'delete-user-with-clerk'
},
{event:'clerk/user.deleted'},
async({event})=>{

const {id}=event.data

await connectDB()
await User.findByIdAndDelete(id)
}
)
3 changes: 3 additions & 0 deletions context/AppContext.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client'
import { productsDummyData, userDummyData } from "@/assets/assets";
import { useUser } from "@clerk/nextjs";
import { useRouter } from "next/navigation";
import { createContext, useContext, useEffect, useState } from "react";

Expand All @@ -13,6 +14,7 @@ export const AppContextProvider = (props) => {

const currency = process.env.NEXT_PUBLIC_CURRENCY
const router = useRouter()
const {user}=useUser()

const [products, setProducts] = useState([])
const [userData, setUserData] = useState(false)
Expand Down Expand Up @@ -82,6 +84,7 @@ export const AppContextProvider = (props) => {
}, [])

const value = {
user,
currency, router,
isSeller, setIsSeller,
userData, fetchUserData,
Expand Down
12 changes: 12 additions & 0 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { clerkMiddleware } from '@clerk/nextjs/server';

export default clerkMiddleware();

export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
};
15 changes: 15 additions & 0 deletions models/User.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import mongoose from "mongoose";


const userSchemema=new mongoose.Schema({
_id:{type:String,required:true},
name:{type:String,required:true},
email:{type:String,required:true,unique:true},
imageUrl:{type:String,required:true},
cartItems:{type:Object,default:{}},

},{minimize:false})

const User= mongoose.models.user||mongoose.model('user',userSchemema)

export default User
Loading