├── .prettierignore ├── apps ├── admin │ ├── .gitignore │ ├── .dockerignore │ ├── bun.lockb │ ├── postcss.config.js │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── providers │ │ │ ├── toast-provider.tsx │ │ │ ├── modal-provider.tsx │ │ │ └── theme-provider.tsx │ │ ├── app │ │ │ ├── login │ │ │ │ └── layout.tsx │ │ │ ├── api │ │ │ │ ├── auth │ │ │ │ │ ├── logout │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── otp │ │ │ │ │ │ └── email │ │ │ │ │ │ ├── try │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── verify │ │ │ │ │ │ └── route.ts │ │ │ │ ├── brands │ │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ │ └── route.ts │ │ │ │ └── categories │ │ │ │ │ └── route.ts │ │ │ ├── loading.tsx │ │ │ ├── (dashboard) │ │ │ │ ├── (routes) │ │ │ │ │ ├── users │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── components │ │ │ │ │ │ │ └── table.tsx │ │ │ │ │ ├── banners │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ ├── [bannerId] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ └── table.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── brands │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ ├── [brandId] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ └── table.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── categories │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ ├── [categoryId] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ └── table.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── orders │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ └── components │ │ │ │ │ │ │ └── table.tsx │ │ │ │ │ ├── payments │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── client.tsx │ │ │ │ │ │ │ └── columns.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── [paymentId] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── products │ │ │ │ │ │ ├── loading.tsx │ │ │ │ │ │ ├── [productId] │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── components │ │ │ │ │ │ └── table.tsx │ │ │ │ └── layout.tsx │ │ │ └── layout.tsx │ │ ├── actions │ │ │ ├── get-stock-count.ts │ │ │ ├── get-sales-count.ts │ │ │ ├── get-total-revenue.ts │ │ │ └── get-graph-revenue.ts │ │ ├── hooks │ │ │ ├── use-active-store.tsx │ │ │ ├── use-origin.tsx │ │ │ ├── use-product-modal.tsx │ │ │ └── use-category-modal.tsx │ │ ├── components │ │ │ ├── ui │ │ │ │ ├── heading.tsx │ │ │ │ ├── label.tsx │ │ │ │ ├── separator.tsx │ │ │ │ ├── input.tsx │ │ │ │ ├── modal.tsx │ │ │ │ ├── popover.tsx │ │ │ │ ├── checkbox.tsx │ │ │ │ ├── badge.tsx │ │ │ │ ├── switch.tsx │ │ │ │ ├── loader.tsx │ │ │ │ ├── avatar.tsx │ │ │ │ ├── api-alert.tsx │ │ │ │ └── alert.tsx │ │ │ ├── theme-toggle.tsx │ │ │ ├── navbar.tsx │ │ │ ├── logout-button.tsx │ │ │ ├── overview.tsx │ │ │ └── modals │ │ │ │ └── alert-modal.tsx │ │ ├── lib │ │ │ ├── prisma.ts │ │ │ ├── jwt.ts │ │ │ ├── utils.ts │ │ │ └── serial.ts │ │ ├── config │ │ │ └── site.ts │ │ ├── types │ │ │ └── prisma.ts │ │ └── middleware.ts │ ├── .eslintrc │ ├── next.config.js │ ├── .env.example │ ├── components.json │ ├── Dockerfile │ └── tsconfig.json └── storefront │ ├── .react-email │ ├── .gitignore │ ├── .prettierignore │ ├── src │ │ ├── styles │ │ │ └── globals.css │ │ ├── utils │ │ │ ├── index.ts │ │ │ ├── language-map.ts │ │ │ ├── unreachable.ts │ │ │ ├── copy-text-to-clipboard.ts │ │ │ ├── get-emails.ts │ │ │ └── as.ts │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── icon-check.tsx │ │ │ ├── icon-download.tsx │ │ │ ├── icon-base.tsx │ │ │ ├── tooltip.tsx │ │ │ ├── icon-button.tsx │ │ │ ├── tooltip-content.tsx │ │ │ ├── shell.tsx │ │ │ └── icon-clipboard.tsx │ │ └── app │ │ │ ├── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── home.tsx │ │ │ └── preview │ │ │ └── [slug] │ │ │ └── page.tsx │ ├── bun.lockb │ ├── postcss.config.js │ ├── next.config.js │ ├── .eslintrc.json │ └── tsconfig.json │ ├── .gitignore │ ├── .dockerignore │ ├── bun.lockb │ ├── postcss.config.js │ ├── public │ ├── favicon.ico │ └── fonts │ │ ├── Yekan │ │ └── Yekan.woff │ │ └── Inter │ │ └── inter-var-latin.woff2 │ ├── src │ ├── providers │ │ ├── toast-provider.tsx │ │ ├── modal-provider.tsx │ │ └── theme-provider.tsx │ ├── types │ │ ├── nav.ts │ │ └── prisma.ts │ ├── app │ │ ├── robots.ts │ │ ├── api │ │ │ ├── auth │ │ │ │ ├── logout │ │ │ │ │ └── route.ts │ │ │ │ └── otp │ │ │ │ │ ├── email │ │ │ │ │ └── try │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── phone │ │ │ │ │ └── try │ │ │ │ │ └── route.ts │ │ │ ├── products │ │ │ │ ├── route.ts │ │ │ │ └── [productId] │ │ │ │ │ └── route.ts │ │ │ ├── addresses │ │ │ │ ├── [addressId] │ │ │ │ │ └── route.tsx │ │ │ │ └── route.ts │ │ │ ├── profile │ │ │ │ └── route.ts │ │ │ ├── orders │ │ │ │ └── [orderId] │ │ │ │ │ └── route.tsx │ │ │ └── subscription │ │ │ │ ├── email │ │ │ │ └── route.ts │ │ │ │ └── phone │ │ │ │ └── route.ts │ │ ├── loading.tsx │ │ ├── (store) │ │ │ ├── layout.tsx │ │ │ └── (routes) │ │ │ │ ├── cart │ │ │ │ ├── page.tsx │ │ │ │ └── components │ │ │ │ │ ├── skeleton.tsx │ │ │ │ │ └── grid.tsx │ │ │ │ ├── profile │ │ │ │ ├── addresses │ │ │ │ │ ├── [addressId] │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── components │ │ │ │ │ │ └── table.tsx │ │ │ │ ├── orders │ │ │ │ │ └── components │ │ │ │ │ │ └── table.tsx │ │ │ │ └── components │ │ │ │ │ └── switcher.tsx │ │ │ │ ├── blog │ │ │ │ └── page.tsx │ │ │ │ ├── wishlist │ │ │ │ └── page.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── privacy │ │ │ │ └── page.tsx │ │ │ │ └── checkout │ │ │ │ └── page.tsx │ │ ├── sitemap.ts │ │ └── layout.tsx │ ├── lib │ │ ├── omit.ts │ │ ├── prisma.ts │ │ ├── cart.ts │ │ ├── jwt.ts │ │ ├── serial.ts │ │ ├── utils.ts │ │ └── order.ts │ ├── components │ │ ├── native │ │ │ ├── separator.tsx │ │ │ ├── heading.tsx │ │ │ ├── mdx │ │ │ │ ├── Step.tsx │ │ │ │ ├── ConsCard.tsx │ │ │ │ ├── ProsCard.tsx │ │ │ │ └── MDXComponents.tsx │ │ │ ├── GoogleAnalytics.tsx │ │ │ ├── modal.tsx │ │ │ ├── nav │ │ │ │ └── sidebar.tsx │ │ │ └── Toast.tsx │ │ ├── ui │ │ │ ├── skeleton.tsx │ │ │ ├── label.tsx │ │ │ ├── textarea.tsx │ │ │ ├── input.tsx │ │ │ ├── separator.tsx │ │ │ ├── toaster.tsx │ │ │ ├── popover.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── switch.tsx │ │ │ ├── badge.tsx │ │ │ ├── loader.tsx │ │ │ ├── toggle.tsx │ │ │ ├── avatar.tsx │ │ │ └── scroll-area.tsx │ │ └── modals │ │ │ └── alert-modal.tsx │ ├── config │ │ ├── site.ts │ │ └── docs.ts │ ├── hooks │ │ └── useAuthentication.tsx │ ├── middleware.ts │ └── state │ │ └── Cart.tsx │ ├── .eslintrc │ ├── .env.example │ ├── components.json │ ├── next.config.js │ ├── vercel.json │ ├── tsconfig.json │ └── Dockerfile ├── packages ├── mail │ ├── .gitignore │ ├── bun.lockb │ ├── src │ │ ├── index.ts │ │ └── helpers │ │ │ ├── sendMail.ts │ │ │ └── getTransporter.ts │ └── package.json ├── oauth │ ├── .gitignore │ ├── src │ │ └── index.ts │ ├── yarn.lock │ └── package.json ├── regex │ ├── .gitignore │ ├── src │ │ └── index.ts │ ├── yarn.lock │ └── package.json ├── rng │ ├── .gitignore │ ├── yarn.lock │ └── package.json ├── sms │ ├── .gitignore │ ├── .env.example │ ├── yarn.lock │ ├── package.json │ └── src │ │ └── index.ts ├── slugify │ ├── .gitignore │ ├── yarn.lock │ ├── src │ │ └── index.ts │ └── package.json └── zarinpal │ ├── .gitignore │ ├── .npmignore │ ├── src │ ├── index.ts │ ├── query.ts │ └── auth.ts │ ├── yarn.lock │ └── package.json ├── bun.lockb ├── .lintstagedrc.json ├── .prettierrc ├── .vscode └── settings.json ├── .gitignore ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── package.json ├── LICENSE.md └── .eslintrc.js /.prettierignore: -------------------------------------------------------------------------------- 1 | .next 2 | .vercel -------------------------------------------------------------------------------- /apps/admin/.gitignore: -------------------------------------------------------------------------------- 1 | /.next 2 | /node_modules -------------------------------------------------------------------------------- /packages/mail/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /packages/oauth/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /packages/regex/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /packages/rng/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /packages/sms/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /packages/slugify/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /packages/zarinpal/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /packages/zarinpal/.npmignore: -------------------------------------------------------------------------------- 1 | /src 2 | /node_modules -------------------------------------------------------------------------------- /apps/storefront/.react-email/.gitignore: -------------------------------------------------------------------------------- 1 | /.next 2 | /node_modules -------------------------------------------------------------------------------- /packages/sms/.env.example: -------------------------------------------------------------------------------- 1 | SMS_API_KEY = "" 2 | SMS_NUMBER = "" -------------------------------------------------------------------------------- /apps/storefront/.gitignore: -------------------------------------------------------------------------------- 1 | /.next 2 | /node_modules 3 | 4 | sw.json 5 | -------------------------------------------------------------------------------- /apps/storefront/.react-email/.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | .next 3 | node_modules -------------------------------------------------------------------------------- /packages/zarinpal/src/index.ts: -------------------------------------------------------------------------------- 1 | import { query } from './query' 2 | 3 | export { query } 4 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/bun.lockb -------------------------------------------------------------------------------- /packages/oauth/src/index.ts: -------------------------------------------------------------------------------- 1 | import googleAuth from './google' 2 | 3 | export { googleAuth } 4 | -------------------------------------------------------------------------------- /apps/admin/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | prisma 4 | Dockerfile 5 | .dockerignore 6 | .git 7 | .env 8 | -------------------------------------------------------------------------------- /apps/admin/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/apps/admin/bun.lockb -------------------------------------------------------------------------------- /apps/storefront/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | prisma 4 | Dockerfile 5 | .dockerignore 6 | .git 7 | .env 8 | -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "*.ts": ["prettier --write", "eslint"], 3 | "*.tsx": ["prettier --write", "eslint"] 4 | } 5 | -------------------------------------------------------------------------------- /apps/storefront/.react-email/src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /packages/mail/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/packages/mail/bun.lockb -------------------------------------------------------------------------------- /apps/storefront/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/apps/storefront/bun.lockb -------------------------------------------------------------------------------- /apps/admin/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /apps/admin/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/apps/admin/public/favicon.ico -------------------------------------------------------------------------------- /apps/storefront/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /apps/storefront/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/apps/storefront/public/favicon.ico -------------------------------------------------------------------------------- /apps/storefront/.react-email/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/apps/storefront/.react-email/bun.lockb -------------------------------------------------------------------------------- /apps/storefront/.react-email/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/storefront/.react-email/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './as'; 2 | export * from './copy-text-to-clipboard'; 3 | export * from './unreachable'; 4 | -------------------------------------------------------------------------------- /apps/storefront/public/fonts/Yekan/Yekan.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/apps/storefront/public/fonts/Yekan/Yekan.woff -------------------------------------------------------------------------------- /packages/mail/src/index.ts: -------------------------------------------------------------------------------- 1 | import getTransporter from './helpers/getTransporter' 2 | import sendMail from './helpers/sendMail' 3 | 4 | export { sendMail, getTransporter } 5 | -------------------------------------------------------------------------------- /apps/storefront/public/fonts/Inter/inter-var-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slowfound/next-prisma-tailwind-ecommerce/HEAD/apps/storefront/public/fonts/Inter/inter-var-latin.woff2 -------------------------------------------------------------------------------- /apps/admin/src/providers/toast-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Toaster } from 'react-hot-toast' 4 | 5 | export const ToastProvider = () => { 6 | return 7 | } 8 | -------------------------------------------------------------------------------- /apps/storefront/.react-email/src/utils/language-map.ts: -------------------------------------------------------------------------------- 1 | const languageMap = { 2 | jsx: 'React', 3 | markup: 'HTML', 4 | markdown: 'Plain Text', 5 | }; 6 | 7 | export default languageMap; 8 | -------------------------------------------------------------------------------- /apps/storefront/src/providers/toast-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Toaster } from 'react-hot-toast' 4 | 5 | export const ToastProvider = () => { 6 | return 7 | } 8 | -------------------------------------------------------------------------------- /apps/storefront/src/types/nav.ts: -------------------------------------------------------------------------------- 1 | export interface NavItem { 2 | title: string 3 | href?: string 4 | disabled?: boolean 5 | external?: boolean 6 | icon?: any 7 | label?: string 8 | } 9 | -------------------------------------------------------------------------------- /apps/admin/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next", 3 | "rules": { 4 | "react/prop-types": 0, 5 | "react/no-unescaped-entities": 0, 6 | "@next/next/no-server-import-in-page": 0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /apps/storefront/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next", 3 | "rules": { 4 | "react/prop-types": 0, 5 | "react/no-unescaped-entities": 0, 6 | "@next/next/no-server-import-in-page": 0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /apps/storefront/.react-email/src/utils/unreachable.ts: -------------------------------------------------------------------------------- 1 | export const unreachable = ( 2 | condition: never, 3 | message = `Entered unreachable code. Received '${condition}'.`, 4 | ): never => { 5 | throw new TypeError(message); 6 | }; 7 | -------------------------------------------------------------------------------- /apps/storefront/.react-email/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | export * from './code'; 3 | export * from './heading'; 4 | export * from './logo'; 5 | export * from './sidebar'; 6 | export * from './text'; 7 | export * from './topbar'; 8 | -------------------------------------------------------------------------------- /apps/storefront/src/app/robots.ts: -------------------------------------------------------------------------------- 1 | import { MetadataRoute } from "next" 2 | 3 | export default function robots(): MetadataRoute.Robots { 4 | return { 5 | rules: { 6 | userAgent: "*", 7 | allow: "/", 8 | }, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/admin/src/app/login/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Fragment } from 'react' 2 | 3 | export default async function DashboardLayout({ 4 | children, 5 | }: { 6 | children: React.ReactNode 7 | }) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /apps/admin/src/actions/get-stock-count.ts: -------------------------------------------------------------------------------- 1 | import prisma from '@/lib/prisma' 2 | 3 | export const getStockCount = async () => { 4 | return await prisma.product.count({ 5 | where: { 6 | isAvailable: true, 7 | }, 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /apps/storefront/.react-email/src/utils/copy-text-to-clipboard.ts: -------------------------------------------------------------------------------- 1 | export const copyTextToClipboard = async (text: string) => { 2 | try { 3 | await navigator.clipboard.writeText(text); 4 | } catch { 5 | throw new Error('Not able to copy'); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /apps/storefront/src/lib/omit.ts: -------------------------------------------------------------------------------- 1 | export function omitUser( 2 | user: User, 3 | ...keys: Key[] 4 | ): Omit { 5 | for (let key of keys) { 6 | delete user['password'] 7 | } 8 | return user 9 | } 10 | -------------------------------------------------------------------------------- /apps/admin/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | 3 | module.exports = { 4 | images: { 5 | remotePatterns: [ 6 | { 7 | protocol: 'https', 8 | hostname: '**', 9 | }, 10 | ], 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /apps/admin/src/actions/get-sales-count.ts: -------------------------------------------------------------------------------- 1 | import prisma from '@/lib/prisma' 2 | 3 | export const getSalesCount = async () => { 4 | const salesCount = await prisma.order.count({ 5 | where: { 6 | isPaid: true, 7 | }, 8 | }) 9 | 10 | return salesCount 11 | } 12 | -------------------------------------------------------------------------------- /apps/admin/src/app/api/auth/logout/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | 3 | export async function GET(req: NextRequest) { 4 | const response = NextResponse.redirect(new URL(`/login`, req.url)) 5 | response.cookies.delete('token') 6 | response.cookies.delete('logged-in') 7 | return response 8 | } 9 | -------------------------------------------------------------------------------- /apps/storefront/.react-email/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { getEmails } from '../utils/get-emails'; 2 | import Home from './home'; 3 | 4 | export default async function Index() { 5 | const { emails } = await getEmails(); 6 | return ; 7 | } 8 | 9 | export const metadata = { 10 | title: 'React Email', 11 | }; 12 | -------------------------------------------------------------------------------- /apps/storefront/src/app/api/auth/logout/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest, NextResponse } from 'next/server' 2 | 3 | export async function GET(req: NextRequest) { 4 | const response = NextResponse.redirect(new URL(`/login`, req.url)) 5 | response.cookies.delete('token') 6 | response.cookies.delete('logged-in') 7 | return response 8 | } 9 | -------------------------------------------------------------------------------- /apps/admin/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL = "" 2 | 3 | NEXT_PUBLIC_GOOGLE_OAUTH_ID = "" 4 | 5 | GOOGLE_OAUTH_SECRET = "" 6 | 7 | MAIL_SMTP_SERVICE = "Gmail" 8 | MAIL_SMTP_PASS = "" 9 | MAIL_SMTP_USER = "" 10 | 11 | NEXT_PUBLIC_URL = "" 12 | 13 | NODE_ENV = 'development' 14 | 15 | JWT_SECRET_KEY = "" 16 | 17 | NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME = "" -------------------------------------------------------------------------------- /apps/admin/src/app/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/storefront/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL = "" 2 | 3 | NEXT_PUBLIC_GOOGLE_OAUTH_ID = "" 4 | 5 | GOOGLE_OAUTH_SECRET = "" 6 | 7 | MAIL_SMTP_SERVICE = "Gmail" 8 | MAIL_SMTP_PASS = "" 9 | MAIL_SMTP_USER = "" 10 | 11 | NEXT_PUBLIC_URL = "" 12 | 13 | NODE_ENV = 'development' 14 | 15 | JWT_SECRET_KEY = "" 16 | 17 | NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME = "" -------------------------------------------------------------------------------- /apps/storefront/.react-email/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | experimental: { 6 | appDir: true, 7 | externalDir: true, // compile files that are located next to the .react-email directory 8 | }, 9 | }; 10 | 11 | module.exports = nextConfig; 12 | -------------------------------------------------------------------------------- /apps/storefront/src/app/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/storefront/src/components/native/separator.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | 3 | export function Separator({ className }: { className?: string }) { 4 | return ( 5 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /apps/storefront/src/lib/prisma.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client' 2 | 3 | let prisma: PrismaClient 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | prisma = new PrismaClient() 7 | } else { 8 | if (!global.prisma) { 9 | global.prisma = new PrismaClient() 10 | } 11 | prisma = global.prisma 12 | } 13 | 14 | export default prisma 15 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 3, 4 | "semi": false, 5 | "singleQuote": true, 6 | "plugins": ["prettier-plugin-tailwindcss", "@trivago/prettier-plugin-sort-imports"], 7 | "importOrder": ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"], 8 | "importOrderSeparation": true, 9 | "importOrderSortSpecifiers": true 10 | } 11 | -------------------------------------------------------------------------------- /apps/admin/src/app/(dashboard)/(routes)/users/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/admin/src/app/(dashboard)/(routes)/banners/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/admin/src/app/(dashboard)/(routes)/brands/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/admin/src/app/(dashboard)/(routes)/categories/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/admin/src/app/(dashboard)/(routes)/orders/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/admin/src/app/(dashboard)/(routes)/payments/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/admin/src/app/(dashboard)/(routes)/products/loading.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Loader } from '@/components/ui/loader' 4 | 5 | export default function Loading() { 6 | return ( 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/admin/src/providers/modal-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect, useState } from 'react' 4 | 5 | export const ModalProvider = () => { 6 | const [isMounted, setIsMounted] = useState(false) 7 | 8 | useEffect(() => { 9 | setIsMounted(true) 10 | }, []) 11 | 12 | if (!isMounted) { 13 | return null 14 | } 15 | 16 | return <> 17 | } 18 | -------------------------------------------------------------------------------- /apps/storefront/src/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/lib/utils' 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /apps/storefront/src/providers/modal-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect, useState } from 'react' 4 | 5 | export const ModalProvider = () => { 6 | const [isMounted, setIsMounted] = useState(false) 7 | 8 | useEffect(() => { 9 | setIsMounted(true) 10 | }, []) 11 | 12 | if (!isMounted) { 13 | return null 14 | } 15 | 16 | return <> 17 | } 18 | -------------------------------------------------------------------------------- /apps/admin/src/hooks/use-active-store.tsx: -------------------------------------------------------------------------------- 1 | import { create } from 'zustand' 2 | 3 | interface useActiveStoreInterface { 4 | id?: string 5 | set: (id: string) => void 6 | reset: () => void 7 | } 8 | 9 | export const useActiveStore = create((set) => ({ 10 | id: undefined, 11 | set: (id: string) => set({ id }), 12 | reset: () => set({ id: undefined }), 13 | })) 14 | -------------------------------------------------------------------------------- /apps/admin/src/providers/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { ThemeProvider as NextThemesProvider } from 'next-themes' 4 | import { type ThemeProviderProps } from 'next-themes/dist/types' 5 | import * as React from 'react' 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /apps/storefront/src/providers/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { ThemeProvider as NextThemesProvider } from 'next-themes' 4 | import { type ThemeProviderProps } from 'next-themes/dist/types' 5 | import * as React from 'react' 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/package-lock.json": true, 4 | "**/node_modules": true, 5 | "**/.next": true, 6 | "**/dist": true, 7 | "**/yarn.lock": true, 8 | "**/bun.lockb": true 9 | }, 10 | "eslint.workingDirectories": [ 11 | "./apps/storefront", 12 | "./apps/admin", 13 | "./apps/storefront/.react-email" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /apps/admin/src/components/ui/heading.tsx: -------------------------------------------------------------------------------- 1 | interface HeadingProps { 2 | title: string 3 | description: string 4 | } 5 | 6 | export const Heading: React.FC = ({ title, description }) => { 7 | return ( 8 |
9 |

{title}

10 |

{description}

11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /apps/admin/src/app/(dashboard)/layout.tsx: -------------------------------------------------------------------------------- 1 | import Navbar from '@/components/navbar' 2 | 3 | export default async function DashboardLayout({ 4 | children, 5 | }: { 6 | children: React.ReactNode 7 | }) { 8 | return ( 9 | <> 10 | 11 |
12 | {children} 13 |
14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /apps/storefront/src/components/native/heading.tsx: -------------------------------------------------------------------------------- 1 | interface HeadingProps { 2 | title: string 3 | description: string 4 | } 5 | 6 | export const Heading: React.FC = ({ title, description }) => { 7 | return ( 8 |
9 |

{title}

10 |

{description}

11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /packages/zarinpal/src/query.ts: -------------------------------------------------------------------------------- 1 | const base = process.env.ZARINPAL_BASE_URL 2 | 3 | export async function query({ token, query }) { 4 | const response = await fetch(base + '/api/v4/graphql', { 5 | method: 'POST', 6 | headers: { 7 | 'Content-Type': 'application/json', 8 | Authorization: 'Bearer ' + token, 9 | }, 10 | body: JSON.stringify({ query }), 11 | }) 12 | 13 | return await response.json() 14 | } 15 | -------------------------------------------------------------------------------- /apps/admin/src/hooks/use-origin.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | 3 | export const useOrigin = () => { 4 | const [mounted, setMounted] = useState(false) 5 | const origin = 6 | typeof window !== 'undefined' && window.location.origin 7 | ? window.location.origin 8 | : '' 9 | 10 | useEffect(() => { 11 | setMounted(true) 12 | }, []) 13 | 14 | if (!mounted) { 15 | return '' 16 | } 17 | 18 | return origin 19 | } 20 | -------------------------------------------------------------------------------- /apps/storefront/src/components/native/mdx/Step.tsx: -------------------------------------------------------------------------------- 1 | export default function Step({ number, title }) { 2 | return ( 3 |
4 |
5 | {number} 6 |
7 |

{title}

8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /apps/admin/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } -------------------------------------------------------------------------------- /apps/storefront/.react-email/src/utils/get-emails.ts: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'fs'; 2 | import path from 'path'; 3 | 4 | export const CONTENT_DIR = '../src/emails'; 5 | 6 | export const getEmails = async () => { 7 | const emailsDirectory = path.join(process.cwd(), CONTENT_DIR); 8 | const filenames = await fs.readdir(emailsDirectory); 9 | const emails = filenames 10 | .map((file) => file.replace(/\.(jsx|tsx)$/g, '')) 11 | .filter((file) => file !== 'components'); 12 | return { emails, filenames }; 13 | }; 14 | -------------------------------------------------------------------------------- /apps/storefront/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } -------------------------------------------------------------------------------- /apps/storefront/src/app/(store)/layout.tsx: -------------------------------------------------------------------------------- 1 | import Footer from '@/components/native/Footer' 2 | import Header from '@/components/native/nav/parent' 3 | 4 | export default async function DashboardLayout({ 5 | children, 6 | }: { 7 | children: React.ReactNode 8 | }) { 9 | return ( 10 | <> 11 |
12 |
13 | {children} 14 |
15 |