├── client ├── public │ ├── 1.webp │ ├── 2.webp │ ├── 3.webp │ ├── favicon.png │ └── stripe.svg ├── lib │ ├── safe-action.ts │ ├── generate-token.ts │ ├── uploadthing.ts │ ├── rate-limiter.ts │ ├── auth-options.ts │ ├── constants.ts │ ├── utils.ts │ └── validation.ts ├── .eslintrc.json ├── postcss.config.mjs ├── next.config.js ├── app │ ├── api │ │ ├── auth │ │ │ └── [...nextauth] │ │ │ │ └── route.ts │ │ └── uploadthing │ │ │ ├── route.ts │ │ │ └── core.ts │ ├── (auth) │ │ ├── layout.tsx │ │ └── sign-in │ │ │ └── page.tsx │ ├── dashboard │ │ ├── watch-list │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── settings │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ ├── _components │ │ │ ├── sidebar.tsx │ │ │ ├── full-name.form.tsx │ │ │ └── edit-information.tsx │ │ ├── payments │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ ├── orders │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ └── (personal-information) │ │ │ ├── page.tsx │ │ │ └── loading.tsx │ ├── (root) │ │ ├── (home) │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ ├── cancel │ │ │ └── page.tsx │ │ ├── success │ │ │ └── page.tsx │ │ └── product │ │ │ ├── [productId] │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ │ └── _components │ │ │ └── create-order.btn.tsx │ ├── admin │ │ ├── layout.tsx │ │ ├── products │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ ├── _components │ │ │ ├── sidebar.tsx │ │ │ ├── order-actions.tsx │ │ │ └── product.card.tsx │ │ ├── payments │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ ├── (customers) │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ │ └── orders │ │ │ ├── loading.tsx │ │ │ └── page.tsx │ ├── layout.tsx │ └── globals.css ├── http │ └── axios.ts ├── types │ ├── next-auth.d.ts │ └── index.ts ├── components │ ├── providers │ │ └── session.provider.tsx │ ├── shared │ │ ├── logo.tsx │ │ ├── navbar.tsx │ │ ├── pagination.tsx │ │ ├── user-box.tsx │ │ └── filter.tsx │ ├── ui │ │ ├── skeleton.tsx │ │ ├── textarea.tsx │ │ ├── label.tsx │ │ ├── input.tsx │ │ ├── separator.tsx │ │ ├── toaster.tsx │ │ ├── badge.tsx │ │ ├── popover.tsx │ │ ├── avatar.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── accordion.tsx │ │ ├── input-otp.tsx │ │ ├── table.tsx │ │ ├── dialog.tsx │ │ ├── sheet.tsx │ │ ├── form.tsx │ │ ├── alert-dialog.tsx │ │ └── toast.tsx │ ├── loaders │ │ └── card.loader.tsx │ └── card │ │ ├── watch-list.card.tsx │ │ └── product.card.tsx ├── hooks │ ├── use-action.ts │ ├── use-product.ts │ └── use-toast.ts ├── components.json ├── .gitignore ├── tsconfig.json ├── middleware.ts ├── actions │ ├── auth.action.ts │ └── admin.action.ts ├── README.md ├── package.json └── tailwind.config.ts ├── server ├── libs │ ├── utils.js │ └── customer.js ├── routes │ ├── otp.js │ ├── auth.js │ ├── click.js │ ├── payme.js │ ├── index.js │ ├── admin.js │ ├── uzum.js │ └── user.js ├── models │ ├── otp.model.js │ ├── order.model.js │ ├── product.model.js │ ├── user.model.js │ └── transaction.model.js ├── errors │ ├── transaction.error.js │ └── base.error.js ├── middlewares │ ├── click.middleware.js │ ├── error.middleware.js │ ├── payme.middleware.js │ ├── user.middleware.js │ ├── admin.middleware.js │ └── uzum.middleware.js ├── controllers │ ├── otp.controller.js │ ├── auth.controller.js │ ├── uzum.controller.js │ ├── click.controller.js │ ├── stripe.controller.js │ └── payme.controller.js ├── .gitignore ├── package.json ├── app.js ├── template │ ├── otp.template.js │ ├── success.template.js │ ├── cancel.template.js │ └── update.template.js ├── services │ └── mail.service.js └── enum │ └── transaction.enum.js └── README.md /client/public/1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samarbadriddin0v/seleor-clone/HEAD/client/public/1.webp -------------------------------------------------------------------------------- /client/public/2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samarbadriddin0v/seleor-clone/HEAD/client/public/2.webp -------------------------------------------------------------------------------- /client/public/3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samarbadriddin0v/seleor-clone/HEAD/client/public/3.webp -------------------------------------------------------------------------------- /client/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samarbadriddin0v/seleor-clone/HEAD/client/public/favicon.png -------------------------------------------------------------------------------- /client/lib/safe-action.ts: -------------------------------------------------------------------------------- 1 | import { createSafeActionClient } from 'next-safe-action' 2 | 3 | export const actionClient = createSafeActionClient() 4 | -------------------------------------------------------------------------------- /client/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "next/typescript"], 3 | "rules": { 4 | "react-hooks/exhaustive-deps": "off" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /client/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /client/next.config.js: -------------------------------------------------------------------------------- 1 | const nextConfig = { 2 | images: { 3 | remotePatterns: [{ protocol: 'https', hostname: 'utfs.io', pathname: '**' }], 4 | }, 5 | } 6 | 7 | export default nextConfig 8 | -------------------------------------------------------------------------------- /server/libs/utils.js: -------------------------------------------------------------------------------- 1 | function formatPrice(price) { 2 | return new Intl.NumberFormat('uz-UZ', { style: 'currency', currency: 'UZS' }).format(price) 3 | } 4 | 5 | module.exports = { formatPrice } 6 | -------------------------------------------------------------------------------- /client/app/api/auth/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | import { authOptions } from '@/lib/auth-options' 2 | import NextAuth from 'next-auth' 3 | 4 | const handler = NextAuth(authOptions) 5 | export { handler as GET, handler as POST } 6 | -------------------------------------------------------------------------------- /client/app/api/uploadthing/route.ts: -------------------------------------------------------------------------------- 1 | import { createRouteHandler } from 'uploadthing/next' 2 | import { ourFileRouter } from './core' 3 | 4 | export const { GET, POST } = createRouteHandler({ 5 | router: ourFileRouter, 6 | }) 7 | -------------------------------------------------------------------------------- /client/http/axios.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | export const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL 4 | 5 | export const axiosClient = axios.create({ 6 | baseURL: SERVER_URL, 7 | withCredentials: true, 8 | }) 9 | -------------------------------------------------------------------------------- /client/types/next-auth.d.ts: -------------------------------------------------------------------------------- 1 | import { DefaultSession } from 'next-auth' 2 | import { IUser } from '.' 3 | 4 | declare module 'next-auth' { 5 | interface Session { 6 | currentUser?: IUser 7 | user: {} & DefaultSession['user'] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/lib/generate-token.ts: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | import jwt from 'jsonwebtoken' 4 | 5 | export const generateToken = async (userId?: string) => { 6 | const token = jwt.sign({ userId }, process.env.NEXT_PUBLIC_JWT_SECRET!, { expiresIn: '1m' }) 7 | return token 8 | } 9 | -------------------------------------------------------------------------------- /server/routes/otp.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router() 2 | 3 | const otpController = require('../controllers/otp.controller') 4 | 5 | router.post('/send', otpController.sendOtp) 6 | router.post('/verify', otpController.verifyOtp) 7 | 8 | module.exports = router 9 | -------------------------------------------------------------------------------- /server/routes/auth.js: -------------------------------------------------------------------------------- 1 | const authController = require('../controllers/auth.controller') 2 | 3 | const router = require('express').Router() 4 | 5 | router.post('/login', authController.login) 6 | router.post('/register', authController.register) 7 | 8 | module.exports = router 9 | -------------------------------------------------------------------------------- /client/app/(auth)/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ChildProps } from '@/types' 2 | import { FC } from 'react' 3 | 4 | const AuthLayout: FC = ({ children }) => { 5 | return
{children}
6 | } 7 | 8 | export default AuthLayout 9 | -------------------------------------------------------------------------------- /server/models/otp.model.js: -------------------------------------------------------------------------------- 1 | const { Schema, model } = require('mongoose') 2 | 3 | const otpSchema = new Schema({ 4 | email: { type: String, required: true }, 5 | otp: { type: String, required: true }, 6 | expireAt: { type: Date }, 7 | }) 8 | 9 | module.exports = model('Otp', otpSchema) 10 | -------------------------------------------------------------------------------- /client/lib/uploadthing.ts: -------------------------------------------------------------------------------- 1 | import { OurFileRouter } from '@/app/api/uploadthing/core' 2 | import { generateUploadButton, generateUploadDropzone } from '@uploadthing/react' 3 | 4 | export const UploadButton = generateUploadButton() 5 | export const UploadDropzone = generateUploadDropzone() 6 | -------------------------------------------------------------------------------- /client/components/providers/session.provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { ChildProps } from '@/types' 4 | import { SessionProvider as Session } from 'next-auth/react' 5 | import { FC } from 'react' 6 | 7 | const SessionProvider: FC = ({ children }) => { 8 | return {children} 9 | } 10 | 11 | export default SessionProvider 12 | -------------------------------------------------------------------------------- /client/components/shared/logo.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | import Link from 'next/link' 3 | 4 | const Logo = () => { 5 | return ( 6 | 7 |
8 | logo 9 |
10 | 11 | ) 12 | } 13 | 14 | export default Logo 15 | -------------------------------------------------------------------------------- /client/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 | -------------------------------------------------------------------------------- /server/routes/click.js: -------------------------------------------------------------------------------- 1 | const clickController = require('../controllers/click.controller') 2 | const userMiddleware = require('../middlewares/user.middleware') 3 | 4 | const router = require('express').Router() 5 | 6 | router.post('/prepare', clickController.prepare) 7 | router.post('/complete', clickController.complete) 8 | router.post('/checkout', userMiddleware, clickController.checkout) 9 | 10 | module.exports = router 11 | -------------------------------------------------------------------------------- /client/hooks/use-action.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { toast } from './use-toast' 3 | 4 | const useAction = () => { 5 | const [isLoading, setIsLoading] = useState(false) 6 | 7 | function onError(message: string) { 8 | setIsLoading(false) 9 | toast({ description: message, variant: 'destructive' }) 10 | } 11 | 12 | return { isLoading, setIsLoading, onError } 13 | } 14 | 15 | export default useAction 16 | -------------------------------------------------------------------------------- /server/routes/payme.js: -------------------------------------------------------------------------------- 1 | const { paymeCheckToken } = require('../middlewares/payme.middleware') 2 | const userMiddleware = require('../middlewares/user.middleware') 3 | const paymeController = require('../controllers/payme.controller') 4 | 5 | const router = require('express').Router() 6 | 7 | router.post('/payment', paymeCheckToken, paymeController.payme) 8 | router.post('/checkout', userMiddleware, paymeController.checkout) 9 | 10 | module.exports = router 11 | -------------------------------------------------------------------------------- /client/hooks/use-product.ts: -------------------------------------------------------------------------------- 1 | import { IProduct } from '@/types' 2 | import { create } from 'zustand' 3 | 4 | type Store = { 5 | product: IProduct | null 6 | setProduct: (product: IProduct | null) => void 7 | open: boolean 8 | setOpen: (open: boolean) => void 9 | } 10 | 11 | export const useProduct = create()(set => ({ 12 | product: null, 13 | setProduct: product => set({ product }), 14 | open: false, 15 | setOpen: open => set({ open }), 16 | })) 17 | -------------------------------------------------------------------------------- /server/models/order.model.js: -------------------------------------------------------------------------------- 1 | const { Schema, model } = require('mongoose') 2 | 3 | const orderSchema = new Schema( 4 | { 5 | user: { type: Schema.Types.ObjectId, ref: 'User', required: true }, 6 | product: { type: Schema.Types.ObjectId, ref: 'Product', required: true }, 7 | price: { type: Number, required: true }, 8 | status: { type: String, default: 'Pending confirm' }, 9 | }, 10 | { timestamps: true } 11 | ) 12 | 13 | module.exports = model('Order', orderSchema) 14 | -------------------------------------------------------------------------------- /server/errors/transaction.error.js: -------------------------------------------------------------------------------- 1 | const BaseError = require('./base.error') 2 | 3 | class TransactionError extends BaseError { 4 | constructor(transactionError, id, data) { 5 | super(transactionError.name) 6 | 7 | this.transactionErrorCode = transactionError.code 8 | this.transactionErrorMessage = transactionError.message 9 | this.transactionData = data 10 | this.transactionId = id 11 | this.isTransactionError = true 12 | } 13 | } 14 | 15 | module.exports = TransactionError 16 | -------------------------------------------------------------------------------- /server/routes/index.js: -------------------------------------------------------------------------------- 1 | const adminMiddleware = require('../middlewares/admin.middleware') 2 | 3 | const router = require('express').Router() 4 | 5 | router.use('/auth', require('./auth')) 6 | router.use('/otp', require('./otp')) 7 | router.use('/admin', adminMiddleware, require('./admin')) 8 | router.use('/user', require('./user')) 9 | router.use('/payme', require('./payme')) 10 | router.use('/uzum', require('./uzum')) 11 | router.use('/click', require('./click')) 12 | 13 | module.exports = router 14 | -------------------------------------------------------------------------------- /client/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.ts", 8 | "css": "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 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /server/errors/base.error.js: -------------------------------------------------------------------------------- 1 | module.exports = class BaseError extends Error { 2 | status 3 | errors 4 | name 5 | statusCode 6 | 7 | constructor(status, message, errors = [], name, statusCode) { 8 | super(message) 9 | this.status = status 10 | this.errors = errors 11 | this.name = name 12 | this.statusCode = statusCode 13 | } 14 | 15 | static BadRequest(message, errors = []) { 16 | return new BaseError(400, message, errors) 17 | } 18 | 19 | static Unauthorized() { 20 | return new BaseError(401, 'Unauthorized') 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/models/product.model.js: -------------------------------------------------------------------------------- 1 | const { Schema, model } = require('mongoose') 2 | 3 | const productSchema = new Schema( 4 | { 5 | title: { type: String, required: true }, 6 | category: { type: String, required: true }, 7 | price: { type: Number, required: true }, 8 | description: { type: String, required: true }, 9 | image: { type: String }, 10 | imageKey: { type: String }, 11 | stripePriceId: { type: String }, 12 | stripeProductId: { type: String }, 13 | }, 14 | { timestamps: true } 15 | ) 16 | 17 | module.exports = model('Product', productSchema) 18 | -------------------------------------------------------------------------------- /server/middlewares/click.middleware.js: -------------------------------------------------------------------------------- 1 | const md5 = require('md5') 2 | 3 | const clickCheckToken = (data, signString) => { 4 | const { click_trans_id, service_id, orderId, merchant_prepare_id, amount, action, sign_time } = data 5 | const CLICK_SECRET_KEY = process.env.CLICK_SECRET_KEY 6 | const prepareId = merchant_prepare_id || '' 7 | const signature = `${click_trans_id}${service_id}${CLICK_SECRET_KEY}${orderId}${prepareId}${amount}${action}${sign_time}` 8 | const signatureHash = md5(signature) 9 | return signatureHash === signString 10 | } 11 | 12 | module.exports = clickCheckToken 13 | -------------------------------------------------------------------------------- /server/middlewares/error.middleware.js: -------------------------------------------------------------------------------- 1 | const BaseError = require('../errors/base.error') 2 | 3 | module.exports = function (err, req, res, next) { 4 | if (err.isTransactionError) { 5 | return res.json({ 6 | error: { code: err.transactionErrorCode, message: err.transactionErrorMessage, data: err.transactionData }, 7 | id: err.transactionId, 8 | }) 9 | } 10 | 11 | if (err instanceof BaseError) { 12 | return res.status(err.status).json({ 13 | message: err.message, 14 | errors: err.errors, 15 | }) 16 | } 17 | 18 | return res.status(500).json({ message: err.message }) 19 | } 20 | -------------------------------------------------------------------------------- /client/app/dashboard/watch-list/loading.tsx: -------------------------------------------------------------------------------- 1 | import CardLoader from '@/components/loaders/card.loader' 2 | import Filter from '@/components/shared/filter' 3 | import { Separator } from '@/components/ui/separator' 4 | 5 | const Loading = () => { 6 | return ( 7 | <> 8 |

Watch list

9 | 10 | 11 |
12 | {Array.from({ length: 4 }).map((_, i) => ( 13 | 14 | ))} 15 |
16 | 17 | ) 18 | } 19 | 20 | export default Loading 21 | -------------------------------------------------------------------------------- /server/controllers/otp.controller.js: -------------------------------------------------------------------------------- 1 | const mailService = require('../services/mail.service') 2 | 3 | class OtpController { 4 | async sendOtp(req, res, next) { 5 | try { 6 | const { email } = req.body 7 | await mailService.sendOtpMail(email) 8 | res.json({ status: 200 }) 9 | } catch (error) { 10 | next(error) 11 | } 12 | } 13 | async verifyOtp(req, res, next) { 14 | try { 15 | const { email, otp } = req.body 16 | const result = await mailService.verifyOtp(email, otp) 17 | res.json(result) 18 | } catch (error) { 19 | next(error) 20 | } 21 | } 22 | } 23 | 24 | module.exports = new OtpController() 25 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | 32 | # env files (can opt-in for committing if needed) 33 | .env* 34 | 35 | # vercel 36 | .vercel 37 | 38 | # typescript 39 | *.tsbuildinfo 40 | next-env.d.ts 41 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | 32 | # env files (can opt-in for committing if needed) 33 | .env* 34 | 35 | # vercel 36 | .vercel 37 | 38 | # typescript 39 | *.tsbuildinfo 40 | next-env.d.ts 41 | -------------------------------------------------------------------------------- /server/models/user.model.js: -------------------------------------------------------------------------------- 1 | const { Schema, model } = require('mongoose') 2 | 3 | const userSchema = new Schema( 4 | { 5 | email: { type: String, required: true, unique: true }, 6 | fullName: { type: String, required: true }, 7 | password: { type: String, required: true }, 8 | role: { type: String, required: true, default: 'user' }, 9 | avatar: { type: String }, 10 | avatarKey: { type: String }, 11 | isDeleted: { type: Boolean, default: false }, 12 | deletedAt: { type: Date }, 13 | favorites: [{ type: Schema.Types.ObjectId, ref: 'Product' }], 14 | customerId: { type: String }, 15 | }, 16 | { timestamps: true } 17 | ) 18 | 19 | module.exports = model('User', userSchema) 20 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "next.config.js"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /server/routes/admin.js: -------------------------------------------------------------------------------- 1 | const adminController = require('../controllers/admin.controller') 2 | 3 | const router = require('express').Router() 4 | 5 | router.get('/products', adminController.getProducts) 6 | router.get('/customers', adminController.getCustomers) 7 | router.get('/orders', adminController.getOrders) 8 | router.get('/transactions', adminController.getTransactions) 9 | 10 | router.post('/create-product', adminController.createProduct) 11 | 12 | router.put('/update-product/:id', adminController.updateProduct) 13 | router.put('/update-order/:id', adminController.updateOrder) 14 | 15 | router.delete('/delete-product/:id', adminController.deleteProduct) 16 | 17 | module.exports = router 18 | -------------------------------------------------------------------------------- /server/routes/uzum.js: -------------------------------------------------------------------------------- 1 | const uzumController = require('../controllers/uzum.controller') 2 | const userMiddleware = require('../middlewares/user.middleware') 3 | const uzumCheckToken = require('../middlewares/uzum.middleware') 4 | 5 | const router = require('express').Router() 6 | 7 | router.post('/check', uzumCheckToken, uzumController.check) 8 | router.post('/create', uzumCheckToken, uzumController.create) 9 | router.post('/confirm', uzumCheckToken, uzumController.confirm) 10 | router.post('/reverse', uzumCheckToken, uzumController.reverse) 11 | router.post('/status', uzumCheckToken, uzumController.status) 12 | router.post('/checkout', userMiddleware, uzumController.checkout) 13 | 14 | module.exports = router 15 | -------------------------------------------------------------------------------- /client/app/dashboard/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ChildProps } from '@/types' 2 | import { FC } from 'react' 3 | import Sidebar from './_components/sidebar' 4 | import { getServerSession } from 'next-auth' 5 | import { authOptions } from '@/lib/auth-options' 6 | import { redirect } from 'next/navigation' 7 | 8 | const Layout: FC = async ({ children }) => { 9 | const session = await getServerSession(authOptions) 10 | 11 | if (!session) return redirect('/sign-in') 12 | 13 | return ( 14 |
15 |
16 | 17 |
18 |
{children}
19 |
20 | ) 21 | } 22 | 23 | export default Layout 24 | -------------------------------------------------------------------------------- /server/models/transaction.model.js: -------------------------------------------------------------------------------- 1 | const { Schema, model } = require('mongoose') 2 | 3 | const transactionSchema = new Schema( 4 | { 5 | id: { type: String }, 6 | user: { type: Schema.Types.ObjectId, ref: 'User' }, 7 | product: { type: Schema.Types.ObjectId, ref: 'Product' }, 8 | state: { type: Number }, 9 | amount: { type: Number }, 10 | create_time: { type: Number, default: Date.now() }, 11 | perform_time: { type: Number, default: 0 }, 12 | cancel_time: { type: Number, default: 0 }, 13 | reason: { type: Number, default: null }, 14 | provider: { type: String }, 15 | prepare_id: { type: String }, 16 | }, 17 | { timestamps: true } 18 | ) 19 | 20 | module.exports = model('Transaction', transactionSchema) 21 | -------------------------------------------------------------------------------- /client/app/(root)/(home)/loading.tsx: -------------------------------------------------------------------------------- 1 | import CardLoader from '@/components/loaders/card.loader' 2 | import Filter from '@/components/shared/filter' 3 | import { Separator } from '@/components/ui/separator' 4 | import React from 'react' 5 | 6 | const Loading = () => { 7 | return ( 8 | <> 9 |
10 |

Products

11 | 12 |
13 | 14 | 15 | 16 |
17 | {Array.from({ length: 6 }).map((_, i) => ( 18 | 19 | ))} 20 |
21 | 22 | ) 23 | } 24 | 25 | export default Loading 26 | -------------------------------------------------------------------------------- /client/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |