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
12 changes: 7 additions & 5 deletions .env
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Public Environment Variables
NEXT_PUBLIC_CURRENCY=$
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=''
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_ZGVhci1mb3dsLTUuY2xlcmsuYWNjb3VudHMuZGV2JA



# Private Environment Variables
CLERK_SECRET_KEY=''
MONGODB_URI=''
INNGEST_SIGNING_KEY=''
INNGEST_EVENT_KEY=''
CLERK_SECRET_KEY=sk_test_kdGJ2mgDXRIhfY11Xiexane62lPdFc8iWVyoVSiaJq
MONGODB_URI='mongodb+srv://greatstack:greatstack123@cluster0.xp4gxmj.mongodb.net'
INNGEST_SIGNING_KEY='signkey-prod-9a5737d753543e837cc3d857fa49f92617071c949bb723e3438b668ede8d01c0'
INNGEST_EVENT_KEY='aJhajuO9jJdvUQLH7kqA7hDnMCukmBG4exJe1Bkxe6Q6JBl_YkTe4c5QjAJQYC6GLcpueCV1NkwQEQDm4MHKoA'
# Cloudinary
CLOUDINARY_CLOUD_NAME =''
CLOUDINARY_API_KEY =''
Expand Down
12 changes: 12 additions & 0 deletions app/api/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { serve } from "inngest/next";
import { inngest, syncUserCreation, syncUserDeletion, syncUserUpdation } from "@/config/inngest";

// Create an API that serves zero functions
export const { GET, POST, PUT } = serve({
client: inngest,
functions: [
syncUserCreation,
syncUserUpdation,
syncUserDeletion
],
});
3 changes: 3 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,7 @@ 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 +22,6 @@ export default function RootLayout({ children }) {
</AppContextProvider>
</body>
</html>
</ClerkProvider>
);
}
40 changes: 30 additions & 10 deletions components/Navbar.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"use client"
import React from "react";
import { assets} from "@/assets/assets";
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";

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">
Expand Down Expand Up @@ -37,18 +39,36 @@ const Navbar = () => {

<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>

</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>
{
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>
);
Expand Down
25 changes: 25 additions & 0 deletions config/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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 Function to save user data to a distance
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,
image_url: image_url
}
await connectDB()
await User.create(userData)

}
)

//Inngest Function to update user data in database
export const syncUserUpdation = inngest.createFunction(
{
id: 'update-user-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,
image_url: image_url
}
await connectDB()
await User.findByIdAndUpdate(id,userData)
}
)


//Inngest Function to delete user 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)
}

)
4 changes: 4 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 @@ -14,6 +15,8 @@ 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)
const [isSeller, setIsSeller] = useState(true)
Expand Down Expand Up @@ -82,6 +85,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)(.*)',
],
};
13 changes: 13 additions & 0 deletions models/User.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import mongoose from "mongoose";

const userSchema = 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',userSchema)

export default User
Loading