87 | >(({ className, ...props }, ref) => (
88 | [role=checkbox]]:translate-y-[2px]",
92 | className
93 | )}
94 | {...props}
95 | />
96 | ))
97 | TableCell.displayName = "TableCell"
98 |
99 | const TableCaption = React.forwardRef<
100 | HTMLTableCaptionElement,
101 | React.HTMLAttributes
102 | >(({ className, ...props }, ref) => (
103 |
108 | ))
109 | TableCaption.displayName = "TableCaption"
110 |
111 | export {
112 | Table,
113 | TableHeader,
114 | TableBody,
115 | TableFooter,
116 | TableHead,
117 | TableRow,
118 | TableCell,
119 | TableCaption,
120 | }
121 |
--------------------------------------------------------------------------------
/client/src/Layout/Header/CartSheet/CartSheet.tsx:
--------------------------------------------------------------------------------
1 | import { Badge } from "@/components/ui/badge";
2 | import { Button, buttonVariants } from "@/components/ui/button";
3 | import { Sheet, SheetContent, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
4 | import { cn } from "@/lib/utils";
5 | import { Separator } from "@radix-ui/react-dropdown-menu";
6 | import { useQuery } from "@tanstack/react-query";
7 | import { ShoppingCartIcon } from "lucide-react";
8 | import { Link } from "react-router-dom";
9 | import CartProducts from "./CartProducts";
10 | import { GetUserCartItems } from "@/services/cart.api";
11 |
12 | export default function CartSheet() {
13 |
14 | const {data} = useQuery({
15 | queryKey: ['cart-items'],
16 | queryFn: GetUserCartItems
17 | })
18 | const ItemCount = data ? data?.products?.length : 0
19 |
20 | return (
21 |
22 |
23 |
29 |
30 |
31 |
32 | Cart {data && (`${ItemCount}`)}
33 |
34 |
35 | {data && ItemCount > 0 ? (
36 | <>
37 |
38 |
39 |
40 |
41 |
42 | Shipping
43 | Free
44 |
45 |
46 | Taxes
47 | Calculated at checkout
48 |
49 |
50 | Total
51 | $ {data.cartTotal}
52 |
53 |
54 |
55 |
56 |
63 | View Cart Page
64 |
65 |
66 |
67 |
68 | >
69 | ): (
70 |
71 |
75 |
76 | Your cart is empty
77 |
78 |
79 |
90 | Add items to your cart to checkout
91 |
92 |
93 |
94 | )}
95 |
96 |
97 | );
98 | }
99 |
--------------------------------------------------------------------------------
/client/src/components/Forms/SignupForm.tsx:
--------------------------------------------------------------------------------
1 | import { SignupSchema } from "@/utils/Schema";
2 | import { Button } from "../ui/button";
3 | import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
4 | import { Input } from "../ui/input";
5 | import { zodResolver } from "@hookform/resolvers/zod";
6 | import {useForm} from 'react-hook-form'
7 | import {z} from 'zod'
8 | import { useMutation, useQueryClient } from "@tanstack/react-query";
9 | import { SignupUserApi } from "@/services/api";
10 | import { toast } from "sonner";
11 | import { useNavigate } from "react-router-dom";
12 |
13 | export default function SignupForm() {
14 | const queryClient = useQueryClient();
15 | const navigate = useNavigate()
16 | const form = useForm>({resolver: zodResolver(SignupSchema), defaultValues: {
17 | email: '',
18 | firstname: '',
19 | lastname: '',
20 | password: '',
21 | mobile: '',
22 | }})
23 |
24 | const {mutate, isPending} = useMutation({
25 | mutationKey: ['signup'],
26 | mutationFn: SignupUserApi,
27 | onSuccess: (data) => {
28 | toast.success(data.message)
29 | queryClient.invalidateQueries({ queryKey: ["authuser"]});
30 | queryClient.invalidateQueries({ queryKey: ["authadmin"] });
31 | navigate('/')
32 | },
33 | onError: (error) => {
34 | toast.error(error.message)
35 | }
36 | })
37 |
38 | const onSubmit = (formData: z.infer) => {
39 | mutate(formData)
40 | }
41 |
42 |
43 | return (
44 |
95 |
96 | )
97 | }
98 |
--------------------------------------------------------------------------------
/server/src/controllers/cart.controller.ts:
--------------------------------------------------------------------------------
1 | import { ErrorMessage, SuccessMessage } from './../utils/helper';
2 | import { CartModel, FoodModel } from "../models";
3 | import { AsyncWrapper, HttpStatusCode } from "../utils";
4 | import { Request, Response } from "express";
5 |
6 | export const GetAllCartItems = AsyncWrapper(async (req: Request, res: Response) => {
7 | const cart = await CartModel.findOne({ orderBy: req.userId }).populate("products.product");
8 | res.status(HttpStatusCode.OK).json(cart);
9 | });
10 |
11 | export const CreateUserCart = AsyncWrapper(async (req: Request, res: Response) => {
12 | const { productId, count } = req.body;
13 |
14 | const product = await FoodModel.findById(productId);
15 |
16 | if (!product) {
17 | return res.status(HttpStatusCode.BAD_REQUEST).json({ message: ErrorMessage.PRODUCT_NOT_FOUND });
18 | }
19 |
20 | const cart = await CartModel.findOne({ orderBy: req.userId });
21 | if (!cart) {
22 | let total = 0;
23 | total = total + product.price * count;
24 | const newCart = await CartModel.create({
25 | orderBy: req.userId,
26 | products: [{ product: productId, count, price: product.price }],
27 | cartTotal: total,
28 | });
29 |
30 | return res.status(HttpStatusCode.CREATED).json(newCart);
31 | }
32 |
33 | const index = cart.products.findIndex((p) => p?.product?.toString() === productId);
34 | if (index > -1) {
35 | cart.products[index].count += count;
36 | cart.cartTotal! += product.price * count;
37 | } else {
38 | cart.products.push({
39 | product: productId,
40 | count,
41 | price: product.price,
42 | });
43 | cart.cartTotal! += product.price * count;
44 | }
45 |
46 | await cart.save();
47 | res.json({ message: SuccessMessage.PRODUCT_ADDED_SUCCESSFULLY });
48 | });
49 |
50 | export const RemoveFromCart = AsyncWrapper(async (req: Request, res: Response) => {
51 | const { productId } = req.params;
52 |
53 | const product = await FoodModel.findById(productId);
54 |
55 | if (!product) {
56 | return res.status(HttpStatusCode.BAD_REQUEST).json({ message: ErrorMessage.PRODUCT_NOT_FOUND });
57 | }
58 |
59 | let cart = await CartModel.findOne({ orderBy: req.userId });
60 |
61 | if (!cart) {
62 | return res.json({ message: ErrorMessage.PRODUCT_NOT_FOUND });
63 | }
64 | const index = cart.products.findIndex((p) => p?.product?.toString() === productId);
65 |
66 | if (index !== -1) {
67 | cart.products.splice(index, 1);
68 | cart.cartTotal! -= product.price;
69 | await cart.save();
70 | res.status(HttpStatusCode.OK).json({ message: SuccessMessage.PRODUCT_DELETED_SUCCESSFULLY });
71 | }
72 | });
73 |
74 | export const UpdateCartItem = AsyncWrapper(async (req: Request, res: Response) => {
75 | const { productId } = req.params;
76 | const { count } = req.body;
77 |
78 | const product = await FoodModel.findById(productId);
79 |
80 | if (!product) {
81 | return res.status(HttpStatusCode.BAD_REQUEST).json({ message: ErrorMessage.PRODUCT_NOT_FOUND });
82 | }
83 |
84 | if (count <= 0) {
85 | return res.status(HttpStatusCode.BAD_REQUEST).json({ message: ErrorMessage.PRODUCT_COUNT });
86 | }
87 |
88 | const cart = await CartModel.findOne({ orderBy: req.userId });
89 |
90 | if (cart) {
91 | const item = cart.products.find((p) => p?.product?.toString() === productId);
92 |
93 | if (item) {
94 | const oldPrice = item.price;
95 |
96 | item.count = count;
97 | item.price! = product.price * count;
98 | cart.cartTotal! = cart.cartTotal! - oldPrice! + item.price;
99 | await cart.save();
100 | res.status(HttpStatusCode.OK).json({ message: SuccessMessage.PRODUCT_UPDATED_SUCCESSFULLY});
101 | }
102 | }
103 | });
104 |
--------------------------------------------------------------------------------
/client/src/pages/Cartpage/Cartpage.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { Button, buttonVariants } from "@/components/ui/button";
3 | import { Input } from "@/components/ui/input";
4 | import { ScrollArea } from "@/components/ui/scroll-area";
5 | import { useAuthContext } from "@/context/AuthContext";
6 | import UpdateCart from "@/Layout/Header/CartSheet/UpdateCart";
7 | import { cn } from "@/lib/utils";
8 | import { CartItemProps } from "@/services/interface";
9 | import { useQuery } from "@tanstack/react-query";
10 | import { Link } from "react-router-dom";
11 |
12 | export default function Cartpage() {
13 | const { isAuth } = useAuthContext();
14 | const { data } = useQuery({queryKey: ["cart-items"]});
15 |
16 |
17 |
18 | return (
19 |
20 |
21 |
22 | Shopping Cart
23 | Cart Item {data?.products.length}
24 |
25 |
26 |
27 | Product Details
28 | Quantity
29 | Price
30 | Total
31 |
32 | {data?.products.map((product) => (
33 |
34 |
35 | 
36 |
37 | {product.product.name}
38 | {product.product.category}
39 |
40 |
41 |
46 |
47 | $ {product.product.price}
48 |
49 |
50 | $ {data.cartTotal}
51 |
52 |
53 | ))}
54 |
55 |
56 |
57 |
58 |
59 | Order Summary
60 |
61 | Cart Total
62 | $ {data?.cartTotal}
63 |
64 |
65 |
66 |
67 | Promo Code
68 |
69 |
70 |
71 |
72 |
73 |
74 | Total Cost
75 | $ {data?.cartTotal}
76 |
77 | {isAuth ? (
78 |
82 | Checkout
83 |
84 | ) : (
85 |
89 | Please Login
90 |
91 | )}
92 |
93 |
94 |
95 | );
96 | }
97 |
--------------------------------------------------------------------------------
/server/dist/controllers/food.controller.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.GetRecentlyAdded = exports.GetNonVegFoods = exports.GetVegFoods = exports.SearchFood = exports.GetAllProducts = exports.CreateProduct = void 0;
13 | const utils_1 = require("../utils");
14 | const models_1 = require("../models");
15 | const cloudinary_1 = require("cloudinary");
16 | /* Create product */
17 | exports.CreateProduct = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
18 | const { name, description, price, category, discount, ingredients, starRating } = req.body;
19 | const findFood = yield models_1.FoodModel.findOne({ name });
20 | if (findFood) {
21 | return res.status(400).json({ message: utils_1.ErrorMessage.PRODUCT_ALREADY_EXIST });
22 | }
23 | const imageUrl = yield uploadImage(req.file);
24 | const newFood = new models_1.FoodModel({ name, description, price, category, discount, starRating, ingredients, image: imageUrl });
25 | yield newFood.save();
26 | res.status(utils_1.HttpStatusCode.OK).json({ message: `${newFood.name} added Successfully` });
27 | }));
28 | /* all product list */
29 | exports.GetAllProducts = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
30 | const foods = yield models_1.FoodModel.find({});
31 | if (foods.length === 0) {
32 | return res.status(utils_1.HttpStatusCode.OK).json({ message: "Products have not been added yet" });
33 | }
34 | return res.status(utils_1.HttpStatusCode.OK).json(foods);
35 | }));
36 | /* search product */
37 | exports.SearchFood = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
38 | const searchRegex = new RegExp(req.params.searchTerm, 'i');
39 | const foodlist = yield models_1.FoodModel.find({ name: { $regex: searchRegex } });
40 | return res.status(utils_1.HttpStatusCode.OK).json(foodlist);
41 | }));
42 | /* veg food product */
43 | exports.GetVegFoods = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
44 | const vegfoods = yield models_1.FoodModel.find({ vegetarian: true }).limit(8);
45 | return res.status(utils_1.HttpStatusCode.OK).json(vegfoods);
46 | }));
47 | /* non veg product */
48 | exports.GetNonVegFoods = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
49 | const Nonvegfoods = yield models_1.FoodModel.find({ vegetarian: false }).limit(8);
50 | return res.status(utils_1.HttpStatusCode.OK).json(Nonvegfoods);
51 | }));
52 | /* recently added */
53 | exports.GetRecentlyAdded = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
54 | const foods = yield models_1.FoodModel.find({}).sort({ createdAt: -1 }).limit(8);
55 | return res.status(utils_1.HttpStatusCode.OK).json(foods);
56 | }));
57 | const uploadImage = (file) => __awaiter(void 0, void 0, void 0, function* () {
58 | const image = file;
59 | const base64Image = Buffer.from(image.buffer).toString("base64");
60 | const dataUri = `data:${image.mimetype};base64,${base64Image}`;
61 | const uploadResponse = yield cloudinary_1.v2.uploader.upload(dataUri, { folder: 'foodZone' });
62 | return uploadResponse.url;
63 | });
64 |
--------------------------------------------------------------------------------
/client/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/dist/controllers/admin.controller.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.BlockUnBlockUser = exports.DeleteUser = exports.DeleteProduct = exports.EnableDisableProduct = exports.VerifyAdmin = exports.GetAllProductsList = exports.GetAllCustomersList = void 0;
13 | const models_1 = require("../models");
14 | const utils_1 = require("../utils");
15 | const cloudinary_1 = require("cloudinary");
16 | exports.GetAllCustomersList = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
17 | const users = yield models_1.UserModel.find();
18 | return res.status(200).json(users);
19 | }));
20 | exports.GetAllProductsList = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
21 | const products = yield models_1.FoodModel.find();
22 | return res.status(200).json(products);
23 | }));
24 | exports.VerifyAdmin = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
25 | res.status(200).send({ userId: req.userId });
26 | }));
27 | exports.EnableDisableProduct = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
28 | const { productId } = req.params;
29 | const product = yield models_1.FoodModel.findById(productId);
30 | if (!product) {
31 | return res.status(400).json({ message: utils_1.ErrorMessage.PRODUCT_NOT_FOUND });
32 | }
33 | if (product.available === true) {
34 | yield models_1.FoodModel.findByIdAndUpdate(productId, {
35 | available: false,
36 | });
37 | return res.status(200).json({ message: "Product disabled" });
38 | }
39 | else {
40 | yield models_1.FoodModel.findByIdAndUpdate(productId, {
41 | available: true,
42 | });
43 | return res.status(200).json({ message: "Product enabled" });
44 | }
45 | }));
46 | exports.DeleteProduct = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
47 | var _a;
48 | const { productId } = req.params;
49 | const product = yield models_1.FoodModel.findById(productId);
50 | if (!product) {
51 | return res.status(400).json({ message: utils_1.ErrorMessage.PRODUCT_NOT_FOUND });
52 | }
53 | if (product.image) {
54 | const imageId = (_a = product.image.split("/").pop()) === null || _a === void 0 ? void 0 : _a.split(".")[0];
55 | yield cloudinary_1.v2.uploader.destroy(imageId);
56 | }
57 | yield models_1.FoodModel.findByIdAndDelete(productId);
58 | return res.status(200).json({ message: "Product deleted" });
59 | }));
60 | exports.DeleteUser = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
61 | const { userId } = req.params;
62 | const user = yield models_1.UserModel.findByIdAndDelete(userId);
63 | return res.status(200).json({ message: "Product deleted" });
64 | }));
65 | exports.BlockUnBlockUser = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
66 | const { userId } = req.params;
67 | const user = yield models_1.UserModel.findById(userId);
68 | if (!user) {
69 | return res.status(400).json({ message: utils_1.ErrorMessage.USER_NOT_FOUND });
70 | }
71 | if (user.blocked === true) {
72 | yield models_1.UserModel.findByIdAndUpdate(userId, {
73 | blocked: false,
74 | });
75 | return res.status(200).json({ message: "User Blocked" });
76 | }
77 | else {
78 | yield models_1.UserModel.findByIdAndUpdate(userId, {
79 | blocked: true,
80 | });
81 | return res.status(200).json({ message: "User UnBlocked" });
82 | }
83 | }));
84 |
--------------------------------------------------------------------------------
/client/src/components/ui/dialog.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as DialogPrimitive from "@radix-ui/react-dialog"
3 | import { Cross2Icon } from "@radix-ui/react-icons"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const Dialog = DialogPrimitive.Root
8 |
9 | const DialogTrigger = DialogPrimitive.Trigger
10 |
11 | const DialogPortal = DialogPrimitive.Portal
12 |
13 | const DialogClose = DialogPrimitive.Close
14 |
15 | const DialogOverlay = React.forwardRef<
16 | React.ElementRef,
17 | React.ComponentPropsWithoutRef
18 | >(({ className, ...props }, ref) => (
19 |
27 | ))
28 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
29 |
30 | const DialogContent = React.forwardRef<
31 | React.ElementRef,
32 | React.ComponentPropsWithoutRef
33 | >(({ className, children, ...props }, ref) => (
34 |
35 |
36 |
44 | {children}
45 |
46 |
47 | Close
48 |
49 |
50 |
51 | ))
52 | DialogContent.displayName = DialogPrimitive.Content.displayName
53 |
54 | const DialogHeader = ({
55 | className,
56 | ...props
57 | }: React.HTMLAttributes) => (
58 |
65 | )
66 | DialogHeader.displayName = "DialogHeader"
67 |
68 | const DialogFooter = ({
69 | className,
70 | ...props
71 | }: React.HTMLAttributes) => (
72 |
79 | )
80 | DialogFooter.displayName = "DialogFooter"
81 |
82 | const DialogTitle = React.forwardRef<
83 | React.ElementRef,
84 | React.ComponentPropsWithoutRef
85 | >(({ className, ...props }, ref) => (
86 |
94 | ))
95 | DialogTitle.displayName = DialogPrimitive.Title.displayName
96 |
97 | const DialogDescription = React.forwardRef<
98 | React.ElementRef,
99 | React.ComponentPropsWithoutRef
100 | >(({ className, ...props }, ref) => (
101 |
106 | ))
107 | DialogDescription.displayName = DialogPrimitive.Description.displayName
108 |
109 | export {
110 | Dialog,
111 | DialogPortal,
112 | DialogOverlay,
113 | DialogTrigger,
114 | DialogClose,
115 | DialogContent,
116 | DialogHeader,
117 | DialogFooter,
118 | DialogTitle,
119 | DialogDescription,
120 | }
121 |
--------------------------------------------------------------------------------
/client/src/components/ui/sheet.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as SheetPrimitive from "@radix-ui/react-dialog"
3 | import { Cross2Icon } from "@radix-ui/react-icons"
4 | import { cva, type VariantProps } from "class-variance-authority"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Sheet = SheetPrimitive.Root
9 |
10 | const SheetTrigger = SheetPrimitive.Trigger
11 |
12 | const SheetClose = SheetPrimitive.Close
13 |
14 | const SheetPortal = SheetPrimitive.Portal
15 |
16 | const SheetOverlay = React.forwardRef<
17 | React.ElementRef,
18 | React.ComponentPropsWithoutRef
19 | >(({ className, ...props }, ref) => (
20 |
28 | ))
29 | SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
30 |
31 | const sheetVariants = cva(
32 | "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
33 | {
34 | variants: {
35 | side: {
36 | top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
37 | bottom:
38 | "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
39 | left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
40 | right:
41 | "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
42 | },
43 | },
44 | defaultVariants: {
45 | side: "right",
46 | },
47 | }
48 | )
49 |
50 | interface SheetContentProps
51 | extends React.ComponentPropsWithoutRef,
52 | VariantProps {}
53 |
54 | const SheetContent = React.forwardRef<
55 | React.ElementRef,
56 | SheetContentProps
57 | >(({ side = "right", className, children, ...props }, ref) => (
58 |
59 |
60 |
65 | {children}
66 |
67 |
68 | Close
69 |
70 |
71 |
72 | ))
73 | SheetContent.displayName = SheetPrimitive.Content.displayName
74 |
75 | const SheetHeader = ({
76 | className,
77 | ...props
78 | }: React.HTMLAttributes) => (
79 |
86 | )
87 | SheetHeader.displayName = "SheetHeader"
88 |
89 | const SheetFooter = ({
90 | className,
91 | ...props
92 | }: React.HTMLAttributes) => (
93 |
100 | )
101 | SheetFooter.displayName = "SheetFooter"
102 |
103 | const SheetTitle = React.forwardRef<
104 | React.ElementRef,
105 | React.ComponentPropsWithoutRef
106 | >(({ className, ...props }, ref) => (
107 |
112 | ))
113 | SheetTitle.displayName = SheetPrimitive.Title.displayName
114 |
115 | const SheetDescription = React.forwardRef<
116 | React.ElementRef,
117 | React.ComponentPropsWithoutRef
118 | >(({ className, ...props }, ref) => (
119 |
124 | ))
125 | SheetDescription.displayName = SheetPrimitive.Description.displayName
126 |
127 | export {
128 | Sheet,
129 | SheetPortal,
130 | SheetOverlay,
131 | SheetTrigger,
132 | SheetClose,
133 | SheetContent,
134 | SheetHeader,
135 | SheetFooter,
136 | SheetTitle,
137 | SheetDescription,
138 | }
139 |
--------------------------------------------------------------------------------
/client/src/components/ui/form.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as LabelPrimitive from "@radix-ui/react-label"
3 | import { Slot } from "@radix-ui/react-slot"
4 | import {
5 | Controller,
6 | ControllerProps,
7 | FieldPath,
8 | FieldValues,
9 | FormProvider,
10 | useFormContext,
11 | } from "react-hook-form"
12 |
13 | import { cn } from "@/lib/utils"
14 | import { Label } from "@/components/ui/label"
15 |
16 | const Form = FormProvider
17 |
18 | type FormFieldContextValue<
19 | TFieldValues extends FieldValues = FieldValues,
20 | TName extends FieldPath = FieldPath
21 | > = {
22 | name: TName
23 | }
24 |
25 | const FormFieldContext = React.createContext(
26 | {} as FormFieldContextValue
27 | )
28 |
29 | const FormField = <
30 | TFieldValues extends FieldValues = FieldValues,
31 | TName extends FieldPath = FieldPath
32 | >({
33 | ...props
34 | }: ControllerProps) => {
35 | return (
36 |
37 |
38 |
39 | )
40 | }
41 |
42 | const useFormField = () => {
43 | const fieldContext = React.useContext(FormFieldContext)
44 | const itemContext = React.useContext(FormItemContext)
45 | const { getFieldState, formState } = useFormContext()
46 |
47 | const fieldState = getFieldState(fieldContext.name, formState)
48 |
49 | if (!fieldContext) {
50 | throw new Error("useFormField should be used within ")
51 | }
52 |
53 | const { id } = itemContext
54 |
55 | return {
56 | id,
57 | name: fieldContext.name,
58 | formItemId: `${id}-form-item`,
59 | formDescriptionId: `${id}-form-item-description`,
60 | formMessageId: `${id}-form-item-message`,
61 | ...fieldState,
62 | }
63 | }
64 |
65 | type FormItemContextValue = {
66 | id: string
67 | }
68 |
69 | const FormItemContext = React.createContext(
70 | {} as FormItemContextValue
71 | )
72 |
73 | const FormItem = React.forwardRef<
74 | HTMLDivElement,
75 | React.HTMLAttributes
76 | >(({ className, ...props }, ref) => {
77 | const id = React.useId()
78 |
79 | return (
80 |
81 |
82 |
83 | )
84 | })
85 | FormItem.displayName = "FormItem"
86 |
87 | const FormLabel = React.forwardRef<
88 | React.ElementRef,
89 | React.ComponentPropsWithoutRef
90 | >(({ className, ...props }, ref) => {
91 | const { error, formItemId } = useFormField()
92 |
93 | return (
94 |
100 | )
101 | })
102 | FormLabel.displayName = "FormLabel"
103 |
104 | const FormControl = React.forwardRef<
105 | React.ElementRef,
106 | React.ComponentPropsWithoutRef
107 | >(({ ...props }, ref) => {
108 | const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
109 |
110 | return (
111 |
122 | )
123 | })
124 | FormControl.displayName = "FormControl"
125 |
126 | const FormDescription = React.forwardRef<
127 | HTMLParagraphElement,
128 | React.HTMLAttributes
129 | >(({ className, ...props }, ref) => {
130 | const { formDescriptionId } = useFormField()
131 |
132 | return (
133 |
139 | )
140 | })
141 | FormDescription.displayName = "FormDescription"
142 |
143 | const FormMessage = React.forwardRef<
144 | HTMLParagraphElement,
145 | React.HTMLAttributes
146 | >(({ className, children, ...props }, ref) => {
147 | const { error, formMessageId } = useFormField()
148 | const body = error ? String(error?.message) : children
149 |
150 | if (!body) {
151 | return null
152 | }
153 |
154 | return (
155 |
161 | {body}
162 |
163 | )
164 | })
165 | FormMessage.displayName = "FormMessage"
166 |
167 | export {
168 | useFormField,
169 | Form,
170 | FormItem,
171 | FormLabel,
172 | FormControl,
173 | FormDescription,
174 | FormMessage,
175 | FormField,
176 | }
177 |
--------------------------------------------------------------------------------
/server/dist/controllers/cart.controller.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.UpdateCartItem = exports.RemoveFromCart = exports.CreateUserCart = exports.GetAllCartItems = void 0;
13 | const helper_1 = require("./../utils/helper");
14 | const models_1 = require("../models");
15 | const utils_1 = require("../utils");
16 | exports.GetAllCartItems = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
17 | const cart = yield models_1.CartModel.findOne({ orderBy: req.userId }).populate("products.product");
18 | res.status(utils_1.HttpStatusCode.OK).json(cart);
19 | }));
20 | exports.CreateUserCart = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
21 | const { productId, count } = req.body;
22 | const product = yield models_1.FoodModel.findById(productId);
23 | if (!product) {
24 | return res.status(utils_1.HttpStatusCode.BAD_REQUEST).json({ message: helper_1.ErrorMessage.PRODUCT_NOT_FOUND });
25 | }
26 | const cart = yield models_1.CartModel.findOne({ orderBy: req.userId });
27 | if (!cart) {
28 | let total = 0;
29 | total = total + product.price * count;
30 | const newCart = yield models_1.CartModel.create({
31 | orderBy: req.userId,
32 | products: [{ product: productId, count, price: product.price }],
33 | cartTotal: total,
34 | });
35 | return res.status(utils_1.HttpStatusCode.CREATED).json(newCart);
36 | }
37 | const index = cart.products.findIndex((p) => { var _a; return ((_a = p === null || p === void 0 ? void 0 : p.product) === null || _a === void 0 ? void 0 : _a.toString()) === productId; });
38 | if (index > -1) {
39 | cart.products[index].count += count;
40 | cart.cartTotal += product.price * count;
41 | }
42 | else {
43 | cart.products.push({
44 | product: productId,
45 | count,
46 | price: product.price,
47 | });
48 | cart.cartTotal += product.price * count;
49 | }
50 | yield cart.save();
51 | res.json({ message: helper_1.SuccessMessage.PRODUCT_ADDED_SUCCESSFULLY });
52 | }));
53 | exports.RemoveFromCart = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
54 | const { productId } = req.params;
55 | const product = yield models_1.FoodModel.findById(productId);
56 | if (!product) {
57 | return res.status(utils_1.HttpStatusCode.BAD_REQUEST).json({ message: helper_1.ErrorMessage.PRODUCT_NOT_FOUND });
58 | }
59 | let cart = yield models_1.CartModel.findOne({ orderBy: req.userId });
60 | if (!cart) {
61 | return res.json({ message: helper_1.ErrorMessage.PRODUCT_NOT_FOUND });
62 | }
63 | const index = cart.products.findIndex((p) => { var _a; return ((_a = p === null || p === void 0 ? void 0 : p.product) === null || _a === void 0 ? void 0 : _a.toString()) === productId; });
64 | if (index !== -1) {
65 | cart.products.splice(index, 1);
66 | cart.cartTotal -= product.price;
67 | yield cart.save();
68 | res.status(utils_1.HttpStatusCode.OK).json({ message: helper_1.SuccessMessage.PRODUCT_DELETED_SUCCESSFULLY });
69 | }
70 | }));
71 | exports.UpdateCartItem = (0, utils_1.AsyncWrapper)((req, res) => __awaiter(void 0, void 0, void 0, function* () {
72 | const { productId } = req.params;
73 | const { count } = req.body;
74 | const product = yield models_1.FoodModel.findById(productId);
75 | if (!product) {
76 | return res.status(utils_1.HttpStatusCode.BAD_REQUEST).json({ message: helper_1.ErrorMessage.PRODUCT_NOT_FOUND });
77 | }
78 | if (count <= 0) {
79 | return res.status(utils_1.HttpStatusCode.BAD_REQUEST).json({ message: helper_1.ErrorMessage.PRODUCT_COUNT });
80 | }
81 | const cart = yield models_1.CartModel.findOne({ orderBy: req.userId });
82 | if (cart) {
83 | const item = cart.products.find((p) => { var _a; return ((_a = p === null || p === void 0 ? void 0 : p.product) === null || _a === void 0 ? void 0 : _a.toString()) === productId; });
84 | if (item) {
85 | const oldPrice = item.price;
86 | item.count = count;
87 | item.price = product.price * count;
88 | cart.cartTotal = cart.cartTotal - oldPrice + item.price;
89 | yield cart.save();
90 | res.status(utils_1.HttpStatusCode.OK).json({ message: helper_1.SuccessMessage.PRODUCT_UPDATED_SUCCESSFULLY });
91 | }
92 | }
93 | }));
94 |
--------------------------------------------------------------------------------
|