Skip to content

b-l-i-n-d/ecommerce-admin

Repository files navigation

E-Commerce Admin

GitHub code size in bytes GitHub last commit GitHub commit activity month GitHub license

πŸ“ About β€’ ✨ Features β€’ πŸ’» Technologies β€’ πŸ“ Project structure β€’ βš™οΈ Environment variables β€’ πŸš€ How to run β€’ ☁️ API endpoints β€’ πŸ“„ License

πŸ“ About

E-Commerce Admin is a web application that allows you to manage your e-commerce store. I have created this project to learn more about next js app router. I have use nextjs as fullstack framework, tailwind css as css framework, clerk as authentication provider, planetscale as mysql database, prisma as orm, zustand as state management, shadcn/ui as ui components, react-hook-form for form validation, zod for data validation, axios for mutations, next-cloudinary for image upload, next-themes for dark mode, stripe for payment. I know that there are many things that I can improve in this project, I will try to improve it in the future. Feel free to contribute to this project. I will be very happy if you give this project a star ⭐.

✨ Features

  • Authentication using CLERK
  • Store management
    • Create store
    • Update store
  • Dashboard
    • Total revenue
    • Total sales
    • Types of products
    • Graph of sales
    • Recent sales
  • Billboards
    • Create billboard
    • Update billboard
    • Delete billboard
  • Categories
    • Create category
    • Update category
    • Delete category
  • Sizes
    • Create size
    • Update size
    • Delete size
  • Colors
    • Create color
    • Update color
    • Delete color
  • Products
    • Create product
    • Update product
    • Delete product
  • Orders
    • View orders
  • Each pages has its related API endpoints to make integration with forntend easier

πŸ’» Technologies

πŸ“ Project structure

β”œβ”€β”€ .eslintrc.json
β”œβ”€β”€ .gitignore
β”œβ”€β”€ README.md
β”œβ”€β”€ actions
β”‚   β”œβ”€β”€ get-revenue-data.ts
β”‚   β”œβ”€β”€ get-sales-data.ts
β”‚   └── get-stock-data.ts
β”œβ”€β”€ app
β”‚   β”œβ”€β”€ (auth)
β”‚   β”‚   β”œβ”€β”€ (routes)
β”‚   β”‚   β”‚   β”œβ”€β”€ sign-in
β”‚   β”‚   β”‚   β”‚   └── [[...sign-in]]
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚       β”‚   └── sign-in-with-theme.tsx
β”‚   β”‚   β”‚   β”‚       └── page.tsx
β”‚   β”‚   β”‚   └── sign-up
β”‚   β”‚   β”‚       └── [[...sign-up]]
β”‚   β”‚   β”‚           β”œβ”€β”€ components
β”‚   β”‚   β”‚           β”‚   └── sign-up-with-theme.tsx
β”‚   β”‚   β”‚           └── page.tsx
β”‚   β”‚   └── layout.tsx
β”‚   β”œβ”€β”€ (dashboard)
β”‚   β”‚   β”œβ”€β”€ [storeId]
β”‚   β”‚   β”‚   β”œβ”€β”€ (routes)
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ billboards
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [billboardId]
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── billboard-form.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ cell-action.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ client.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── columns.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ categories
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [categoryId]
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── category-form.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ cell-action.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ client.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── columns.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ colors
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [colorId]
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── color-form.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ cell-action.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ client.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── columns.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ orders
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ client.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── columns.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ page.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ products
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [productId]
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── product-form.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ cell-action.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ client.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── columns.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ settings
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── settings-form.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚   └── sizes
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ [sizeId]
β”‚   β”‚   β”‚   β”‚       β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚       β”‚   β”‚   └── size-form.tsx
β”‚   β”‚   β”‚   β”‚       β”‚   β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚       β”‚   β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚       β”‚   └── page.tsx
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”‚       β”‚   β”œβ”€β”€ cell-action.tsx
β”‚   β”‚   β”‚   β”‚       β”‚   β”œβ”€β”€ client.tsx
β”‚   β”‚   β”‚   β”‚       β”‚   └── columns.tsx
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ error.tsx
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ loading.tsx
β”‚   β”‚   β”‚   β”‚       └── page.tsx
β”‚   β”‚   β”‚   └── layout.tsx
β”‚   β”‚   └── user-profile
β”‚   β”‚       └── [[...user-profile]]
β”‚   β”‚           β”œβ”€β”€ layout.tsx
β”‚   β”‚           └── page.tsx
β”‚   β”œβ”€β”€ (root)
β”‚   β”‚   β”œβ”€β”€ (routes)
β”‚   β”‚   β”‚   └── page.tsx
β”‚   β”‚   └── layout.tsx
β”‚   β”œβ”€β”€ api
β”‚   β”‚   β”œβ”€β”€ [storeId]
β”‚   β”‚   β”‚   β”œβ”€β”€ billboards
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [billboardId]
β”‚   β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ categories
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [categoryId]
β”‚   β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ checkout
β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ colors
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [colorId]
β”‚   β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ products
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ [productId]
β”‚   β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   └── sizes
β”‚   β”‚   β”‚       β”œβ”€β”€ [sizeId]
β”‚   β”‚   β”‚       β”‚   └── route.ts
β”‚   β”‚   β”‚       └── route.ts
β”‚   β”‚   β”œβ”€β”€ stores
β”‚   β”‚   β”‚   β”œβ”€β”€ [storeId]
β”‚   β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   β”‚   └── route.ts
β”‚   β”‚   └── webhook
β”‚   β”‚       └── route.ts
β”‚   β”œβ”€β”€ favicon.ico
β”‚   β”œβ”€β”€ globals.css
β”‚   β”œβ”€β”€ layout.tsx
β”‚   └── loading.tsx
β”œβ”€β”€ components.json
β”œβ”€β”€ components
β”‚   β”œβ”€β”€ main-nav.tsx
β”‚   β”œβ”€β”€ modals
β”‚   β”‚   β”œβ”€β”€ alert-modal.tsx
β”‚   β”‚   └── store-modal.tsx
β”‚   β”œβ”€β”€ navbar-actions.tsx
β”‚   β”œβ”€β”€ navbar.tsx
β”‚   β”œβ”€β”€ overview.tsx
β”‚   β”œβ”€β”€ store-switcher.tsx
β”‚   β”œβ”€β”€ theme-toggle.tsx
β”‚   └── ui
β”‚       β”œβ”€β”€ alert.tsx
β”‚       β”œβ”€β”€ api-alert.tsx
β”‚       β”œβ”€β”€ api-list.tsx
β”‚       β”œβ”€β”€ avatar.tsx
β”‚       β”œβ”€β”€ badge.tsx
β”‚       β”œβ”€β”€ button.tsx
β”‚       β”œβ”€β”€ card.tsx
β”‚       β”œβ”€β”€ checkbox.tsx
β”‚       β”œβ”€β”€ command.tsx
β”‚       β”œβ”€β”€ data-table.tsx
β”‚       β”œβ”€β”€ dialog.tsx
β”‚       β”œβ”€β”€ dropdown-menu.tsx
β”‚       β”œβ”€β”€ form.tsx
β”‚       β”œβ”€β”€ heading.tsx
β”‚       β”œβ”€β”€ image-upload.tsx
β”‚       β”œβ”€β”€ input.tsx
β”‚       β”œβ”€β”€ label.tsx
β”‚       β”œβ”€β”€ loader.tsx
β”‚       β”œβ”€β”€ modal.tsx
β”‚       β”œβ”€β”€ popover.tsx
β”‚       β”œβ”€β”€ select.tsx
β”‚       β”œβ”€β”€ separator.tsx
β”‚       β”œβ”€β”€ table.tsx
β”‚       β”œβ”€β”€ toast.tsx
β”‚       β”œβ”€β”€ toaster.tsx
β”‚       └── use-toast.ts
β”œβ”€β”€ hooks
β”‚   β”œβ”€β”€ use-origin.tsx
β”‚   └── use-store-modal.tsx
β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ prismadb.ts
β”‚   β”œβ”€β”€ stripe.ts
β”‚   └── utils.ts
β”œβ”€β”€ middleware.ts
β”œβ”€β”€ next.config.js
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ package.json
β”œβ”€β”€ postcss.config.js
β”œβ”€β”€ prisma
β”‚   └── schema.prisma
β”œβ”€β”€ providers
β”‚   β”œβ”€β”€ modal-provider.tsx
β”‚   β”œβ”€β”€ nprogress-provider.tsx
β”‚   └── theme-provider.tsx
β”œβ”€β”€ public
β”‚   β”œβ”€β”€ next.svg
β”‚   └── vercel.svg
β”œβ”€β”€ tailwind.config.ts
└── tsconfig.json

βš™οΈ Environment variables

Create a .env.local file in the root directory and add the following variables:

# CLERK
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<CLERK_PUBLISHABLE_KEY>
CLERK_SECRET_KEY=<CLERK_SECRET_KEY>
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/

# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL=<PLANETSCALE_DATABASE_URL>

# Cloudinary
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=<CLOUDINARY_CLOUD_NAME>
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET=<CLOUDINARY_UPLOAD_PRESET>

# Stripe
STRIPE_SECRET_KEY=<STRIPE_SECRET_KEY>
STRIPE_WEBHOOK_SECRET=<STRIPE_WEBHOOK_SECRET>

# Frontend
FRONTEND_STORE_URL=<FRONTEND_STORE_URL>

πŸš€ How to run

  1. Clone this repository
git clone https://github.com/b-l-i-n-d/ecommerce-admin.git
  1. Install dependencies
npm install
  1. Generate prisma client
dotenv -e .env.local -- npx prisma generate

# make sure to install dotenv-cli globally first
# npm install -g dotenv-cli
# or to be hassle free, just rename .env.local to .env
# and run npx prisma generate
  1. Push prisma schema to database
dotenv -e .env.local --  npx prisma db push
  1. Run the development server
npm run dev
  1. Open http://localhost:3001 with your browser to see the result.

☁️ API endpoints

Store

Endpoint Method Description
/api/stores POST Create new store
/api/stores/:id PATCH Update store
/api/stores/:id DELETE Delete store

Billboard

Endpoint Method Description
/api/:storeId/billboards GET Get all billboards
/api/:storeId/billboards/:id GET Get billboard by id
/api/:storeId/billboards POST Create new billboard
/api/:storeId/billboards/:id PATCH Update billboard
/api/:storeId/billboards/:id DELETE Delete billboard

Category

Endpoint Method Description
/api/:storeId/categories GET Get all categories
/api/:storeId/categories/:id GET Get category by id
/api/:storeId/categories POST Create new category
/api/:storeId/categories/:id PATCH Update category
/api/:storeId/categories/:id DELETE Delete category

Size

Endpoint Method Description
/api/:storeId/sizes GET Get all sizes
/api/:storeId/sizes/:id GET Get size by id
/api/:storeId/sizes POST Create new size
/api/:storeId/sizes/:id PATCH Update size
/api/:storeId/sizes/:id DELETE Delete size

Color

Endpoint Method Description
/api/:storeId/colors GET Get all colors
/api/:storeId/colors/:id GET Get color by id
/api/:storeId/colors POST Create new color
/api/:storeId/colors/:id PATCH Update color
/api/:storeId/colors/:id DELETE Delete color

Product

Endpoint Method Description
/api/:storeId/products GET Get all products
/api/:storeId/products/:id GET Get product by id
/api/:storeId/products POST Create new product
/api/:storeId/products/:id PATCH Update product
/api/:storeId/products/:id DELETE Delete product

Order

Endpoint Method Description
/api/:storeId/orders GET Get all orders

Screenshots

Sign in

Sign in

Sign up

Sign up

Create Store

Create Store

Dashboard

Dashboard

Billboards

Billboards

Create Billboard

Create Billboard

Edit Billboard

Edit Billboard

Categories

Categories

Create Category

Create Category

Sizes

Sizes

Create Size

Create Size

Colors

Colors

Create Color

Create Color

Products

Products

Create Product

Create Product

Orders

Orders

Store Settings

Store Settings

User Profile

User Profile

Light Mode

Light Mode

πŸ“„ License

MIT

Releases

No releases published

Packages

No packages published

Languages