From 0a6668e20848e50da94826029a6215eb93b5d1b0 Mon Sep 17 00:00:00 2001 From: ola Date: Wed, 26 Jul 2023 18:27:49 +0800 Subject: [PATCH 01/19] implement the menu search --- frontend/src/apis/menusApi.tsx | 10 --- frontend/src/components/Cart/ShoppingCart.tsx | 2 +- frontend/src/components/Forms/search.tsx | 75 +++++++++++++++++++ frontend/src/components/Menu/MenuList.tsx | 1 + frontend/src/pages/Home.tsx | 14 +++- 5 files changed, 89 insertions(+), 13 deletions(-) create mode 100644 frontend/src/components/Forms/search.tsx diff --git a/frontend/src/apis/menusApi.tsx b/frontend/src/apis/menusApi.tsx index 13681c2b..4036e200 100644 --- a/frontend/src/apis/menusApi.tsx +++ b/frontend/src/apis/menusApi.tsx @@ -3,16 +3,6 @@ import { ICreateMenu } from "../interfaces/menu.interface"; import { QueryObserverResult, useQuery } from "react-query"; import { menuApi } from "./axios"; -export const getMenus = async (): Promise => { - const response = await menuApi.get("/menus/merchant/63d792433b857e1697fe7017", { - headers: { - "Content-Type": "application/json", - "x-correlation-id": "55a30d65-f523-45b2-9ecb-de4290cf432a", - }, - }); - return response.data; -}; - export const addMenu = async (menu: ICreateMenu): Promise => { const response = await menuApi.post("/menus", menu); return response.data; diff --git a/frontend/src/components/Cart/ShoppingCart.tsx b/frontend/src/components/Cart/ShoppingCart.tsx index a772cb90..3f10c56b 100644 --- a/frontend/src/components/Cart/ShoppingCart.tsx +++ b/frontend/src/components/Cart/ShoppingCart.tsx @@ -10,7 +10,7 @@ export const ShoppingCart = ({ isOpen }: shoppingCartAction) => { const { closeCart } = useShoppingCart(); const header = "ORDER SUMMARY"; return ( - + ); diff --git a/frontend/src/components/Forms/search.tsx b/frontend/src/components/Forms/search.tsx new file mode 100644 index 00000000..6bee6ef0 --- /dev/null +++ b/frontend/src/components/Forms/search.tsx @@ -0,0 +1,75 @@ +import { ChangeEvent, useState } from "react"; +import { Card, CardGroup, Form } from "react-bootstrap"; +import { OffcanvasPlacement } from "react-bootstrap/esm/Offcanvas"; +import { useQuery } from "react-query"; +import { Link } from "react-router-dom"; +import { axiosPrivate } from "../../apis/axios"; +import { IMenus } from "../../models/menu.model"; +import { OffCanvas } from "../Utilities/OffCanvas"; + +type menuSearchAction = { + isOpen: boolean; + closeCart: () => void; + placement: OffcanvasPlacement; + header: string; +}; + +export const MenuSearch = ({ isOpen, closeCart, header, placement }: menuSearchAction) => { + const [searchTerm, setSearchTerm] = useState(""); + const handleSearch = (event: ChangeEvent) => { + setSearchTerm(event.target.value); + }; + const getMenus = async (): Promise => { + //remove the add coded value and make it dynamic + const response = await axiosPrivate.get("/menus/merchant/63d792433b857e1697fe7017"); + return response.data; + }; + + const { + isLoading, + isError, + error, + data: menus, + } = useQuery("menus", getMenus, { staleTime: 3600000, cacheTime: 3600000 }); + + const filteredMenus = menus?.data.filter((menu) => { + return menu.name?.toLowerCase().includes(searchTerm.toLowerCase()); + }); + + return ( + +
+
+ + +
+
+ + {filteredMenus?.map((menu) => ( + +
+ + + +

{menu.name}

+
+ +
+
+ ))} +
+
+
+ ); +}; diff --git a/frontend/src/components/Menu/MenuList.tsx b/frontend/src/components/Menu/MenuList.tsx index 583bb10b..0e335df9 100644 --- a/frontend/src/components/Menu/MenuList.tsx +++ b/frontend/src/components/Menu/MenuList.tsx @@ -9,6 +9,7 @@ export const MenuList = () => { const axiosPrivate = useAxiosPrivate(); const getMenus = async (): Promise => { + //remove the add coded value and make it dynamic const response = await axiosPrivate.get("/menus/merchant/63d792433b857e1697fe7017"); return response.data; }; diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index 59e1c080..256a14fa 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,18 +1,28 @@ import { Form } from "react-bootstrap"; import { MenuList } from "../components/Menu/MenuList"; import { AddonScrollBar } from "../components/Utilities/AddonScrollBar"; +import { useState } from "react"; +import { MenuSearch } from "../components/Forms/search"; export const Home = () => { + const [isOpen, setIsOpen] = useState(false); + const openCart = () => { + setIsOpen(true); + }; + const closeCart = () => { + setIsOpen(false); + }; + return (
- +
- +
); }; From ff364d1454f959b1943018441d58e4cfd967d4b3 Mon Sep 17 00:00:00 2001 From: ola Date: Wed, 26 Jul 2023 18:28:22 +0800 Subject: [PATCH 02/19] fix code smell --- frontend/src/components/MenuItems/StoreItem.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/MenuItems/StoreItem.tsx b/frontend/src/components/MenuItems/StoreItem.tsx index 99cf938a..30d16500 100644 --- a/frontend/src/components/MenuItems/StoreItem.tsx +++ b/frontend/src/components/MenuItems/StoreItem.tsx @@ -1,4 +1,3 @@ -import { useState } from "react"; import { Card, Col, Row } from "react-bootstrap"; import { Item } from "../../reducers"; import { wordWrap } from "../../utility/utils"; From 65b60092f6181849a430319e793a69c6b80e0176 Mon Sep 17 00:00:00 2001 From: ola Date: Mon, 11 Sep 2023 09:12:14 +0800 Subject: [PATCH 03/19] calculate service charge --- .../src/components/Cart/ShoppinCartDetails.tsx | 18 ++++++++++++------ .../src/components/Utilities/Conditional.tsx | 2 +- frontend/src/utility/utils.ts | 4 ++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/Cart/ShoppinCartDetails.tsx b/frontend/src/components/Cart/ShoppinCartDetails.tsx index 887a7c57..8d8e6b1c 100644 --- a/frontend/src/components/Cart/ShoppinCartDetails.tsx +++ b/frontend/src/components/Cart/ShoppinCartDetails.tsx @@ -5,7 +5,7 @@ import { useNavigate } from "react-router-dom"; import { CONSTANTS } from "../../constants/constant"; import { useShoppingCart } from "../../hooks/UseShoppingCart"; import { OrderSummary } from "../../reducers"; -import { calculateTotalOrderAmount, setLocalStorageData, wordWrap } from "../../utility/utils"; +import { calculateServiceCharge, calculateTotalOrderAmount, setLocalStorageData, wordWrap } from "../../utility/utils"; import { QtyButton } from "../MenuItems/addItemButton"; import { CallToAction } from "../Utilities/modal"; import { CartSelectedItems } from "./CartSelectedItems"; @@ -121,7 +121,7 @@ export const ShoppingCartDetails = () => { -

RM {summary.menus[0].menuTotalPrice!}

+

{summary.menus[0].menuTotalPrice!}

@@ -171,10 +171,16 @@ export const ShoppingCartDetails = () => { )}
- -
Total
-
-

RM {handleCalculateTotalOrder()}

+ + Subtotal +
+

{handleCalculateTotalOrder()}

+
+
+ + Service Charge +
+

{calculateServiceCharge(calculateTotalOrderAmount())}

From d2dfe38fb78e4646b49a8cb0d1efaaae371c1cdc Mon Sep 17 00:00:00 2001 From: ola Date: Mon, 11 Sep 2023 09:53:20 +0800 Subject: [PATCH 06/19] add cart items to order --- .../models/cart-item-data.model.ts | 1 - .../models/order-model.interface.ts | 2 ++ .../repositories/schemas/order.schema.ts | 5 +++++ .../schemas/selected-cart-item.schema.ts | 3 ++- backend/src/order/order-entity.interface.ts | 10 ++-------- backend/src/order/order.mapper.ts | 20 +++++++++++++++---- backend/src/order/order.ts | 13 +++++++++++- 7 files changed, 39 insertions(+), 15 deletions(-) diff --git a/backend/src/infrastructure/data_access/repositories/models/cart-item-data.model.ts b/backend/src/infrastructure/data_access/repositories/models/cart-item-data.model.ts index f3aad418..c33bdf81 100644 --- a/backend/src/infrastructure/data_access/repositories/models/cart-item-data.model.ts +++ b/backend/src/infrastructure/data_access/repositories/models/cart-item-data.model.ts @@ -1,5 +1,4 @@ import { Types } from 'mongoose'; -import { ISelectedCartItem } from 'src/cart/selectedItems/selected-cart-items-entity.interface'; import { SelectedCartItemDataModel } from '../schemas/selected-cart-item.schema'; export interface ICartItemModel { diff --git a/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts b/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts index bb02b67b..6803c165 100644 --- a/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts +++ b/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts @@ -1,5 +1,6 @@ import { Types } from 'mongoose'; import { currentStatus, dinningType } from 'src/order/order-entity.interface'; +import { CartItemDataModel } from '../schemas/cartItem.schema'; export interface IOrderDataModel { readonly state: currentStatus; @@ -10,4 +11,5 @@ export interface IOrderDataModel { readonly quantity: number; readonly discount?: number; readonly orderManagerId?: Types.ObjectId; + readonly cartItems: CartItemDataModel[]; } diff --git a/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts index a66899dc..702af263 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts @@ -6,6 +6,7 @@ import { IOrderDataModel } from '../models/order-model.interface'; import { currentStatus, dinningType } from './../../../../order/order-entity.interface'; import { MerchantDataModel } from './merchant.schema'; import { OrderManagerDataModel } from './order-manger.schema'; +import { CartItemDataModel } from './cartItem.schema'; export type OrderDocument = OrderDataModel & Document; @@ -33,6 +34,10 @@ export class OrderDataModel extends BaseDocument implements IOrderDataModel { @Prop({ type: Number, required: true }) quantity: number; + + @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: CartItemDataModel }] }) + @Type(() => CartItemDataModel) + cartItems: CartItemDataModel[]; } export const OrderSchema = SchemaFactory.createForClass(OrderDataModel); diff --git a/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts index f24a9527..be0f488f 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts @@ -4,6 +4,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import mongoose, { Types } from 'mongoose'; import { Type } from 'class-transformer'; import { MenuDataModel } from './menu.schema'; +import { CartItemDataModel } from './cartItem.schema'; export type SelectedCartItemDocument = SelectedCartItemDataModel & Document; @@ -14,7 +15,7 @@ export class SelectedCartItemDataModel extends BaseDocument implements ISelected menuId: Types.ObjectId; @Prop({ type: mongoose.Schema.Types.ObjectId }) - @Type(() => MenuDataModel) + @Type(() => CartItemDataModel) itemId: Types.ObjectId; @Prop({ type: Number, required: true }) diff --git a/backend/src/order/order-entity.interface.ts b/backend/src/order/order-entity.interface.ts index 137f37dc..63478088 100644 --- a/backend/src/order/order-entity.interface.ts +++ b/backend/src/order/order-entity.interface.ts @@ -1,17 +1,10 @@ import { Types } from 'mongoose'; +import { CartItem } from 'src/cart/cart-item'; import { Audit } from 'src/domain'; export type currentStatus = 'CREATED' | 'ACCEPTED' | 'DENIED' | 'FINISHED' | 'CANCELLED'; export type dinningType = 'PICK_UP' | 'DINE_IN' | 'DELIVERY'; -export enum orderStatus { - 'CREATED', - 'ACCEPTED', - 'DENIED', - 'FINISHED', - 'CANCELLED', -} - export interface IOrder { state: currentStatus; type: dinningType; @@ -22,4 +15,5 @@ export interface IOrder { discount?: number; orderManagerId?: Types.ObjectId; audit: Audit; + cartItems: CartItem[]; } diff --git a/backend/src/order/order.mapper.ts b/backend/src/order/order.mapper.ts index d24173f8..5c0c8e8b 100644 --- a/backend/src/order/order.mapper.ts +++ b/backend/src/order/order.mapper.ts @@ -1,3 +1,4 @@ +import { CartItemMapper } from './../cart/cart-item.mapper'; import { Injectable } from '@nestjs/common'; import { IMapper } from 'src/domain'; import { OrderDataModel } from 'src/infrastructure/data_access/repositories/schemas/order.schema'; @@ -6,9 +7,9 @@ import { AuditMapper } from 'src/audit'; @Injectable() export class OrderMapper implements IMapper { - constructor(private readonly auditMapper: AuditMapper) {} + constructor(private readonly auditMapper: AuditMapper, private readonly cartItemMapper: CartItemMapper) {} toPersistence(entity: Order): OrderDataModel { - const { id, state, type, merchantId, total, quantity, discount, orderManagerId, audit } = entity; + const { id, state, type, merchantId, total, quantity, discount, orderManagerId, audit, cartItems } = entity; const { auditCreatedBy, auditCreatedDateTime, @@ -25,6 +26,7 @@ export class OrderMapper implements IMapper { total, quantity, discount, + cartItems: cartItems.map((cartItem) => this.cartItemMapper.toPersistence(cartItem)), orderManagerId, auditCreatedBy, auditCreatedDateTime, @@ -37,9 +39,19 @@ export class OrderMapper implements IMapper { } toDomain(model: OrderDataModel): Order { - const { state, type, merchantId, total, quantity, discount, orderManagerId, _id } = model; + const { state, type, merchantId, total, quantity, discount, orderManagerId, _id, cartItems } = model; const entity: Order = Order.create( - { state, type, merchantId, total, quantity, discount, orderManagerId, audit: this.auditMapper.toDomain(model) }, + { + state, + type, + merchantId, + total, + quantity, + discount, + orderManagerId, + audit: this.auditMapper.toDomain(model), + cartItems: cartItems.map((cartItem) => this.cartItemMapper.toDomain(cartItem)), + }, _id, ).getValue(); return entity; diff --git a/backend/src/order/order.ts b/backend/src/order/order.ts index 50e26f4f..1dce9908 100644 --- a/backend/src/order/order.ts +++ b/backend/src/order/order.ts @@ -2,6 +2,7 @@ import { Audit } from './../domain/audit/audit'; import { Entity, Result } from 'src/domain'; import { IOrder, currentStatus, dinningType } from './order-entity.interface'; import { Types } from 'mongoose'; +import { CartItem } from 'src/cart/cart-item'; export class Order extends Entity implements IOrder { _state: currentStatus; @@ -13,10 +14,11 @@ export class Order extends Entity implements IOrder { _discount?: number; _orderManagerId: Types.ObjectId; _audit: Audit; + _cartItems: CartItem[]; constructor( id: Types.ObjectId, - { state, type, merchantId, customerId, total, quantity, discount, orderManagerId, audit }: IOrder, + { state, type, merchantId, customerId, total, quantity, discount, orderManagerId, audit, cartItems }: IOrder, ) { super(id); this._state = state; @@ -28,6 +30,7 @@ export class Order extends Entity implements IOrder { this._discount = discount; this._orderManagerId = orderManagerId; this._audit = audit; + this._cartItems = cartItems; } get state(): currentStatus { @@ -102,6 +105,14 @@ export class Order extends Entity implements IOrder { this._audit = audit; } + get cartItems() { + return this._cartItems; + } + + set cartItems(cartItems: CartItem[]) { + this._cartItems = cartItems; + } + static create(props: IOrder, id?: Types.ObjectId) { return Result.ok(new Order(id, props)); } From 541a0a3dad76606a04a0fd94f0ebd4dd76331234 Mon Sep 17 00:00:00 2001 From: ola Date: Mon, 11 Sep 2023 10:41:55 +0800 Subject: [PATCH 07/19] move email header check to the backend --- backend/.env | 1 + backend/src/application/constants/types.ts | 1 + .../infrastructure/middlewares/context.middleware.ts | 11 +++++++---- backend/src/menu/menu.service.ts | 4 ++-- backend/src/order/order.service.ts | 7 +++++++ 5 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 backend/src/order/order.service.ts diff --git a/backend/.env b/backend/.env index 7cb1c84d..613345f8 100644 --- a/backend/.env +++ b/backend/.env @@ -5,3 +5,4 @@ JWT_REFRESH_TOKEN_SECRET='few%i&o3298hin2p9#kn2u80@#$749' JWT_ACCESS_TOKEN_EXPIRATION_TIME=60m JWT_REFRESH_TOKEN_EXPIRATION_TIME=420m APPSESSION=RestaurantApp +GUEST_EMAIL=guest@application.com diff --git a/backend/src/application/constants/types.ts b/backend/src/application/constants/types.ts index 05100598..bb931544 100644 --- a/backend/src/application/constants/types.ts +++ b/backend/src/application/constants/types.ts @@ -20,4 +20,5 @@ export const TYPES = { IMenuRepository: Symbol('IMenuRepository'), IItemRepository: Symbol('IItemRepository'), IAddonRepository: Symbol('IAddonRepository'), + IOrderRepository: Symbol('IOrderRepository'), }; diff --git a/backend/src/infrastructure/middlewares/context.middleware.ts b/backend/src/infrastructure/middlewares/context.middleware.ts index 91bec8d8..16c06993 100644 --- a/backend/src/infrastructure/middlewares/context.middleware.ts +++ b/backend/src/infrastructure/middlewares/context.middleware.ts @@ -6,19 +6,21 @@ import { HttpStatus, Inject, Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; import { Context } from '../context/context'; import { throwApplicationError } from '../utilities/exception-instance'; +import { ConfigService } from '@nestjs/config'; @Injectable() export class ContextMiddleWare implements NestMiddleware { constructor( @Inject(TYPES.IContextService) private readonly contextService: IContextService, + private readonly configService: ConfigService, ) {} use(req: Request, res: Response, next: NextFunction) { const headers = req.headers; const errors = new Object() as any; - if (Object.hasOwnProperty.call(headers, APIResponseMessage.emailHeader) ?? 'guest@application.com') { - errors.email = APIResponseMessage.emailHeaderError; - } + // if (Object.hasOwnProperty.call(headers, APIResponseMessage.emailHeader)) { + // errors.email = APIResponseMessage.emailHeaderError; + // } if (!Object.hasOwnProperty.call(headers, APIResponseMessage.correlationIdHeader)) { errors.correlationId = APIResponseMessage.correlationIdHeaderError; } @@ -36,7 +38,8 @@ export class ContextMiddleWare implements NestMiddleware { throwApplicationError(HttpStatus.BAD_REQUEST, errors); } } - const email = req.headers[APIResponseMessage.emailHeader] as string; + const email = + (req.headers[APIResponseMessage.emailHeader] as string) ?? this.configService.get('GUEST_EMAIL'); const correlationId = req.headers[APIResponseMessage.correlationIdHeader] as string; const token = (req.headers[APIResponseMessage.authorizationHeader] as string) ?? ''; const role = (req.headers[APIResponseMessage.roleHeader] as string) ?? ''; diff --git a/backend/src/menu/menu.service.ts b/backend/src/menu/menu.service.ts index 744983cb..53290d25 100644 --- a/backend/src/menu/menu.service.ts +++ b/backend/src/menu/menu.service.ts @@ -122,10 +122,10 @@ export class MenuService implements IMenuService { async getMenuByRestaurantId(restaurantId: string): Promise> { const result = await this.menuRepository.getMenuByRestaurantId(restaurantId); - let menus: Menu[] | undefined; + let menus: Menu[] | []; if (result.getValue()) { menus = result.getValue(); } - return Result.ok(MenuParser.createMenusResponse(menus)); + return Result.ok(menus && menus.length ? MenuParser.createMenusResponse(menus) : []); } } diff --git a/backend/src/order/order.service.ts b/backend/src/order/order.service.ts new file mode 100644 index 00000000..e288f0b3 --- /dev/null +++ b/backend/src/order/order.service.ts @@ -0,0 +1,7 @@ +import { Inject } from '@nestjs/common'; +import { TYPES } from 'src/application'; +import { IOrderRepository } from 'src/infrastructure/data_access/repositories/interfaces/order-repository.interface'; + +export class OrderService { + constructor(@Inject(TYPES.IOrderRepository) private readonly orderRepository: IOrderRepository) {} +} From 55765a0a8604f362e204809ad5d45432589d5620 Mon Sep 17 00:00:00 2001 From: ola Date: Sun, 24 Sep 2023 07:06:15 +0800 Subject: [PATCH 08/19] remove quantity from order --- .../repositories/models/order-model.interface.ts | 1 - .../repositories/schemas/order.schema.ts | 3 --- backend/src/order/dto/create-order.dto.ts | 10 ++++++++++ backend/src/order/order-entity.interface.ts | 1 - backend/src/order/order-response.dto.ts | 1 - backend/src/order/order.controller.ts | 0 backend/src/order/order.mapper.ts | 6 ++---- backend/src/order/order.parser.ts | 3 +-- backend/src/order/order.service.ts | 14 ++++++++------ backend/src/order/order.ts | 12 +----------- 10 files changed, 22 insertions(+), 29 deletions(-) create mode 100644 backend/src/order/dto/create-order.dto.ts create mode 100644 backend/src/order/order.controller.ts diff --git a/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts b/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts index 6803c165..daafe39b 100644 --- a/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts +++ b/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts @@ -8,7 +8,6 @@ export interface IOrderDataModel { readonly merchantId: Types.ObjectId; readonly customerId?: Types.ObjectId; readonly total: number; - readonly quantity: number; readonly discount?: number; readonly orderManagerId?: Types.ObjectId; readonly cartItems: CartItemDataModel[]; diff --git a/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts index 702af263..306ee462 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts @@ -32,9 +32,6 @@ export class OrderDataModel extends BaseDocument implements IOrderDataModel { @Prop({ type: Number, required: true }) total: number; - @Prop({ type: Number, required: true }) - quantity: number; - @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: CartItemDataModel }] }) @Type(() => CartItemDataModel) cartItems: CartItemDataModel[]; diff --git a/backend/src/order/dto/create-order.dto.ts b/backend/src/order/dto/create-order.dto.ts new file mode 100644 index 00000000..661ce39a --- /dev/null +++ b/backend/src/order/dto/create-order.dto.ts @@ -0,0 +1,10 @@ +import { CartItemDataModel } from 'src/infrastructure/data_access/repositories/schemas/cartItem.schema'; + +export class CreateOrderDTO { + state: string; + type: string; + merchantId: string; + total: number; + quantity: number; + cartItems: CartItemDataModel[]; +} diff --git a/backend/src/order/order-entity.interface.ts b/backend/src/order/order-entity.interface.ts index 63478088..a2798ab6 100644 --- a/backend/src/order/order-entity.interface.ts +++ b/backend/src/order/order-entity.interface.ts @@ -11,7 +11,6 @@ export interface IOrder { merchantId: Types.ObjectId; customerId?: Types.ObjectId; total: number; - quantity: number; discount?: number; orderManagerId?: Types.ObjectId; audit: Audit; diff --git a/backend/src/order/order-response.dto.ts b/backend/src/order/order-response.dto.ts index 0dfc4846..dd1fce91 100644 --- a/backend/src/order/order-response.dto.ts +++ b/backend/src/order/order-response.dto.ts @@ -8,7 +8,6 @@ export interface IOrderResponseDTO extends IAudit { merchantId: Types.ObjectId; customerId?: Types.ObjectId; total: number; - quantity: number; discount?: number; orderManagerId?: Types.ObjectId; } diff --git a/backend/src/order/order.controller.ts b/backend/src/order/order.controller.ts new file mode 100644 index 00000000..e69de29b diff --git a/backend/src/order/order.mapper.ts b/backend/src/order/order.mapper.ts index 5c0c8e8b..15b9338d 100644 --- a/backend/src/order/order.mapper.ts +++ b/backend/src/order/order.mapper.ts @@ -9,7 +9,7 @@ import { AuditMapper } from 'src/audit'; export class OrderMapper implements IMapper { constructor(private readonly auditMapper: AuditMapper, private readonly cartItemMapper: CartItemMapper) {} toPersistence(entity: Order): OrderDataModel { - const { id, state, type, merchantId, total, quantity, discount, orderManagerId, audit, cartItems } = entity; + const { id, state, type, merchantId, total, discount, orderManagerId, audit, cartItems } = entity; const { auditCreatedBy, auditCreatedDateTime, @@ -24,7 +24,6 @@ export class OrderMapper implements IMapper { type, merchantId, total, - quantity, discount, cartItems: cartItems.map((cartItem) => this.cartItemMapper.toPersistence(cartItem)), orderManagerId, @@ -39,14 +38,13 @@ export class OrderMapper implements IMapper { } toDomain(model: OrderDataModel): Order { - const { state, type, merchantId, total, quantity, discount, orderManagerId, _id, cartItems } = model; + const { state, type, merchantId, total, discount, orderManagerId, _id, cartItems } = model; const entity: Order = Order.create( { state, type, merchantId, total, - quantity, discount, orderManagerId, audit: this.auditMapper.toDomain(model), diff --git a/backend/src/order/order.parser.ts b/backend/src/order/order.parser.ts index 12beb7c9..416876a6 100644 --- a/backend/src/order/order.parser.ts +++ b/backend/src/order/order.parser.ts @@ -4,7 +4,7 @@ import { IOrderResponseDTO } from './order-response.dto'; export class OrderParser { static createOrderResponse(order: Order): IOrderResponseDTO { - const { id, state, type, merchantId, customerId, total, quantity, discount, orderManagerId, audit } = order; + const { id, state, type, merchantId, customerId, total, discount, orderManagerId, audit } = order; return { id, state, @@ -12,7 +12,6 @@ export class OrderParser { merchantId, customerId, total, - quantity, discount, orderManagerId, ...AuditParser.createAuditResponse(audit), diff --git a/backend/src/order/order.service.ts b/backend/src/order/order.service.ts index e288f0b3..7f2a3724 100644 --- a/backend/src/order/order.service.ts +++ b/backend/src/order/order.service.ts @@ -1,7 +1,9 @@ -import { Inject } from '@nestjs/common'; -import { TYPES } from 'src/application'; -import { IOrderRepository } from 'src/infrastructure/data_access/repositories/interfaces/order-repository.interface'; +// import { Inject } from '@nestjs/common'; +// import { TYPES } from 'src/application'; +// import { IOrderRepository } from 'src/infrastructure/data_access/repositories/interfaces/order-repository.interface'; -export class OrderService { - constructor(@Inject(TYPES.IOrderRepository) private readonly orderRepository: IOrderRepository) {} -} +// export class OrderService { +// constructor(@Inject(TYPES.IOrderRepository) private readonly orderRepository: IOrderRepository) {} + +// createOrder(orderSummary: ){} +// } diff --git a/backend/src/order/order.ts b/backend/src/order/order.ts index 1dce9908..f4554bd6 100644 --- a/backend/src/order/order.ts +++ b/backend/src/order/order.ts @@ -10,7 +10,6 @@ export class Order extends Entity implements IOrder { _merchantId: Types.ObjectId; _customerId?: Types.ObjectId; _total: number; - _quantity: number; _discount?: number; _orderManagerId: Types.ObjectId; _audit: Audit; @@ -18,7 +17,7 @@ export class Order extends Entity implements IOrder { constructor( id: Types.ObjectId, - { state, type, merchantId, customerId, total, quantity, discount, orderManagerId, audit, cartItems }: IOrder, + { state, type, merchantId, customerId, total, discount, orderManagerId, audit, cartItems }: IOrder, ) { super(id); this._state = state; @@ -26,7 +25,6 @@ export class Order extends Entity implements IOrder { this._merchantId = merchantId; this._customerId = customerId; this._total = total; - this._quantity = quantity; this._discount = discount; this._orderManagerId = orderManagerId; this._audit = audit; @@ -73,14 +71,6 @@ export class Order extends Entity implements IOrder { this._total = total; } - get quantity(): number { - return this._quantity; - } - - set quantity(quantity: number) { - this._quantity = quantity; - } - get discount(): number { return this._discount; } From f0dfa7b99aa06f9a71a4c198df9934bc53b82d72 Mon Sep 17 00:00:00 2001 From: ola Date: Sun, 24 Sep 2023 07:46:40 +0800 Subject: [PATCH 09/19] update selected items to include itemId --- .../selectedItems/selected-cart-item.mapper.ts | 8 ++++---- .../selected-cart-items-entity.interface.ts | 2 +- backend/src/cart/selectedItems/selectedCartItem.ts | 12 ++++++------ .../models/selected-item-model.interface.ts | 3 +-- .../schemas/selected-cart-item.schema.ts | 14 +++++++------- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/backend/src/cart/selectedItems/selected-cart-item.mapper.ts b/backend/src/cart/selectedItems/selected-cart-item.mapper.ts index 20b19ab4..7cb2b743 100644 --- a/backend/src/cart/selectedItems/selected-cart-item.mapper.ts +++ b/backend/src/cart/selectedItems/selected-cart-item.mapper.ts @@ -6,7 +6,7 @@ import { SelectedCartItem } from './selectedCartItem'; export class SelectedCartItemMapper implements IMapper { constructor(private readonly auditMapper: AuditMapper) {} toPersistence(entity: SelectedCartItem): SelectedCartItemDataModel { - const { id, menuId, itemId, price, quantity, audit } = entity; + const { id, cartItemId, itemId, price, quantity, audit } = entity; const { auditCreatedBy, auditCreatedDateTime, @@ -17,7 +17,7 @@ export class SelectedCartItemMapper implements IMapper implements ISelectedCartItem { - _menuId: Types.ObjectId; + _cartItemId: Types.ObjectId; _itemId: Types.ObjectId; _price: number; _quantity: number; @@ -11,19 +11,19 @@ export class SelectedCartItem extends Entity implements ISele constructor(id: Types.ObjectId, props: ISelectedCartItem) { super(id); - this._menuId = props.menuId; + this._cartItemId = props.cartItemId; this._price = props.price; this._quantity = props.quantity; this._itemId = props.itemId; this._audit = props.audit; } - get menuId(): Types.ObjectId { - return this._menuId; + get cartItemId(): Types.ObjectId { + return this._cartItemId; } - set menuId(id: Types.ObjectId) { - this._menuId = id; + set cartItemId(id: Types.ObjectId) { + this._cartItemId = id; } get itemId(): Types.ObjectId { diff --git a/backend/src/infrastructure/data_access/repositories/models/selected-item-model.interface.ts b/backend/src/infrastructure/data_access/repositories/models/selected-item-model.interface.ts index d54a7c59..4a792efb 100644 --- a/backend/src/infrastructure/data_access/repositories/models/selected-item-model.interface.ts +++ b/backend/src/infrastructure/data_access/repositories/models/selected-item-model.interface.ts @@ -1,8 +1,7 @@ import { Types } from 'mongoose'; export interface ISelectedCartItemDataModel { - readonly menuId: Types.ObjectId; - readonly itemId: Types.ObjectId; + readonly cartItemId: Types.ObjectId; readonly price: number; readonly quantity: number; } diff --git a/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts index be0f488f..0c6cfce9 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts @@ -1,22 +1,22 @@ -import { BaseDocument } from 'src/infrastructure/database'; -import { ISelectedCartItemDataModel } from '../models/selected-item-model.interface'; import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; -import mongoose, { Types } from 'mongoose'; import { Type } from 'class-transformer'; -import { MenuDataModel } from './menu.schema'; +import mongoose, { Types } from 'mongoose'; +import { BaseDocument } from 'src/infrastructure/database'; +import { ISelectedCartItemDataModel } from '../models/selected-item-model.interface'; import { CartItemDataModel } from './cartItem.schema'; +import { ItemDataModel } from './item.schema'; export type SelectedCartItemDocument = SelectedCartItemDataModel & Document; @Schema({ versionKey: 'false' }) export class SelectedCartItemDataModel extends BaseDocument implements ISelectedCartItemDataModel { @Prop({ type: mongoose.Schema.Types.ObjectId }) - @Type(() => MenuDataModel) - menuId: Types.ObjectId; + @Type(() => ItemDataModel) + itemId: Types.ObjectId; @Prop({ type: mongoose.Schema.Types.ObjectId }) @Type(() => CartItemDataModel) - itemId: Types.ObjectId; + cartItemId: Types.ObjectId; @Prop({ type: Number, required: true }) price: number; From dead621882291c22d14e1dc134e7f12cd4d7a96a Mon Sep 17 00:00:00 2001 From: ola Date: Sun, 24 Sep 2023 07:56:47 +0800 Subject: [PATCH 10/19] make cartitem and selectedCart Items optional in parent models --- backend/src/cart/cart-entity.interface.ts | 2 +- backend/src/cart/cart-item.ts | 6 +++--- .../data_access/repositories/models/cart-item-data.model.ts | 2 +- .../repositories/models/order-model.interface.ts | 2 +- .../data_access/repositories/schemas/cartItem.schema.ts | 2 +- .../data_access/repositories/schemas/order.schema.ts | 4 ++-- backend/src/order/order-entity.interface.ts | 2 +- backend/src/order/order.ts | 6 +++--- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/backend/src/cart/cart-entity.interface.ts b/backend/src/cart/cart-entity.interface.ts index b996d340..473cfd8b 100644 --- a/backend/src/cart/cart-entity.interface.ts +++ b/backend/src/cart/cart-entity.interface.ts @@ -6,6 +6,6 @@ export interface ICartItem { menuId: Types.ObjectId; orderId: Types.ObjectId; total: number; - selectedItems: SelectedCartItem[]; + selectedItems?: SelectedCartItem[]; audit: Audit; } diff --git a/backend/src/cart/cart-item.ts b/backend/src/cart/cart-item.ts index e35f7c0a..9b06f870 100644 --- a/backend/src/cart/cart-item.ts +++ b/backend/src/cart/cart-item.ts @@ -7,7 +7,7 @@ export class CartItem extends Entity implements ICartItem { _menuId: Types.ObjectId; _orderId: Types.ObjectId; _total: number; - _selectedItems: SelectedCartItem[]; + _selectedItems: SelectedCartItem[] | undefined; _audit: Audit; constructor(id: Types.ObjectId, props: ICartItem) { @@ -42,11 +42,11 @@ export class CartItem extends Entity implements ICartItem { this._total = total; } - get selectedItems(): SelectedCartItem[] { + get selectedItems(): SelectedCartItem[] | undefined { return this._selectedItems; } - set setSelectedItems(selectedItems: SelectedCartItem[]) { + set setSelectedItems(selectedItems: SelectedCartItem[] | undefined) { this._selectedItems = selectedItems; } diff --git a/backend/src/infrastructure/data_access/repositories/models/cart-item-data.model.ts b/backend/src/infrastructure/data_access/repositories/models/cart-item-data.model.ts index c33bdf81..3ed81007 100644 --- a/backend/src/infrastructure/data_access/repositories/models/cart-item-data.model.ts +++ b/backend/src/infrastructure/data_access/repositories/models/cart-item-data.model.ts @@ -5,5 +5,5 @@ export interface ICartItemModel { readonly menuId: Types.ObjectId; readonly orderId: Types.ObjectId; readonly total: number; - readonly selectedItems: SelectedCartItemDataModel[]; + readonly selectedItems?: SelectedCartItemDataModel[]; } diff --git a/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts b/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts index daafe39b..3d27734f 100644 --- a/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts +++ b/backend/src/infrastructure/data_access/repositories/models/order-model.interface.ts @@ -10,5 +10,5 @@ export interface IOrderDataModel { readonly total: number; readonly discount?: number; readonly orderManagerId?: Types.ObjectId; - readonly cartItems: CartItemDataModel[]; + readonly cartItems?: CartItemDataModel[]; } diff --git a/backend/src/infrastructure/data_access/repositories/schemas/cartItem.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/cartItem.schema.ts index 883c526f..1d662bb3 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/cartItem.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/cartItem.schema.ts @@ -23,7 +23,7 @@ export class CartItemDataModel extends BaseDocument implements ICartItemModel { @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: SelectedCartItemDataModel }] }) @Type(() => SelectedCartItemDataModel) - selectedItems: SelectedCartItemDataModel[]; + selectedItems?: SelectedCartItemDataModel[]; } export const CartItemSchema = SchemaFactory.createForClass(CartItemDataModel); diff --git a/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts index c7562f2c..caab78d2 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts @@ -31,10 +31,10 @@ export class OrderDataModel extends BaseDocument implements IOrderDataModel { @Prop({ type: Number, required: true }) total: number; - + @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: CartItemDataModel }] }) @Type(() => CartItemDataModel) - cartItems: CartItemDataModel[]; + cartItems?: CartItemDataModel[]; } export const OrderSchema = SchemaFactory.createForClass(OrderDataModel); diff --git a/backend/src/order/order-entity.interface.ts b/backend/src/order/order-entity.interface.ts index a2798ab6..1dc06cd6 100644 --- a/backend/src/order/order-entity.interface.ts +++ b/backend/src/order/order-entity.interface.ts @@ -14,5 +14,5 @@ export interface IOrder { discount?: number; orderManagerId?: Types.ObjectId; audit: Audit; - cartItems: CartItem[]; + cartItems?: CartItem[]; } diff --git a/backend/src/order/order.ts b/backend/src/order/order.ts index f4554bd6..c93d7dd5 100644 --- a/backend/src/order/order.ts +++ b/backend/src/order/order.ts @@ -13,7 +13,7 @@ export class Order extends Entity implements IOrder { _discount?: number; _orderManagerId: Types.ObjectId; _audit: Audit; - _cartItems: CartItem[]; + _cartItems: CartItem[] | undefined; constructor( id: Types.ObjectId, @@ -95,11 +95,11 @@ export class Order extends Entity implements IOrder { this._audit = audit; } - get cartItems() { + get cartItems(): CartItem[] | undefined { return this._cartItems; } - set cartItems(cartItems: CartItem[]) { + set cartItems(cartItems: CartItem[] | undefined) { this._cartItems = cartItems; } From ad8f925852969d989b7e458e595abfa20ed2c0b7 Mon Sep 17 00:00:00 2001 From: ola Date: Sun, 24 Sep 2023 13:57:48 +0800 Subject: [PATCH 11/19] create the order service --- backend/src/app.module.ts | 2 + backend/src/application/constants/types.ts | 1 + backend/src/cart/cart-item.mapper.ts | 2 +- backend/src/cart/cart-item.ts | 2 +- backend/src/cart/dto/create-cart-item.dto.ts | 15 +++ .../selected-cart-item.mapper.ts | 8 +- .../selected-cart-items-entity.interface.ts | 1 + .../cart/selectedItems/selectedCartItem.ts | 12 +- .../repositories/cart-item.repository.ts | 19 ++++ .../interfaces/order-repository.interface.ts | 5 +- .../repositories/order.repository.ts | 14 +-- .../repositories/schemas/cartItem.schema.ts | 4 +- .../schemas/selected-cart-item.schema.ts | 7 +- .../selected-cart-item.repository.ts | 17 +++ .../mongoDB/generic-document.repository.ts | 19 ++-- .../middlewares/context.middleware.ts | 8 +- backend/src/order/dto/create-order.dto.ts | 21 +++- .../interface/order-service.interface.ts | 6 + backend/src/order/order.mapper.ts | 2 +- backend/src/order/order.module.ts | 58 ++++++++++ backend/src/order/order.service.ts | 107 ++++++++++++++++-- backend/src/order/order.ts | 2 +- backend/tsconfig.json | 2 +- 23 files changed, 288 insertions(+), 46 deletions(-) create mode 100644 backend/src/cart/dto/create-cart-item.dto.ts create mode 100644 backend/src/infrastructure/data_access/repositories/cart-item.repository.ts create mode 100644 backend/src/infrastructure/data_access/repositories/selected-cart-item.repository.ts create mode 100644 backend/src/order/interface/order-service.interface.ts create mode 100644 backend/src/order/order.module.ts diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index 692996d9..67202f98 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -18,6 +18,7 @@ import { ItemModule } from './item/item.module'; import { MerchantModule } from './merchant/merchant.module'; import { ApplicationExceptionsFilter, ApplicationLogger } from './infrastructure'; import { LocationModule } from './location'; +import { OrderModule } from './order/order.module'; @Module({ imports: [ @@ -47,6 +48,7 @@ import { LocationModule } from './location'; MenuModule, AddonModule, CategoryModule, + OrderModule, ], controllers: [AppController], providers: [ diff --git a/backend/src/application/constants/types.ts b/backend/src/application/constants/types.ts index bb931544..e529bb75 100644 --- a/backend/src/application/constants/types.ts +++ b/backend/src/application/constants/types.ts @@ -21,4 +21,5 @@ export const TYPES = { IItemRepository: Symbol('IItemRepository'), IAddonRepository: Symbol('IAddonRepository'), IOrderRepository: Symbol('IOrderRepository'), + IOrderService: Symbol('IOrderService'), }; diff --git a/backend/src/cart/cart-item.mapper.ts b/backend/src/cart/cart-item.mapper.ts index 0c0747fb..3d590884 100644 --- a/backend/src/cart/cart-item.mapper.ts +++ b/backend/src/cart/cart-item.mapper.ts @@ -52,7 +52,7 @@ export class CartItemMapper implements IMapper { const entity: CartItem = CartItem.create( { menuId, orderId, total, selectedItems: selectedItemsToDomain, audit: this.auditMapper.toDomain(model) }, _id, - ).getValue(); + ); return entity; } } diff --git a/backend/src/cart/cart-item.ts b/backend/src/cart/cart-item.ts index 9b06f870..30ba4131 100644 --- a/backend/src/cart/cart-item.ts +++ b/backend/src/cart/cart-item.ts @@ -59,6 +59,6 @@ export class CartItem extends Entity implements ICartItem { } static create(props: ICartItem, id?: Types.ObjectId) { - return Result.ok(new CartItem(id, props)); + return Result.ok(new CartItem(id, props)).getValue(); } } diff --git a/backend/src/cart/dto/create-cart-item.dto.ts b/backend/src/cart/dto/create-cart-item.dto.ts new file mode 100644 index 00000000..8629aa0a --- /dev/null +++ b/backend/src/cart/dto/create-cart-item.dto.ts @@ -0,0 +1,15 @@ +import { IsNotEmpty, IsNumber, IsString } from 'class-validator'; + +export class CreateCartItemDTO { + @IsString() + @IsNotEmpty() + menuId: string; + + @IsString() + @IsNotEmpty() + orderId: string; + + @IsNumber() + @IsNotEmpty() + total: number; +} diff --git a/backend/src/cart/selectedItems/selected-cart-item.mapper.ts b/backend/src/cart/selectedItems/selected-cart-item.mapper.ts index 7cb2b743..0a6220c3 100644 --- a/backend/src/cart/selectedItems/selected-cart-item.mapper.ts +++ b/backend/src/cart/selectedItems/selected-cart-item.mapper.ts @@ -6,7 +6,7 @@ import { SelectedCartItem } from './selectedCartItem'; export class SelectedCartItemMapper implements IMapper { constructor(private readonly auditMapper: AuditMapper) {} toPersistence(entity: SelectedCartItem): SelectedCartItemDataModel { - const { id, cartItemId, itemId, price, quantity, audit } = entity; + const { id, cartItemId, itemId, price, quantity, menuId, audit } = entity; const { auditCreatedBy, auditCreatedDateTime, @@ -19,6 +19,7 @@ export class SelectedCartItemMapper implements IMapper implements ISelectedCartItem { _cartItemId: Types.ObjectId; _itemId: Types.ObjectId; + _menuId: Types.ObjectId; _price: number; _quantity: number; _audit: Audit; @@ -12,6 +13,7 @@ export class SelectedCartItem extends Entity implements ISele constructor(id: Types.ObjectId, props: ISelectedCartItem) { super(id); this._cartItemId = props.cartItemId; + this._menuId = props.menuId; this._price = props.price; this._quantity = props.quantity; this._itemId = props.itemId; @@ -26,6 +28,14 @@ export class SelectedCartItem extends Entity implements ISele this._cartItemId = id; } + get menuId(): Types.ObjectId { + return this._menuId; + } + + set menuId(id: Types.ObjectId) { + this._menuId = id; + } + get itemId(): Types.ObjectId { return this._itemId; } @@ -59,6 +69,6 @@ export class SelectedCartItem extends Entity implements ISele } static create(props: ISelectedCartItem, id?: Types.ObjectId) { - return Result.ok(new SelectedCartItem(id, props)); + return Result.ok(new SelectedCartItem(id, props)).getValue(); } } diff --git a/backend/src/infrastructure/data_access/repositories/cart-item.repository.ts b/backend/src/infrastructure/data_access/repositories/cart-item.repository.ts new file mode 100644 index 00000000..a5dfb24a --- /dev/null +++ b/backend/src/infrastructure/data_access/repositories/cart-item.repository.ts @@ -0,0 +1,19 @@ +import { CartItemMapper } from './../../../cart/cart-item.mapper'; +import { Injectable } from '@nestjs/common'; +import { CartItem } from 'src/cart/cart-item'; +import { GenericDocumentRepository } from 'src/infrastructure/database'; +import { CartItemDataModel, CartItemDocument } from './schemas/cartItem.schema'; +import { InjectConnection, InjectModel } from '@nestjs/mongoose'; +import { Connection, Model } from 'mongoose'; + +@Injectable() +export class CartItemRepository extends GenericDocumentRepository { + cartItemMapper: CartItemMapper; + constructor( + @InjectModel(CartItemDataModel.name) cartItemDataModel: Model, + @InjectConnection() readonly connection: Connection, + cartItemMapper: CartItemMapper, + ) { + super(cartItemDataModel, connection, cartItemMapper); + } +} diff --git a/backend/src/infrastructure/data_access/repositories/interfaces/order-repository.interface.ts b/backend/src/infrastructure/data_access/repositories/interfaces/order-repository.interface.ts index 3e9f9992..a239e105 100644 --- a/backend/src/infrastructure/data_access/repositories/interfaces/order-repository.interface.ts +++ b/backend/src/infrastructure/data_access/repositories/interfaces/order-repository.interface.ts @@ -1,7 +1,8 @@ import { Order } from 'src/order/order'; -import { OrderDataModel } from '../schemas/order.schema'; +import { OrderDataModel, OrderDocument } from '../schemas/order.schema'; +import { IGenericDocument } from 'src/infrastructure/database'; -export interface IOrderRepository { +export interface IOrderRepository extends IGenericDocument { getOrders(): Promise; createOrder(order: OrderDataModel): Promise; } diff --git a/backend/src/infrastructure/data_access/repositories/order.repository.ts b/backend/src/infrastructure/data_access/repositories/order.repository.ts index 0e8b1eb2..64ca93ee 100644 --- a/backend/src/infrastructure/data_access/repositories/order.repository.ts +++ b/backend/src/infrastructure/data_access/repositories/order.repository.ts @@ -10,7 +10,6 @@ import { IOrderRepository } from './interfaces/order-repository.interface'; @Injectable() export class OrderRepository extends GenericDocumentRepository implements IOrderRepository { orderMapper: OrderMapper; - orderDataModel: Model; constructor( @InjectModel(OrderDataModel.name) orderDataModel: Model, @InjectConnection() readonly connection: Connection, @@ -18,20 +17,13 @@ export class OrderRepository extends GenericDocumentRepository { - const documents = await this.orderDataModel.find({}); - return documents.length ? documents.map((doc) => this.orderMapper.toDomain(doc)) : []; + return (await this.find({})).getValue(); } - async createOrder(order: OrderDataModel): Promise { - const doc = new this.DocumentModel({ - ...order, - _id: new Types.ObjectId(), - }); - const result = (await doc.save()).toJSON(); - return result; + async createOrder(order: OrderDataModel): Promise { + return (await this.create(order)).getValue(); } } diff --git a/backend/src/infrastructure/data_access/repositories/schemas/cartItem.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/cartItem.schema.ts index 1d662bb3..50485a8a 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/cartItem.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/cartItem.schema.ts @@ -1,6 +1,6 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Type } from 'class-transformer'; -import mongoose, { Types } from 'mongoose'; +import mongoose, { Document, Types } from 'mongoose'; import { BaseDocument } from 'src/infrastructure/database'; import { ICartItemModel } from '../models/cart-item-data.model'; import { MenuDataModel } from './menu.schema'; @@ -21,7 +21,7 @@ export class CartItemDataModel extends BaseDocument implements ICartItemModel { @Prop({ type: String, required: true }) total: number; - @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: SelectedCartItemDataModel }] }) + @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: SelectedCartItemDataModel.name }] }) @Type(() => SelectedCartItemDataModel) selectedItems?: SelectedCartItemDataModel[]; } diff --git a/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts index 0c6cfce9..f7112a72 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema.ts @@ -1,10 +1,11 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Type } from 'class-transformer'; -import mongoose, { Types } from 'mongoose'; +import mongoose, { Document, Types } from 'mongoose'; import { BaseDocument } from 'src/infrastructure/database'; import { ISelectedCartItemDataModel } from '../models/selected-item-model.interface'; import { CartItemDataModel } from './cartItem.schema'; import { ItemDataModel } from './item.schema'; +import { MenuDataModel } from './menu.schema'; export type SelectedCartItemDocument = SelectedCartItemDataModel & Document; @@ -14,6 +15,10 @@ export class SelectedCartItemDataModel extends BaseDocument implements ISelected @Type(() => ItemDataModel) itemId: Types.ObjectId; + @Prop({ type: mongoose.Schema.Types.ObjectId }) + @Type(() => MenuDataModel) + menuId: Types.ObjectId; + @Prop({ type: mongoose.Schema.Types.ObjectId }) @Type(() => CartItemDataModel) cartItemId: Types.ObjectId; diff --git a/backend/src/infrastructure/data_access/repositories/selected-cart-item.repository.ts b/backend/src/infrastructure/data_access/repositories/selected-cart-item.repository.ts new file mode 100644 index 00000000..1915f42c --- /dev/null +++ b/backend/src/infrastructure/data_access/repositories/selected-cart-item.repository.ts @@ -0,0 +1,17 @@ +import { SelectedCartItemMapper } from './../../../cart/selectedItems/selected-cart-item.mapper'; +import { SelectedCartItem } from 'src/cart/selectedItems/selectedCartItem'; +import { SelectedCartItemDataModel, SelectedCartItemDocument } from './schemas/selected-cart-item.schema'; +import { InjectConnection, InjectModel } from '@nestjs/mongoose'; +import { Connection, Model } from 'mongoose'; +import { GenericDocumentRepository } from 'src/infrastructure/database'; + +export class SelectedCartItemRepository extends GenericDocumentRepository { + selectedCartItemMapper: SelectedCartItemMapper; + constructor( + @InjectModel(SelectedCartItemDataModel.name) selectedCartItemDataModel: Model, + @InjectConnection() readonly connection: Connection, + selectedCartItemMapper: SelectedCartItemMapper, + ) { + super(selectedCartItemDataModel, connection, selectedCartItemMapper); + } +} diff --git a/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts b/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts index 69dac7b5..a652f2eb 100644 --- a/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts +++ b/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts @@ -50,10 +50,7 @@ export abstract class GenericDocumentRepository imp } async create(document: any, options?: SaveOptions): Promise> { - const doc = new this.DocumentModel({ - ...document, - _id: new Types.ObjectId(), - }); + const doc = this.createDocument(document); const result = (await (await doc.save(options)).toJSON()) as T; if (!result) { return Result.fail('An Error occured, unable to save document in the db', HttpStatus.INTERNAL_SERVER_ERROR); @@ -73,7 +70,7 @@ export abstract class GenericDocumentRepository imp return Result.ok(entity); } - async upsert(filterQuery: FilterQuery, document: Partial): Promise { + async upsert(filterQuery: FilterQuery, document: Partial): Promise { const result = await this.DocumentModel.findOneAndUpdate(filterQuery, document, { lean: true, upsert: true, @@ -102,14 +99,22 @@ export abstract class GenericDocumentRepository imp } async insertMany(docs: any): Promise> { - const documents = await this.DocumentModel.insertMany(docs); + const documentsToSave = docs.map((doc) => this.createDocument(doc)); + const documents = await this.DocumentModel.insertMany(documentsToSave); const entities: TEntity[] = documents.map((doc) => this.mapper.toDomain(doc)); return Result.ok(entities); } async updateOne(filter: any, query: any): Promise> { const document = await this.DocumentModel.updateOne(filter, { $set: query }); - const entity: TEntity = this.mapper.toDomain(document); + const entity: TEntity = this.mapper.toDomain(document as any); return Result.ok(entity); } + + createDocument(document: any) { + return new this.DocumentModel({ + ...document, + _id: new Types.ObjectId(), + }); + } } diff --git a/backend/src/infrastructure/middlewares/context.middleware.ts b/backend/src/infrastructure/middlewares/context.middleware.ts index 16c06993..34ff54e8 100644 --- a/backend/src/infrastructure/middlewares/context.middleware.ts +++ b/backend/src/infrastructure/middlewares/context.middleware.ts @@ -18,10 +18,10 @@ export class ContextMiddleWare implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { const headers = req.headers; const errors = new Object() as any; - // if (Object.hasOwnProperty.call(headers, APIResponseMessage.emailHeader)) { - // errors.email = APIResponseMessage.emailHeaderError; - // } - if (!Object.hasOwnProperty.call(headers, APIResponseMessage.correlationIdHeader)) { + if (!Object.hasOwn(headers, APIResponseMessage.emailHeader)) { + errors.email = APIResponseMessage.emailHeaderError; + } + if (!Object.hasOwn(headers, APIResponseMessage.correlationIdHeader)) { errors.correlationId = APIResponseMessage.correlationIdHeaderError; } for (const [key, value] of Object.entries(headers)) { diff --git a/backend/src/order/dto/create-order.dto.ts b/backend/src/order/dto/create-order.dto.ts index 661ce39a..f1866b7c 100644 --- a/backend/src/order/dto/create-order.dto.ts +++ b/backend/src/order/dto/create-order.dto.ts @@ -1,10 +1,25 @@ +import { IsArray, IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator'; +import { currentStatus, dinningType } from '../order-entity.interface'; import { CartItemDataModel } from 'src/infrastructure/data_access/repositories/schemas/cartItem.schema'; export class CreateOrderDTO { - state: string; - type: string; + @IsString() + @IsNotEmpty() + state: currentStatus; + + @IsString() + @IsNotEmpty() + type: dinningType; + + @IsString() + @IsNotEmpty() merchantId: string; + + @IsNumber() + @IsNotEmpty() total: number; - quantity: number; + + @IsOptional() + @IsArray() cartItems: CartItemDataModel[]; } diff --git a/backend/src/order/interface/order-service.interface.ts b/backend/src/order/interface/order-service.interface.ts new file mode 100644 index 00000000..910cb74e --- /dev/null +++ b/backend/src/order/interface/order-service.interface.ts @@ -0,0 +1,6 @@ +import { CreateOrderDTO } from '../dto/create-order.dto'; +import { IOrderResponseDTO } from '../order-response.dto'; + +export interface IOrderService { + createOrder(orderSummary: CreateOrderDTO): Promise; +} diff --git a/backend/src/order/order.mapper.ts b/backend/src/order/order.mapper.ts index 15b9338d..1d5ee857 100644 --- a/backend/src/order/order.mapper.ts +++ b/backend/src/order/order.mapper.ts @@ -51,7 +51,7 @@ export class OrderMapper implements IMapper { cartItems: cartItems.map((cartItem) => this.cartItemMapper.toDomain(cartItem)), }, _id, - ).getValue(); + ); return entity; } } diff --git a/backend/src/order/order.module.ts b/backend/src/order/order.module.ts new file mode 100644 index 00000000..b286901b --- /dev/null +++ b/backend/src/order/order.module.ts @@ -0,0 +1,58 @@ +import { Module } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { MongooseModule } from '@nestjs/mongoose'; +import { TYPES } from 'src/application'; +import { AuditMapper } from 'src/audit'; +import { CartItemMapper } from 'src/cart/cart-item.mapper'; +import { SelectedCartItemMapper } from 'src/cart/selectedItems/selected-cart-item.mapper'; +import { + ContextService, + ItemDataModel, + ItemSchema, + MerchantDataModel, + MerchantRepository, + MerchantSchema, +} from 'src/infrastructure'; +import { CartItemRepository } from 'src/infrastructure/data_access/repositories/cart-item.repository'; +import { OrderRepository } from 'src/infrastructure/data_access/repositories/order.repository'; +import { CartItemDataModel, CartItemSchema } from 'src/infrastructure/data_access/repositories/schemas/cartItem.schema'; +import { OrderDataModel, OrderSchema } from 'src/infrastructure/data_access/repositories/schemas/order.schema'; +import { + SelectedCartItemDataModel, + SelectedCartItemSchema, +} from 'src/infrastructure/data_access/repositories/schemas/selected-cart-item.schema'; +import { SelectedCartItemRepository } from 'src/infrastructure/data_access/repositories/selected-cart-item.repository'; +import { MerchantMapper, MerchantService } from 'src/merchant'; +import { ValidateUser } from 'src/utils'; +import { OrderMapper } from './order.mapper'; +import { OrderService } from './order.service'; + +@Module({ + imports: [ + MongooseModule.forFeature([ + { name: OrderDataModel.name, schema: OrderSchema }, + { name: MerchantDataModel.name, schema: MerchantSchema }, + { name: ItemDataModel.name, schema: ItemSchema }, + { name: CartItemDataModel.name, schema: CartItemSchema }, + { name: SelectedCartItemDataModel.name, schema: SelectedCartItemSchema }, + ]), + ], + controllers: [], + providers: [ + { provide: TYPES.IOrderService, useClass: OrderService }, + { provide: TYPES.IOrderRepository, useClass: OrderRepository }, + { provide: TYPES.IMerchantService, useClass: MerchantService }, + { provide: TYPES.IContextService, useClass: ContextService }, + { provide: TYPES.IValidateUser, useClass: ValidateUser }, + MerchantRepository, + CartItemRepository, + SelectedCartItemRepository, + OrderMapper, + SelectedCartItemMapper, + CartItemMapper, + JwtService, + MerchantMapper, + AuditMapper, + ], +}) +export class OrderModule {} diff --git a/backend/src/order/order.service.ts b/backend/src/order/order.service.ts index 7f2a3724..da2fa619 100644 --- a/backend/src/order/order.service.ts +++ b/backend/src/order/order.service.ts @@ -1,9 +1,102 @@ -// import { Inject } from '@nestjs/common'; -// import { TYPES } from 'src/application'; -// import { IOrderRepository } from 'src/infrastructure/data_access/repositories/interfaces/order-repository.interface'; +import { CartItemMapper } from './../cart/cart-item.mapper'; +import { CartItemDataModel } from 'src/infrastructure/data_access/repositories/schemas/cartItem.schema'; +import { SelectedCartItemMapper } from './../cart/selectedItems/selected-cart-item.mapper'; +import { ConvertId } from './../utils/mongoose-id-conversion'; +import { HttpStatus, Inject } from '@nestjs/common'; +import { TYPES } from 'src/application'; +import { IOrderRepository } from 'src/infrastructure/data_access/repositories/interfaces/order-repository.interface'; +import { CreateOrderDTO } from './dto/create-order.dto'; +import { IMerchantService, Merchant } from 'src/merchant'; +import { Context, IContextService, MerchantRepository } from 'src/infrastructure'; +import { Audit, Result } from 'src/domain'; +import { throwApplicationError } from 'src/infrastructure/utilities/exception-instance'; +import { Order } from './order'; +import { OrderDataModel } from 'src/infrastructure/data_access/repositories/schemas/order.schema'; +import { OrderMapper } from './order.mapper'; +import { CartItem } from 'src/cart/cart-item'; +import { CartItemRepository } from 'src/infrastructure/data_access/repositories/cart-item.repository'; +import { Types } from 'mongoose'; +import { SelectedCartItem } from 'src/cart/selectedItems/selectedCartItem'; +import { SelectedCartItemRepository } from 'src/infrastructure/data_access/repositories/selected-cart-item.repository'; +import { OrderParser } from './order.parser'; +import { IOrderResponseDTO } from './order-response.dto'; +import { IOrderService } from './interface/order-service.interface'; -// export class OrderService { -// constructor(@Inject(TYPES.IOrderRepository) private readonly orderRepository: IOrderRepository) {} +export class OrderService implements IOrderService { + private context: Context; + constructor( + @Inject(TYPES.IOrderRepository) private readonly orderRepository: IOrderRepository, + @Inject(TYPES.IMerchantService) private readonly merchantService: IMerchantService, + @Inject(TYPES.IContextService) + private readonly contextService: IContextService, + private readonly merchantRepository: MerchantRepository, + private readonly cartItemRepository: CartItemRepository, + private readonly selectedCartItemRepository: SelectedCartItemRepository, + private readonly orderMapper: OrderMapper, + private readonly selectedItemMapper: SelectedCartItemMapper, + private readonly cartItemMapper: CartItemMapper, + ) { + this.context = this.contextService.getContext(); + } -// createOrder(orderSummary: ){} -// } + async createOrder(orderSummary: CreateOrderDTO): Promise { + await this.merchantService.validateContext(); + const { state, type, merchantId, total, cartItems } = orderSummary; + const validateMerchant: Result = await this.merchantRepository.findOne({ _id: merchantId }); + if (!validateMerchant.isSuccess) { + throwApplicationError(HttpStatus.NOT_FOUND, `Merchant does not exist`); + } + const session = await this.orderRepository.startSession(); + session.startTransaction(); + try { + const audit: Audit = Audit.createInsertContext(this.context); + const merchantObjId = ConvertId.convertStringToObjectId(merchantId); + const order: Order = Order.create({ state, type, total, merchantId: merchantObjId, audit }); + const orderModel: OrderDataModel = this.orderMapper.toPersistence(order); + const orderToSave: Result = await this.orderRepository.createOrder(orderModel); + if (!orderToSave.isSuccess) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Error while creating order'); + } + const savedOrder = orderToSave.getValue(); + const orderId = savedOrder.id; + if (cartItems) { + const items = cartItems.map((item) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { selectedItems, ...otherItemProperties } = item; + return CartItem.create({ ...otherItemProperties, orderId, audit }); + }); + const cartItemDataModels: CartItemDataModel[] = items.map((item) => this.cartItemMapper.toPersistence(item)); + const savedCartItems: Result = await this.cartItemRepository.insertMany(cartItemDataModels); + if (!savedCartItems.isSuccess) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Error while creating order'); + } + const savedItems = savedCartItems.getValue(); + + const cartItemMap = new Map(); + savedItems.forEach((item) => cartItemMap.set(item.menuId, item.id)); + + const cartSelectedItems = cartItems.map((item) => item.selectedItems); + const flattenedSelectedItems = cartSelectedItems.flat(); + flattenedSelectedItems.forEach((item) => { + if (cartItemMap.has(item.menuId)) { + item.cartItemId = cartItemMap.get(item.menuId); + } + }); + const selectedItems = flattenedSelectedItems.map((item) => SelectedCartItem.create({ ...item, audit })); + const selectedCartItemsDataModel = selectedItems.map((item) => this.selectedItemMapper.toPersistence(item)); + const savedSelectedCartItems: Result = await this.selectedCartItemRepository.insertMany( + selectedCartItemsDataModel, + ); + if (!savedSelectedCartItems.isSuccess) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Error while creating order'); + } + await session.commitTransaction(); + const response = OrderParser.createOrderResponse(savedOrder); + return response; + } + } catch (error) { + session.abortTransaction(); + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, JSON.stringify(error)); + } + } +} diff --git a/backend/src/order/order.ts b/backend/src/order/order.ts index c93d7dd5..fc5301ff 100644 --- a/backend/src/order/order.ts +++ b/backend/src/order/order.ts @@ -104,6 +104,6 @@ export class Order extends Entity implements IOrder { } static create(props: IOrder, id?: Types.ObjectId) { - return Result.ok(new Order(id, props)); + return Result.ok(new Order(id, props)).getValue(); } } diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 6727ee55..1fe14438 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -6,7 +6,7 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, - "target": "es2017", + "target": "ESNext", "sourceMap": true, "outDir": "./dist", "baseUrl": "./", From a83f120a01b125dd22e416faaef68196621fb61d Mon Sep 17 00:00:00 2001 From: ola Date: Sun, 24 Sep 2023 14:13:21 +0800 Subject: [PATCH 12/19] create order controller --- .../src/cart/selectedItems/selectedCartItem.ts | 4 ---- .../order/interface/order-service.interface.ts | 3 ++- backend/src/order/order.controller.ts | 16 ++++++++++++++++ backend/src/order/order.service.ts | 4 ++-- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/backend/src/cart/selectedItems/selectedCartItem.ts b/backend/src/cart/selectedItems/selectedCartItem.ts index be8a5a83..9157bfc4 100644 --- a/backend/src/cart/selectedItems/selectedCartItem.ts +++ b/backend/src/cart/selectedItems/selectedCartItem.ts @@ -32,10 +32,6 @@ export class SelectedCartItem extends Entity implements ISele return this._menuId; } - set cartItemId(id: Types.ObjectId) { - this._cartItemId = id; - } - get itemId(): Types.ObjectId { return this._itemId; } diff --git a/backend/src/order/interface/order-service.interface.ts b/backend/src/order/interface/order-service.interface.ts index 910cb74e..52beea65 100644 --- a/backend/src/order/interface/order-service.interface.ts +++ b/backend/src/order/interface/order-service.interface.ts @@ -1,6 +1,7 @@ +import { Result } from 'src/domain'; import { CreateOrderDTO } from '../dto/create-order.dto'; import { IOrderResponseDTO } from '../order-response.dto'; export interface IOrderService { - createOrder(orderSummary: CreateOrderDTO): Promise; + createOrder(orderSummary: CreateOrderDTO): Promise>; } diff --git a/backend/src/order/order.controller.ts b/backend/src/order/order.controller.ts index e69de29b..a6ce5cf0 100644 --- a/backend/src/order/order.controller.ts +++ b/backend/src/order/order.controller.ts @@ -0,0 +1,16 @@ +import { IOrderResponseDTO } from './order-response.dto'; +import { Body, Controller, Inject, Post } from '@nestjs/common'; +import { TYPES } from 'src/application'; +import { IOrderService } from './interface/order-service.interface'; +import { CreateOrderDTO } from './dto/create-order.dto'; +import { Result } from 'src/domain'; + +@Controller('orders') +export class OrderController { + constructor(@Inject(TYPES.IOrderService) private readonly orderService: IOrderService) {} + + @Post() + async create(@Body() request: CreateOrderDTO): Promise> { + return this.orderService.createOrder(request); + } +} diff --git a/backend/src/order/order.service.ts b/backend/src/order/order.service.ts index da2fa619..2aa1963e 100644 --- a/backend/src/order/order.service.ts +++ b/backend/src/order/order.service.ts @@ -39,7 +39,7 @@ export class OrderService implements IOrderService { this.context = this.contextService.getContext(); } - async createOrder(orderSummary: CreateOrderDTO): Promise { + async createOrder(orderSummary: CreateOrderDTO): Promise> { await this.merchantService.validateContext(); const { state, type, merchantId, total, cartItems } = orderSummary; const validateMerchant: Result = await this.merchantRepository.findOne({ _id: merchantId }); @@ -92,7 +92,7 @@ export class OrderService implements IOrderService { } await session.commitTransaction(); const response = OrderParser.createOrderResponse(savedOrder); - return response; + return Result.ok(response); } } catch (error) { session.abortTransaction(); From d90a5348f1abce09d8ce7c1c972e4b89891ecbc2 Mon Sep 17 00:00:00 2001 From: Oyinlola Olasunkanmi Raymond <60177090+olasunkanmi-SE@users.noreply.github.com> Date: Tue, 24 Oct 2023 08:13:22 +0800 Subject: [PATCH 13/19] checkout and fix (#391) --- .../repositories/order.repository.ts | 4 +- .../middlewares/context.middleware.ts | 6 +-- frontend/src/apis/menusApi.tsx | 2 +- frontend/src/apis/orderApi.ts | 47 +++++++++++++++++++ frontend/src/contexts/shoppingCartContext.tsx | 1 + frontend/src/models/order.model.ts | 21 +++++++++ 6 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 frontend/src/apis/orderApi.ts create mode 100644 frontend/src/models/order.model.ts diff --git a/backend/src/infrastructure/data_access/repositories/order.repository.ts b/backend/src/infrastructure/data_access/repositories/order.repository.ts index 64ca93ee..34f52c56 100644 --- a/backend/src/infrastructure/data_access/repositories/order.repository.ts +++ b/backend/src/infrastructure/data_access/repositories/order.repository.ts @@ -1,11 +1,11 @@ import { Injectable } from '@nestjs/common'; import { InjectConnection, InjectModel } from '@nestjs/mongoose'; -import { Connection, Model, Types } from 'mongoose'; +import { Connection, Model } from 'mongoose'; import { GenericDocumentRepository } from 'src/infrastructure/database'; import { Order } from 'src/order/order'; import { OrderMapper } from './../../../order/order.mapper'; -import { OrderDataModel, OrderDocument } from './schemas/order.schema'; import { IOrderRepository } from './interfaces/order-repository.interface'; +import { OrderDataModel, OrderDocument } from './schemas/order.schema'; @Injectable() export class OrderRepository extends GenericDocumentRepository implements IOrderRepository { diff --git a/backend/src/infrastructure/middlewares/context.middleware.ts b/backend/src/infrastructure/middlewares/context.middleware.ts index 34ff54e8..f9abcf52 100644 --- a/backend/src/infrastructure/middlewares/context.middleware.ts +++ b/backend/src/infrastructure/middlewares/context.middleware.ts @@ -18,9 +18,9 @@ export class ContextMiddleWare implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { const headers = req.headers; const errors = new Object() as any; - if (!Object.hasOwn(headers, APIResponseMessage.emailHeader)) { - errors.email = APIResponseMessage.emailHeaderError; - } + // if (!Object.hasOwn(headers, APIResponseMessage.emailHeader)) { + // errors.email = APIResponseMessage.emailHeaderError; + // } if (!Object.hasOwn(headers, APIResponseMessage.correlationIdHeader)) { errors.correlationId = APIResponseMessage.correlationIdHeaderError; } diff --git a/frontend/src/apis/menusApi.tsx b/frontend/src/apis/menusApi.tsx index 4036e200..7549116c 100644 --- a/frontend/src/apis/menusApi.tsx +++ b/frontend/src/apis/menusApi.tsx @@ -1,4 +1,4 @@ -import { IMenu, IMenus } from "../models/menu.model"; +import { IMenu } from "../models/menu.model"; import { ICreateMenu } from "../interfaces/menu.interface"; import { QueryObserverResult, useQuery } from "react-query"; import { menuApi } from "./axios"; diff --git a/frontend/src/apis/orderApi.ts b/frontend/src/apis/orderApi.ts new file mode 100644 index 00000000..c913ed2c --- /dev/null +++ b/frontend/src/apis/orderApi.ts @@ -0,0 +1,47 @@ +import { SelectedItem } from "./../reducers/cartReducer"; +import { useShoppingCart } from "../hooks/UseShoppingCart"; + +export const createOrder = async (order: any) => {}; + +const getOrderSummary = () => { + const { GetOrderSummary } = useShoppingCart(); + return GetOrderSummary(); +}; + +const reduceSelectedItems = () => { + const orderSummary = getOrderSummary(); + let selectedItems: SelectedItem[] = []; + if (orderSummary?.length) { + selectedItems = orderSummary.reduce((result: SelectedItem[], item) => { + if (item.menus?.length) { + item.menus.forEach((menu) => { + if (menu.selectedItems) { + menu.selectedItems.forEach((selectedItem) => { + const itemId = selectedItem.id; + const existingItem = result.find((item: any) => item.id === itemId); + if (existingItem) { + existingItem.price += selectedItem.price; + existingItem.quantity! += selectedItem.quantity!; + } else { + result.push({ ...selectedItem }); + } + }); + } + }); + } + return result; + }, []); + } + return selectedItems; +}; + +const getCartItems = () => { + const orderSummary = getOrderSummary(); + if (orderSummary?.length) { + const selectedItemsMap = new Map(); + reduceSelectedItems.forEach((item) => {}); + orderSummary.map((summary) => { + const cartItem = summary.menus; + }); + } +}; diff --git a/frontend/src/contexts/shoppingCartContext.tsx b/frontend/src/contexts/shoppingCartContext.tsx index 263f4c86..a8ac2697 100644 --- a/frontend/src/contexts/shoppingCartContext.tsx +++ b/frontend/src/contexts/shoppingCartContext.tsx @@ -399,6 +399,7 @@ export const ShoppingCartProvider = ({ children }: shoppingCartProviderProps) => const updateCartItems = (orderSummary: OrderSummary[]) => { state.orderSummary = orderSummary; + console.log(state.orderSummary); setLocalStorageData("cart", JSON.stringify(state), true); dispatch({ type: CartActionsType.UPDATE_CART_ITEMS, diff --git a/frontend/src/models/order.model.ts b/frontend/src/models/order.model.ts new file mode 100644 index 00000000..6054b762 --- /dev/null +++ b/frontend/src/models/order.model.ts @@ -0,0 +1,21 @@ +interface IOrder { + state: string; + type: string; + merchantId: string; + total: number; + cartItems: IcartItems[]; +} + +interface IcartItems { + menuId: string; + total: number; + quantity: number; + selectedItems: IselectedItems[]; +} + +interface IselectedItems { + itemId: string; + menuId: string; + price: number; + quantity: number; +} From a998d1ee0e971576d8cee6dd0c0ff332a53af014 Mon Sep 17 00:00:00 2001 From: Oyinlola Olasunkanmi Raymond <60177090+olasunkanmi-SE@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:54:37 +0800 Subject: [PATCH 14/19] Test (#393) * checkout and fix * fix errors and remove env from application (#392) Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#394) * fix errors and remove env from application * fix build errors Co-authored-by: Olasunkanmi Oyinlola <143487325+olasunkanmiraymond@users.noreply.github.com> Co-authored-by: Olasunkanmi Oyinlola --- backend/.gitignore | 4 +++- .../middlewares/context.middleware.ts | 2 +- frontend/src/apis/orderApi.ts | 24 ++++++++++--------- frontend/src/models/order.model.ts | 6 ++--- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/backend/.gitignore b/backend/.gitignore index 7ce7d985..6021dc60 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -33,4 +33,6 @@ lerna-debug.log* !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -.vscode/launch.json \ No newline at end of file +.vscode/launch.json + +.env \ No newline at end of file diff --git a/backend/src/infrastructure/middlewares/context.middleware.ts b/backend/src/infrastructure/middlewares/context.middleware.ts index f9abcf52..63251c08 100644 --- a/backend/src/infrastructure/middlewares/context.middleware.ts +++ b/backend/src/infrastructure/middlewares/context.middleware.ts @@ -21,7 +21,7 @@ export class ContextMiddleWare implements NestMiddleware { // if (!Object.hasOwn(headers, APIResponseMessage.emailHeader)) { // errors.email = APIResponseMessage.emailHeaderError; // } - if (!Object.hasOwn(headers, APIResponseMessage.correlationIdHeader)) { + if (!Object.hasOwnProperty.call(headers, APIResponseMessage.correlationIdHeader)) { errors.correlationId = APIResponseMessage.correlationIdHeaderError; } for (const [key, value] of Object.entries(headers)) { diff --git a/frontend/src/apis/orderApi.ts b/frontend/src/apis/orderApi.ts index c913ed2c..be372538 100644 --- a/frontend/src/apis/orderApi.ts +++ b/frontend/src/apis/orderApi.ts @@ -18,7 +18,9 @@ const reduceSelectedItems = () => { if (menu.selectedItems) { menu.selectedItems.forEach((selectedItem) => { const itemId = selectedItem.id; - const existingItem = result.find((item: any) => item.id === itemId); + const existingItem = result.find( + (item: any) => item.id === itemId + ); if (existingItem) { existingItem.price += selectedItem.price; existingItem.quantity! += selectedItem.quantity!; @@ -35,13 +37,13 @@ const reduceSelectedItems = () => { return selectedItems; }; -const getCartItems = () => { - const orderSummary = getOrderSummary(); - if (orderSummary?.length) { - const selectedItemsMap = new Map(); - reduceSelectedItems.forEach((item) => {}); - orderSummary.map((summary) => { - const cartItem = summary.menus; - }); - } -}; +// const getCartItems = () => { +// const orderSummary = getOrderSummary(); +// if (orderSummary?.length) { +// const selectedItemsMap = new Map(); +// reduceSelectedItems.forEach((item) => {}); +// orderSummary.map((summary) => { +// const cartItem = summary.menus; +// }); +// } +// }; diff --git a/frontend/src/models/order.model.ts b/frontend/src/models/order.model.ts index 6054b762..ae40de81 100644 --- a/frontend/src/models/order.model.ts +++ b/frontend/src/models/order.model.ts @@ -1,4 +1,4 @@ -interface IOrder { +export interface IOrder { state: string; type: string; merchantId: string; @@ -6,14 +6,14 @@ interface IOrder { cartItems: IcartItems[]; } -interface IcartItems { +export interface IcartItems { menuId: string; total: number; quantity: number; selectedItems: IselectedItems[]; } -interface IselectedItems { +export interface IselectedItems { itemId: string; menuId: string; price: number; From 599e37cc79727406765e95afbc40ed1939438762 Mon Sep 17 00:00:00 2001 From: Oyinlola Olasunkanmi Raymond <60177090+olasunkanmi-SE@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:13:43 +0800 Subject: [PATCH 15/19] Test (#396) * checkout and fix * fix errors and remove env from application (#392) Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#394) * fix errors and remove env from application * fix build errors --------- Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#395) * fix errors and remove env from application * fix build errors * remove .env file from backend --------- Co-authored-by: Olasunkanmi Oyinlola --------- Co-authored-by: Olasunkanmi Oyinlola <143487325+olasunkanmiraymond@users.noreply.github.com> Co-authored-by: Olasunkanmi Oyinlola --- backend/.env | 8 -------- backend/.gitignore | 1 + 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 backend/.env diff --git a/backend/.env b/backend/.env deleted file mode 100644 index 613345f8..00000000 --- a/backend/.env +++ /dev/null @@ -1,8 +0,0 @@ -DATABASE_URL=mongodb+srv://kosemani:omowunmi888@cluster0.4i82g.mongodb.net/learn?retryWrites=true -mockHash=23rt565regf3454t -JWT_ACCESS_TOKEN_SECRET='98h34jfew%i&o3298hin2p9#kn2u80@#$' -JWT_REFRESH_TOKEN_SECRET='few%i&o3298hin2p9#kn2u80@#$749' -JWT_ACCESS_TOKEN_EXPIRATION_TIME=60m -JWT_REFRESH_TOKEN_EXPIRATION_TIME=420m -APPSESSION=RestaurantApp -GUEST_EMAIL=guest@application.com diff --git a/backend/.gitignore b/backend/.gitignore index 6021dc60..65fe4734 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,3 +1,4 @@ +.env # compiled output /dist /node_modules From 35a3d9d829cce4cc2506c6a44411f5fb64afa0c3 Mon Sep 17 00:00:00 2001 From: Oyinlola Olasunkanmi Raymond <60177090+olasunkanmi-SE@users.noreply.github.com> Date: Wed, 25 Oct 2023 10:23:05 +0800 Subject: [PATCH 16/19] Test (#400) * checkout and fix * fix errors and remove env from application (#392) Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#394) * fix errors and remove env from application * fix build errors --------- Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#395) * fix errors and remove env from application * fix build errors * remove .env file from backend --------- Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#399) * fix errors and remove env from application * fix build errors * remove .env file from backend * fake an error * fake an error * fake an error --------- Co-authored-by: Olasunkanmi Oyinlola --------- Co-authored-by: Olasunkanmi Oyinlola <143487325+olasunkanmiraymond@users.noreply.github.com> Co-authored-by: Olasunkanmi Oyinlola From b6dd7f150f8bd89416cf6ab77930c5926795a1ce Mon Sep 17 00:00:00 2001 From: Oyinlola Olasunkanmi Raymond <60177090+olasunkanmi-SE@users.noreply.github.com> Date: Thu, 26 Oct 2023 09:59:42 +0800 Subject: [PATCH 17/19] Test (#403) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * checkout and fix * fix errors and remove env from application (#392) Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#394) * fix errors and remove env from application * fix build errors --------- Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#395) * fix errors and remove env from application * fix build errors * remove .env file from backend --------- Co-authored-by: Olasunkanmi Oyinlola * Offshore dev (#399) * fix errors and remove env from application * fix build errors * remove .env file from backend * fake an error * fake an error * fake an error --------- Co-authored-by: Olasunkanmi Oyinlola * Add additional methods to the Generic Repository (#402) * Release (#386) * Development (#235) * update github workflow yaml file * rename the frontend folder * Development (#237) * update github workflow yaml file * rename the frontend folder * create the checkout button * Development (#239) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * Development (#241) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Development (#242) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * Development (#244) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * Development (#246) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * Development (#248) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * Development (#250) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * Development (#252) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * Development (#254) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * Development (#256) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * Development (#257) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * Development (#259) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * Development (#261) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * Development (#262) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * Development (#264) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * Development (#266) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * merge conflicts * Development (#267) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * Development (#269) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * Development (#271) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * Development (#273) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * Development (#274) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * Development (#276) * Development (#277) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * Development (#279) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Development (#287) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * Development (#290) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Development (#292) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Development (#295) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Development (#297) * Development (#298) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * Development (#300) * Development (#301) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * add the call to action to clear cart * generate Ids for ordersummary * generate ordersummary ids * update the cart UI * Development (#303) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * add the call to action to clear cart * generate Ids for ordersummary * generate ordersummary ids * update the cart UI * create the localstorage utility functions * remove uuid package * remove crypto declaration * save state in local storage * persist cart state in local storage * Development (#306) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * add the call to action to clear cart * generate Ids for ordersummary * generate ordersummary ids * update the cart UI * create the localstorage utility functions * remove uuid package * remove crypto declaration * save state in local storage * persist cart state in local storage * Display list of car items * Development (#308) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * add the call to action to clear cart * generate Ids for ordersummary * generate ordersummary ids * update the cart UI * create the localstorage utility functions * remove uuid package * remove crypto declaration * save state in local storage * persist cart state in local storage * Display list of car items * implement remove item from cart * Development (#310) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * add the call to action to clear cart * generate Ids for ordersummary * generate ordersummary ids * update the cart UI * create the localstorage utility functions * remove uuid package * remove crypto declaration * save state in local storage * persist cart state in local storage * Display list of car items * implement remove item from cart * refactor shopping cart context component, move type definition to a new folder * Development (#312) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * add the call to action to clear cart * generate Ids for ordersummary * generate ordersummary ids * update the cart UI * create the localstorage utility functions * remove uuid package * remove crypto declaration * save state in local storage * persist cart state in local storage * Display list of car items * implement remove item from cart * refactor shopping cart context component, move type definition to a new folder * make shopping cart details child to offcanvas * Development (#315) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * add the call to action to clear cart * generate Ids for ordersummary * generate ordersummary ids * update the cart UI * create the localstorage utility functions * remove uuid package * remove crypto declaration * save state in local storage * persist cart state in local storage * Display list of car items * implement remove item from cart * refactor shopping cart context component, move type definition to a new folder * make shopping cart details child to offcanvas * create the update cart item modal * move the shopping cart component into cart folder * upgrade menu items on edit * fix build error * fix code smell * Development (#317) * update github workflow yaml file * rename the frontend folder * create the checkout button * create dynamic route * update the routing definition and getmenubyId API call * Merge branch 'development' of github.com:olasunkanmi-SE/restaurant into development * remove the styling for menu name * optimize the components * conditionally render the checkout component * remove code smell * Merge branch 'release' into development * update the menu item page and clean up the navigation * create the delete menu repo method, service and controller * create the delete menu API * update food menu component to include item id * update food menu component to include item id * add the add menu item to cart functionality * implement add menu items to cart * fix build errors * fix code smell * create the item quantity button component * update the menu list ui * implement the add items to cart functionality * fix code smell * create the selected items summary * update cart reducer * update the add item to cart implementation * create folder structure for componsnts * implement the remove from cart functionality * implement the add to cart functionality * rename add and remove from cart to add and remove menu from cart * remove the menuid from foodmenu component * create the shopping component * implement display menu quantity, also display only menu items ata a time * prevent increase in total price if the menu quantity is 1 * fix issues with totalprice calculations * fix issues with menu items reduction * fix the bug in shopping cart provider * remove menu price from global state * fix bug in remove menu from cart * fix error in menuItems calculations * update some names in the shoppingcart context * add the none button for food items * update remove item from cart method to calculate total price correctly * remove unused file * create the radio button * calculate order quantity * remove quantity count from checkout * Calculate cart total * disable add to cart buttons on page load * add development branch to github workflow, in order to track and build branches created from issues * fix code smells * enable the add to cart button on click none and addons * Incrementing cart quantity without addons * Fix: Add to Cart without incrementing the cart quantity throws an error * Create the summary modal and include error boundary in applocation * update error boundary url * add the edit and update button to the order summary page * add the call to action to clear cart * generate Ids for ordersummary * generate ordersummary ids * update the cart UI * create the localstorage utility functions * remove uuid package * remove crypto declaration * save state in local storage * persist cart state in local storage * Display list of car items * implement remove item from cart * refactor shopping cart context component, move type definition to a new folder * make shopp… --------- Co-authored-by: Olasunkanmi Oyinlola <143487325+olasunkanmiraymond@users.noreply.github.com> Co-authored-by: Olasunkanmi Oyinlola --- .../repositories/order.repository.ts | 8 ++- .../repositories/schemas/order.schema.ts | 2 +- .../mongoDB/generic-document.interface.ts | 6 +- .../mongoDB/generic-document.repository.ts | 68 ++++++++++++++++--- .../filters/exception.filter.ts | 11 ++- backend/src/order/order.service.ts | 46 +++++-------- 6 files changed, 96 insertions(+), 45 deletions(-) diff --git a/backend/src/infrastructure/data_access/repositories/order.repository.ts b/backend/src/infrastructure/data_access/repositories/order.repository.ts index 34f52c56..33438c46 100644 --- a/backend/src/infrastructure/data_access/repositories/order.repository.ts +++ b/backend/src/infrastructure/data_access/repositories/order.repository.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { HttpStatus, Injectable } from '@nestjs/common'; import { InjectConnection, InjectModel } from '@nestjs/mongoose'; import { Connection, Model } from 'mongoose'; import { GenericDocumentRepository } from 'src/infrastructure/database'; @@ -6,6 +6,7 @@ import { Order } from 'src/order/order'; import { OrderMapper } from './../../../order/order.mapper'; import { IOrderRepository } from './interfaces/order-repository.interface'; import { OrderDataModel, OrderDocument } from './schemas/order.schema'; +import { Result } from 'src/domain'; @Injectable() export class OrderRepository extends GenericDocumentRepository implements IOrderRepository { @@ -23,7 +24,8 @@ export class OrderRepository extends GenericDocumentRepository { - return (await this.create(order)).getValue(); + async createOrder(order: OrderDataModel): Promise> { + const response = (await this.create(order)).getValue(); + return response ? Result.ok(response) : Result.fail('Could not create order', HttpStatus.INTERNAL_SERVER_ERROR); } } diff --git a/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts b/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts index 0a0fffe5..caab78d2 100644 --- a/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts +++ b/backend/src/infrastructure/data_access/repositories/schemas/order.schema.ts @@ -31,7 +31,7 @@ export class OrderDataModel extends BaseDocument implements IOrderDataModel { @Prop({ type: Number, required: true }) total: number; - + @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: CartItemDataModel }] }) @Type(() => CartItemDataModel) cartItems?: CartItemDataModel[]; diff --git a/backend/src/infrastructure/database/mongoDB/generic-document.interface.ts b/backend/src/infrastructure/database/mongoDB/generic-document.interface.ts index 7559e2a5..8ecd66da 100644 --- a/backend/src/infrastructure/database/mongoDB/generic-document.interface.ts +++ b/backend/src/infrastructure/database/mongoDB/generic-document.interface.ts @@ -1,5 +1,5 @@ import { Result } from './../../../domain/result/result'; -import { FilterQuery, ProjectionType, QueryOptions, SaveOptions, UpdateQuery, ClientSession } from 'mongoose'; +import { FilterQuery, ProjectionType, QueryOptions, SaveOptions, UpdateQuery, ClientSession, Types } from 'mongoose'; export interface IGenericDocument { findOne(filterQuery: FilterQuery, projection?: ProjectionType): Promise>; @@ -27,4 +27,8 @@ export interface IGenericDocument { updateOne(filter: any, query: any): Promise>; deleteOne(filterQuery: FilterQuery): Promise; + + objectIdToString(objectId: Types.ObjectId): string; + + stringToObjectId(prop: string): Types.ObjectId; } diff --git a/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts b/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts index a652f2eb..ea8f00f0 100644 --- a/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts +++ b/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts @@ -12,6 +12,7 @@ import { UpdateQuery, } from 'mongoose'; import { Result } from './../../../domain/result/result'; +import { throwApplicationError } from './../../utilities/exception-instance'; import { IGenericDocument } from './generic-document.interface'; export abstract class GenericDocumentRepository implements IGenericDocument { @@ -21,6 +22,36 @@ export abstract class GenericDocumentRepository imp private readonly mapper: any, ) {} + public static createObjectId() { + return new Types.ObjectId(); + } + + private convertObjectIdToString(objectId: Types.ObjectId) { + return objectId.toString(); + } + + public objectIdToString(objectId: Types.ObjectId): string { + return this.convertObjectIdToString(objectId); + } + + public stringToObjectId(prop: string): Types.ObjectId { + return this.convertStringToObjectId(prop); + } + + private convertStringToObjectId(prop: string) { + return new Types.ObjectId(prop); + } + + async count(query: FilterQuery, limit?: number): Promise { + return this.DocumentModel.countDocuments(query, { limit }); + } + async aggregate( + query: any[], + options: { readPeference?: 'secondaryPreferred' | 'primaryPreferred' } = {}, + ): Promise { + return await this.DocumentModel.aggregate(query).read(options.readPeference || 'primary'); + } + async findOne(filterQuery: FilterQuery, projection?: ProjectionType): Promise> { const document = await this.DocumentModel.findOne(filterQuery, projection); if (!document) { @@ -40,15 +71,30 @@ export abstract class GenericDocumentRepository imp } async find( - filterQuery: FilterQuery, - projection?: ProjectionType, + query: FilterQuery, + select?: ProjectionType, options?: QueryOptions, - ): Promise> { - const documents = await this.DocumentModel.find(filterQuery, projection, options); + ): Promise> { + const documents = await this.DocumentModel.find(query, select, options) + .skip(options.skip) + .limit(options.limit) + .lean() + .exec(); const entities = documents?.length ? documents.map((document) => this.mapper.toDomain(document)) : []; return Result.ok(entities); } + async pagination(query: FilterQuery, select: ProjectionType, options: QueryOptions) { + const pageSize = 500; + const page = options.page || 1; + const skip = (page - 1) * pageSize; + const limit = options.limit || pageSize; + const documents = this.DocumentModel.find(query, select, { ...options, skip, limit }) + .batchSize(pageSize) + .cursor(); + return documents.map((doc) => this.mapper.toDomain(doc)); + } + async create(document: any, options?: SaveOptions): Promise> { const doc = this.createDocument(document); const result = (await (await doc.save(options)).toJSON()) as T; @@ -99,10 +145,14 @@ export abstract class GenericDocumentRepository imp } async insertMany(docs: any): Promise> { - const documentsToSave = docs.map((doc) => this.createDocument(doc)); - const documents = await this.DocumentModel.insertMany(documentsToSave); - const entities: TEntity[] = documents.map((doc) => this.mapper.toDomain(doc)); - return Result.ok(entities); + try { + const documentsToSave = docs.map((doc) => this.createDocument(doc)); + const documents = await this.DocumentModel.insertMany(documentsToSave); + const entities: TEntity[] = documents.map((doc) => this.mapper.toDomain(doc)); + return Result.ok(entities); + } catch (error) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to insert documents into the database'); + } } async updateOne(filter: any, query: any): Promise> { @@ -114,7 +164,7 @@ export abstract class GenericDocumentRepository imp createDocument(document: any) { return new this.DocumentModel({ ...document, - _id: new Types.ObjectId(), + _id: GenericDocumentRepository.createObjectId(), }); } } diff --git a/backend/src/infrastructure/filters/exception.filter.ts b/backend/src/infrastructure/filters/exception.filter.ts index f078625d..a6e6ed67 100644 --- a/backend/src/infrastructure/filters/exception.filter.ts +++ b/backend/src/infrastructure/filters/exception.filter.ts @@ -5,13 +5,16 @@ import { TYPES } from '../../application/constants'; import { IContextAwareLogger } from '../logger'; import { APIResponseMessage } from './../../application/constants/constants'; import { IExceptionResponse, IRequestException } from './exception-response.interface'; +import { BaseExceptionFilter } from '@nestjs/core'; @Catch() -export class ApplicationExceptionsFilter implements ExceptionFilter { +export class ApplicationExceptionsFilter extends BaseExceptionFilter { constructor( @Inject(TYPES.IApplicationLogger) private readonly logger: IContextAwareLogger, - ) {} + ) { + super(); + } catch(exception: any, host: ArgumentsHost) { const context = host.switchToHttp(); const response = context.getResponse(); @@ -36,6 +39,10 @@ export class ApplicationExceptionsFilter implements ExceptionFilter { this.logErrorMessage(request, JSON.stringify(responseBody), statusCode, exception); const errorLog: string = this.constructErrorMessage(responseBody, request, exception); this.writeErrorLogToFile(errorLog); + //consider using sentry + //https://docs.sentry.io/platforms/node/ + //https://dev.to/marcelozapatta/how-to-integrate-sentry-in-nestjs-3ema + super.catch(exception, host); response.status(statusCode).json(responseBody); return exception; } diff --git a/backend/src/order/order.service.ts b/backend/src/order/order.service.ts index 2aa1963e..9a2a3b65 100644 --- a/backend/src/order/order.service.ts +++ b/backend/src/order/order.service.ts @@ -1,26 +1,25 @@ -import { CartItemMapper } from './../cart/cart-item.mapper'; -import { CartItemDataModel } from 'src/infrastructure/data_access/repositories/schemas/cartItem.schema'; -import { SelectedCartItemMapper } from './../cart/selectedItems/selected-cart-item.mapper'; -import { ConvertId } from './../utils/mongoose-id-conversion'; import { HttpStatus, Inject } from '@nestjs/common'; +import { Types } from 'mongoose'; import { TYPES } from 'src/application'; -import { IOrderRepository } from 'src/infrastructure/data_access/repositories/interfaces/order-repository.interface'; -import { CreateOrderDTO } from './dto/create-order.dto'; -import { IMerchantService, Merchant } from 'src/merchant'; -import { Context, IContextService, MerchantRepository } from 'src/infrastructure'; +import { CartItem } from 'src/cart/cart-item'; +import { SelectedCartItem } from 'src/cart/selectedItems/selectedCartItem'; import { Audit, Result } from 'src/domain'; +import { Context, IContextService, MerchantRepository } from 'src/infrastructure'; +import { CartItemRepository } from 'src/infrastructure/data_access/repositories/cart-item.repository'; +import { IOrderRepository } from 'src/infrastructure/data_access/repositories/interfaces/order-repository.interface'; +import { CartItemDataModel } from 'src/infrastructure/data_access/repositories/schemas/cartItem.schema'; +import { OrderDataModel } from 'src/infrastructure/data_access/repositories/schemas/order.schema'; +import { SelectedCartItemRepository } from 'src/infrastructure/data_access/repositories/selected-cart-item.repository'; import { throwApplicationError } from 'src/infrastructure/utilities/exception-instance'; +import { IMerchantService, Merchant } from 'src/merchant'; +import { CartItemMapper } from './../cart/cart-item.mapper'; +import { SelectedCartItemMapper } from './../cart/selectedItems/selected-cart-item.mapper'; +import { CreateOrderDTO } from './dto/create-order.dto'; +import { IOrderService } from './interface/order-service.interface'; import { Order } from './order'; -import { OrderDataModel } from 'src/infrastructure/data_access/repositories/schemas/order.schema'; +import { IOrderResponseDTO } from './order-response.dto'; import { OrderMapper } from './order.mapper'; -import { CartItem } from 'src/cart/cart-item'; -import { CartItemRepository } from 'src/infrastructure/data_access/repositories/cart-item.repository'; -import { Types } from 'mongoose'; -import { SelectedCartItem } from 'src/cart/selectedItems/selectedCartItem'; -import { SelectedCartItemRepository } from 'src/infrastructure/data_access/repositories/selected-cart-item.repository'; import { OrderParser } from './order.parser'; -import { IOrderResponseDTO } from './order-response.dto'; -import { IOrderService } from './interface/order-service.interface'; export class OrderService implements IOrderService { private context: Context; @@ -50,13 +49,10 @@ export class OrderService implements IOrderService { session.startTransaction(); try { const audit: Audit = Audit.createInsertContext(this.context); - const merchantObjId = ConvertId.convertStringToObjectId(merchantId); + const merchantObjId = this.orderRepository.stringToObjectId(merchantId); const order: Order = Order.create({ state, type, total, merchantId: merchantObjId, audit }); const orderModel: OrderDataModel = this.orderMapper.toPersistence(order); const orderToSave: Result = await this.orderRepository.createOrder(orderModel); - if (!orderToSave.isSuccess) { - throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Error while creating order'); - } const savedOrder = orderToSave.getValue(); const orderId = savedOrder.id; if (cartItems) { @@ -67,9 +63,6 @@ export class OrderService implements IOrderService { }); const cartItemDataModels: CartItemDataModel[] = items.map((item) => this.cartItemMapper.toPersistence(item)); const savedCartItems: Result = await this.cartItemRepository.insertMany(cartItemDataModels); - if (!savedCartItems.isSuccess) { - throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Error while creating order'); - } const savedItems = savedCartItems.getValue(); const cartItemMap = new Map(); @@ -84,12 +77,7 @@ export class OrderService implements IOrderService { }); const selectedItems = flattenedSelectedItems.map((item) => SelectedCartItem.create({ ...item, audit })); const selectedCartItemsDataModel = selectedItems.map((item) => this.selectedItemMapper.toPersistence(item)); - const savedSelectedCartItems: Result = await this.selectedCartItemRepository.insertMany( - selectedCartItemsDataModel, - ); - if (!savedSelectedCartItems.isSuccess) { - throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Error while creating order'); - } + await this.selectedCartItemRepository.insertMany(selectedCartItemsDataModel); await session.commitTransaction(); const response = OrderParser.createOrderResponse(savedOrder); return Result.ok(response); From 2bd6071dcb04373839cf1fcd71c3cf334f39be8f Mon Sep 17 00:00:00 2001 From: ola Date: Sun, 29 Oct 2023 16:55:13 +0800 Subject: [PATCH 18/19] create the create order service --- backend/src/cart/cart-item.mapper.ts | 56 ++++++++++--------- backend/src/cart/cart-item.ts | 1 + .../selected-cart-item.mapper.ts | 3 +- .../repositories/menu.repopsitory.ts | 1 + .../selected-cart-item.repository.ts | 1 + .../mongoDB/generic-document.repository.ts | 9 ++- .../filters/exception.filter.ts | 8 +-- backend/src/merchant/merchant.service.ts | 1 + backend/src/order/index.ts | 7 +++ backend/src/order/order.controller.ts | 2 +- backend/src/order/order.mapper.ts | 4 +- backend/src/order/order.module.ts | 12 +++- backend/src/order/order.service.ts | 31 +++++++--- backend/src/restaurant/restaurant.service.ts | 1 + 14 files changed, 84 insertions(+), 53 deletions(-) diff --git a/backend/src/cart/cart-item.mapper.ts b/backend/src/cart/cart-item.mapper.ts index 3d590884..117ebc77 100644 --- a/backend/src/cart/cart-item.mapper.ts +++ b/backend/src/cart/cart-item.mapper.ts @@ -14,39 +14,41 @@ export class CartItemMapper implements IMapper { private readonly selectedCartItemMapper: SelectedCartItemMapper, ) {} toPersistence(entity: CartItem): CartItemDataModel { - const { id, menuId, orderId, total, selectedItems, audit } = entity; - const { - auditCreatedBy, - auditCreatedDateTime, - auditModifiedBy, - auditModifiedDateTime, - auditDeletedBy, - auditDeletedDateTime, - } = audit; - let selectedItemsToPersistence: SelectedCartItemDataModel[] = []; - if (selectedItems.length) { - selectedItemsToPersistence = selectedItems.map((item) => this.selectedCartItemMapper.toPersistence(item)); + try { + const { id, menuId, orderId, total, selectedItems, audit } = entity; + const { + auditCreatedBy, + auditCreatedDateTime, + auditModifiedBy, + auditModifiedDateTime, + auditDeletedBy, + auditDeletedDateTime, + } = audit; + const cartItemDocument: CartItemDataModel = { + _id: id, + menuId, + orderId, + total, + selectedItems: selectedItems?.length + ? selectedItems.map((item) => this.selectedCartItemMapper.toPersistence(item)) + : [], + auditCreatedBy, + auditCreatedDateTime, + auditModifiedBy, + auditModifiedDateTime, + auditDeletedBy, + auditDeletedDateTime, + }; + return cartItemDocument; + } catch (error) { + console.log(error); } - const cartItemDocument: CartItemDataModel = { - _id: id, - menuId, - orderId, - total, - selectedItems: selectedItemsToPersistence, - auditCreatedBy, - auditCreatedDateTime, - auditModifiedBy, - auditModifiedDateTime, - auditDeletedBy, - auditDeletedDateTime, - }; - return cartItemDocument; } toDomain(model: CartItemDataModel): CartItem { const { _id, menuId, orderId, total, selectedItems } = model; let selectedItemsToDomain: SelectedCartItem[] = []; - if (selectedItems.length) { + if (selectedItems?.length) { selectedItemsToDomain = selectedItems.map((item) => this.selectedCartItemMapper.toDomain(item)); } const entity: CartItem = CartItem.create( diff --git a/backend/src/cart/cart-item.ts b/backend/src/cart/cart-item.ts index 30ba4131..5e06a513 100644 --- a/backend/src/cart/cart-item.ts +++ b/backend/src/cart/cart-item.ts @@ -16,6 +16,7 @@ export class CartItem extends Entity implements ICartItem { this._orderId = props.orderId; this._total = props.total; this._selectedItems = props.selectedItems; + this._audit = props.audit; } get menuId(): Types.ObjectId { diff --git a/backend/src/cart/selectedItems/selected-cart-item.mapper.ts b/backend/src/cart/selectedItems/selected-cart-item.mapper.ts index 0a6220c3..55c59479 100644 --- a/backend/src/cart/selectedItems/selected-cart-item.mapper.ts +++ b/backend/src/cart/selectedItems/selected-cart-item.mapper.ts @@ -4,7 +4,6 @@ import { SelectedCartItemDataModel } from 'src/infrastructure/data_access/reposi import { SelectedCartItem } from './selectedCartItem'; export class SelectedCartItemMapper implements IMapper { - constructor(private readonly auditMapper: AuditMapper) {} toPersistence(entity: SelectedCartItem): SelectedCartItemDataModel { const { id, cartItemId, itemId, price, quantity, menuId, audit } = entity; const { @@ -41,7 +40,7 @@ export class SelectedCartItemMapper implements IMapper imp options?: QueryOptions, ): Promise> { const documents = await this.DocumentModel.find(query, select, options) - .skip(options.skip) - .limit(options.limit) + .skip(options ? options.skip : null) + .limit(options ? options.limit : null) .lean() .exec(); const entities = documents?.length ? documents.map((document) => this.mapper.toDomain(document)) : []; @@ -148,10 +148,13 @@ export abstract class GenericDocumentRepository imp try { const documentsToSave = docs.map((doc) => this.createDocument(doc)); const documents = await this.DocumentModel.insertMany(documentsToSave); + if (!documents?.length) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to insert documents into the database'); + } const entities: TEntity[] = documents.map((doc) => this.mapper.toDomain(doc)); return Result.ok(entities); } catch (error) { - throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to insert documents into the database'); + console.error(error); } } diff --git a/backend/src/infrastructure/filters/exception.filter.ts b/backend/src/infrastructure/filters/exception.filter.ts index a6e6ed67..be7e3520 100644 --- a/backend/src/infrastructure/filters/exception.filter.ts +++ b/backend/src/infrastructure/filters/exception.filter.ts @@ -5,16 +5,13 @@ import { TYPES } from '../../application/constants'; import { IContextAwareLogger } from '../logger'; import { APIResponseMessage } from './../../application/constants/constants'; import { IExceptionResponse, IRequestException } from './exception-response.interface'; -import { BaseExceptionFilter } from '@nestjs/core'; @Catch() -export class ApplicationExceptionsFilter extends BaseExceptionFilter { +export class ApplicationExceptionsFilter implements ExceptionFilter { constructor( @Inject(TYPES.IApplicationLogger) private readonly logger: IContextAwareLogger, - ) { - super(); - } + ) {} catch(exception: any, host: ArgumentsHost) { const context = host.switchToHttp(); const response = context.getResponse(); @@ -42,7 +39,6 @@ export class ApplicationExceptionsFilter extends BaseExceptionFilter { //consider using sentry //https://docs.sentry.io/platforms/node/ //https://dev.to/marcelozapatta/how-to-integrate-sentry-in-nestjs-3ema - super.catch(exception, host); response.status(statusCode).json(responseBody); return exception; } diff --git a/backend/src/merchant/merchant.service.ts b/backend/src/merchant/merchant.service.ts index 37b702ce..806f029c 100644 --- a/backend/src/merchant/merchant.service.ts +++ b/backend/src/merchant/merchant.service.ts @@ -83,6 +83,7 @@ export class MerchantService extends AuthService implements IMerchantService { } return Result.ok(MerchantParser.createMerchantResponse(merchant)); } + ß; async getMerchants(): Promise> { const isValidUser = await this.validateContext(); diff --git a/backend/src/order/index.ts b/backend/src/order/index.ts index e69de29b..30da9724 100644 --- a/backend/src/order/index.ts +++ b/backend/src/order/index.ts @@ -0,0 +1,7 @@ +export * from './order'; +export * from './order-entity.interface'; +export * from './order.controller'; +export * from './order.mapper'; +export * from './order.module'; +export * from './order.parser'; +export * from './order.service'; diff --git a/backend/src/order/order.controller.ts b/backend/src/order/order.controller.ts index a6ce5cf0..2b5fade1 100644 --- a/backend/src/order/order.controller.ts +++ b/backend/src/order/order.controller.ts @@ -9,7 +9,7 @@ import { Result } from 'src/domain'; export class OrderController { constructor(@Inject(TYPES.IOrderService) private readonly orderService: IOrderService) {} - @Post() + @Post('create') async create(@Body() request: CreateOrderDTO): Promise> { return this.orderService.createOrder(request); } diff --git a/backend/src/order/order.mapper.ts b/backend/src/order/order.mapper.ts index 1d5ee857..d8386561 100644 --- a/backend/src/order/order.mapper.ts +++ b/backend/src/order/order.mapper.ts @@ -25,7 +25,7 @@ export class OrderMapper implements IMapper { merchantId, total, discount, - cartItems: cartItems.map((cartItem) => this.cartItemMapper.toPersistence(cartItem)), + cartItems: cartItems?.length ? cartItems.map((cartItem) => this.cartItemMapper.toPersistence(cartItem)) : [], orderManagerId, auditCreatedBy, auditCreatedDateTime, @@ -48,7 +48,7 @@ export class OrderMapper implements IMapper { discount, orderManagerId, audit: this.auditMapper.toDomain(model), - cartItems: cartItems.map((cartItem) => this.cartItemMapper.toDomain(cartItem)), + cartItems: cartItems?.length ? cartItems.map((cartItem) => this.cartItemMapper.toDomain(cartItem)) : [], }, _id, ); diff --git a/backend/src/order/order.module.ts b/backend/src/order/order.module.ts index b286901b..10031b7f 100644 --- a/backend/src/order/order.module.ts +++ b/backend/src/order/order.module.ts @@ -1,4 +1,4 @@ -import { Module } from '@nestjs/common'; +import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { MongooseModule } from '@nestjs/mongoose'; import { TYPES } from 'src/application'; @@ -26,6 +26,8 @@ import { MerchantMapper, MerchantService } from 'src/merchant'; import { ValidateUser } from 'src/utils'; import { OrderMapper } from './order.mapper'; import { OrderService } from './order.service'; +import { OrderController } from './order.controller'; +import { ContextMiddleWare } from 'src/infrastructure/middlewares'; @Module({ imports: [ @@ -37,7 +39,7 @@ import { OrderService } from './order.service'; { name: SelectedCartItemDataModel.name, schema: SelectedCartItemSchema }, ]), ], - controllers: [], + controllers: [OrderController], providers: [ { provide: TYPES.IOrderService, useClass: OrderService }, { provide: TYPES.IOrderRepository, useClass: OrderRepository }, @@ -55,4 +57,8 @@ import { OrderService } from './order.service'; AuditMapper, ], }) -export class OrderModule {} +export class OrderModule implements NestModule { + configure(consumer: MiddlewareConsumer) { + consumer.apply(ContextMiddleWare).exclude().forRoutes(OrderController); + } +} diff --git a/backend/src/order/order.service.ts b/backend/src/order/order.service.ts index 9a2a3b65..1bf26f6b 100644 --- a/backend/src/order/order.service.ts +++ b/backend/src/order/order.service.ts @@ -55,7 +55,7 @@ export class OrderService implements IOrderService { const orderToSave: Result = await this.orderRepository.createOrder(orderModel); const savedOrder = orderToSave.getValue(); const orderId = savedOrder.id; - if (cartItems) { + if (cartItems?.length) { const items = cartItems.map((item) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { selectedItems, ...otherItemProperties } = item; @@ -65,26 +65,39 @@ export class OrderService implements IOrderService { const savedCartItems: Result = await this.cartItemRepository.insertMany(cartItemDataModels); const savedItems = savedCartItems.getValue(); - const cartItemMap = new Map(); - savedItems.forEach((item) => cartItemMap.set(item.menuId, item.id)); + const cartItemMap = savedItems.reduce((map, item) => { + map.set(this.orderRepository.objectIdToString(item.menuId), this.orderRepository.objectIdToString(item.id)); + return map; + }, new Map()); const cartSelectedItems = cartItems.map((item) => item.selectedItems); const flattenedSelectedItems = cartSelectedItems.flat(); flattenedSelectedItems.forEach((item) => { - if (cartItemMap.has(item.menuId)) { - item.cartItemId = cartItemMap.get(item.menuId); + console.log(item.menuId); + if (cartItemMap.has(this.orderRepository.objectIdToString(item.menuId))) { + item.cartItemId = this.orderRepository.stringToObjectId( + cartItemMap.get(this.orderRepository.objectIdToString(item.menuId)), + ); } }); const selectedItems = flattenedSelectedItems.map((item) => SelectedCartItem.create({ ...item, audit })); const selectedCartItemsDataModel = selectedItems.map((item) => this.selectedItemMapper.toPersistence(item)); - await this.selectedCartItemRepository.insertMany(selectedCartItemsDataModel); - await session.commitTransaction(); - const response = OrderParser.createOrderResponse(savedOrder); + const insertedItems: Result = await this.selectedCartItemRepository.insertMany( + selectedCartItemsDataModel, + ); + let response: IOrderResponseDTO | undefined; + if (insertedItems.isSuccess) { + response = OrderParser.createOrderResponse(savedOrder); + } else { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, `Could not create an order`); + } return Result.ok(response); } } catch (error) { session.abortTransaction(); - throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, JSON.stringify(error)); + } finally { + await session.commitTransaction(); + await session.endSession(); } } } diff --git a/backend/src/restaurant/restaurant.service.ts b/backend/src/restaurant/restaurant.service.ts index fa81ceb7..1ce05fd8 100644 --- a/backend/src/restaurant/restaurant.service.ts +++ b/backend/src/restaurant/restaurant.service.ts @@ -85,6 +85,7 @@ export class RestaurantService implements IRestaurantService { return Result.ok(RestaurantParser.createRestaurantResponse(response)); } catch (error) { await session.abortTransaction(); + console.error(error); } finally { session.endSession(); } From b4f6733234545e2418ecf061d9896351cd675d3b Mon Sep 17 00:00:00 2001 From: ola Date: Mon, 30 Oct 2023 00:18:48 +0800 Subject: [PATCH 19/19] create order --- .github/workflows/workflow.yml | 9 ++++ backend/src/application/constants/types.ts | 1 + backend/src/cart/cart-item.ts | 2 +- .../repositories/cart-item.repository.ts | 21 ++++++-- .../cart-item-repository.interface.ts | 7 +++ .../mongoDB/generic-document.interface.ts | 2 +- .../mongoDB/generic-document.repository.ts | 54 ++++++++++++++----- backend/src/order/order.module.ts | 1 + backend/src/order/order.service.ts | 33 +++++++++--- 9 files changed, 106 insertions(+), 24 deletions(-) create mode 100644 backend/src/infrastructure/data_access/repositories/interfaces/cart-item-repository.interface.ts diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 80172490..e56b93a6 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -37,3 +37,12 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + - name: ChatGPT comment + uses: kxxt/chatgpt-action@v0.3 + id: chatgpr + with: + number: ${{ github.event.pull_request.number }} + sessionToken: ${{ secrets.CHATGPT_SESSION_TOKEN }} + split: "yolo" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/backend/src/application/constants/types.ts b/backend/src/application/constants/types.ts index e529bb75..7105f07e 100644 --- a/backend/src/application/constants/types.ts +++ b/backend/src/application/constants/types.ts @@ -22,4 +22,5 @@ export const TYPES = { IAddonRepository: Symbol('IAddonRepository'), IOrderRepository: Symbol('IOrderRepository'), IOrderService: Symbol('IOrderService'), + ICartItemRepository: Symbol('ICartItemRepository'), }; diff --git a/backend/src/cart/cart-item.ts b/backend/src/cart/cart-item.ts index 5e06a513..0c0ac9e7 100644 --- a/backend/src/cart/cart-item.ts +++ b/backend/src/cart/cart-item.ts @@ -47,7 +47,7 @@ export class CartItem extends Entity implements ICartItem { return this._selectedItems; } - set setSelectedItems(selectedItems: SelectedCartItem[] | undefined) { + set selectedItems(selectedItems: SelectedCartItem[] | undefined) { this._selectedItems = selectedItems; } diff --git a/backend/src/infrastructure/data_access/repositories/cart-item.repository.ts b/backend/src/infrastructure/data_access/repositories/cart-item.repository.ts index a5dfb24a..c038bca3 100644 --- a/backend/src/infrastructure/data_access/repositories/cart-item.repository.ts +++ b/backend/src/infrastructure/data_access/repositories/cart-item.repository.ts @@ -1,13 +1,18 @@ -import { CartItemMapper } from './../../../cart/cart-item.mapper'; import { Injectable } from '@nestjs/common'; +import { InjectConnection, InjectModel } from '@nestjs/mongoose'; +import { Connection, Model } from 'mongoose'; import { CartItem } from 'src/cart/cart-item'; import { GenericDocumentRepository } from 'src/infrastructure/database'; +import { CartItemMapper } from './../../../cart/cart-item.mapper'; +import { ICartItemRepository } from './interfaces/cart-item-repository.interface'; import { CartItemDataModel, CartItemDocument } from './schemas/cartItem.schema'; -import { InjectConnection, InjectModel } from '@nestjs/mongoose'; -import { Connection, Model } from 'mongoose'; +import { Result } from 'src/domain'; @Injectable() -export class CartItemRepository extends GenericDocumentRepository { +export class CartItemRepository + extends GenericDocumentRepository + implements ICartItemRepository +{ cartItemMapper: CartItemMapper; constructor( @InjectModel(CartItemDataModel.name) cartItemDataModel: Model, @@ -15,5 +20,13 @@ export class CartItemRepository extends GenericDocumentRepository { + const document = cartItems.map((doc) => this.cartItemMapper.toPersistence(doc)); + document.forEach((item) => { + this.updateOne({ _id: item._id }, { selectedItems: item.selectedItems }); + }); } } diff --git a/backend/src/infrastructure/data_access/repositories/interfaces/cart-item-repository.interface.ts b/backend/src/infrastructure/data_access/repositories/interfaces/cart-item-repository.interface.ts new file mode 100644 index 00000000..6c6177ec --- /dev/null +++ b/backend/src/infrastructure/data_access/repositories/interfaces/cart-item-repository.interface.ts @@ -0,0 +1,7 @@ +import { CartItem } from 'src/cart/cart-item'; +import { IGenericDocument } from 'src/infrastructure/database'; +import { CartItemDocument } from '../schemas/cartItem.schema'; + +export interface ICartItemRepository extends IGenericDocument { + updateCartItemSelectedItems(cartItems: CartItem[]): Promise; +} diff --git a/backend/src/infrastructure/database/mongoDB/generic-document.interface.ts b/backend/src/infrastructure/database/mongoDB/generic-document.interface.ts index 8ecd66da..ef16cd74 100644 --- a/backend/src/infrastructure/database/mongoDB/generic-document.interface.ts +++ b/backend/src/infrastructure/database/mongoDB/generic-document.interface.ts @@ -16,7 +16,7 @@ export interface IGenericDocument { findOneAndUpdate(filterQuery: FilterQuery, update: UpdateQuery): Promise>; - upsert(filterQuery: FilterQuery, document: Partial): Promise; + upsert(filterQuery: FilterQuery, document: Partial): Promise>; deleteMany(filterQuery: FilterQuery): Promise; diff --git a/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts b/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts index 89130465..9c48f9e4 100644 --- a/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts +++ b/backend/src/infrastructure/database/mongoDB/generic-document.repository.ts @@ -75,13 +75,20 @@ export abstract class GenericDocumentRepository imp select?: ProjectionType, options?: QueryOptions, ): Promise> { - const documents = await this.DocumentModel.find(query, select, options) - .skip(options ? options.skip : null) - .limit(options ? options.limit : null) - .lean() - .exec(); - const entities = documents?.length ? documents.map((document) => this.mapper.toDomain(document)) : []; - return Result.ok(entities); + try { + const documents = await this.DocumentModel.find(query, select, options) + .skip(options ? options.skip : null) + .limit(options ? options.limit : null) + .lean() + .exec(); + if (!documents?.length) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'documents does not exist'); + } + const entities = documents?.length ? documents.map((document) => this.mapper.toDomain(document)) : []; + return Result.ok(entities); + } catch (error) { + console.error(error); + } } async pagination(query: FilterQuery, select: ProjectionType, options: QueryOptions) { @@ -116,7 +123,7 @@ export abstract class GenericDocumentRepository imp return Result.ok(entity); } - async upsert(filterQuery: FilterQuery, document: Partial): Promise { + async upsert(filterQuery: FilterQuery, document: Partial): Promise> { const result = await this.DocumentModel.findOneAndUpdate(filterQuery, document, { lean: true, upsert: true, @@ -127,7 +134,7 @@ export abstract class GenericDocumentRepository imp return Result.fail('Unable to update the database', HttpStatus.INTERNAL_SERVER_ERROR); } const entity = this.mapper.toDomain(result); - return entity; + return Result.ok(entity); } async deleteMany(filterQuery: FilterQuery): Promise { @@ -159,9 +166,32 @@ export abstract class GenericDocumentRepository imp } async updateOne(filter: any, query: any): Promise> { - const document = await this.DocumentModel.updateOne(filter, { $set: query }); - const entity: TEntity = this.mapper.toDomain(document as any); - return Result.ok(entity); + try { + const document = await this.DocumentModel.updateOne(filter, { $set: query }); + if (!document) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to update document in the database'); + } + const entity: TEntity = this.mapper.toDomain(document as any); + return Result.ok(entity); + } catch (error) { + console.error(error); + } + } + + async updateMany(query: FilterQuery, updateBody: UpdateQuery): Promise> { + try { + const saved = await this.DocumentModel.updateMany(query, updateBody, { + multi: true, + }); + if (saved.matchedCount < 1) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to update documents into the database'); + } + const updatedDocuments = await this.DocumentModel.find(query); + const entities: TEntity[] = updatedDocuments.map((doc) => this.mapper.toDomain(doc)); + return Result.ok(entities); + } catch (error) { + console.error(error); + } } createDocument(document: any) { diff --git a/backend/src/order/order.module.ts b/backend/src/order/order.module.ts index 10031b7f..a0efacc8 100644 --- a/backend/src/order/order.module.ts +++ b/backend/src/order/order.module.ts @@ -42,6 +42,7 @@ import { ContextMiddleWare } from 'src/infrastructure/middlewares'; controllers: [OrderController], providers: [ { provide: TYPES.IOrderService, useClass: OrderService }, + { provide: TYPES.ICartItemRepository, useClass: CartItemRepository }, { provide: TYPES.IOrderRepository, useClass: OrderRepository }, { provide: TYPES.IMerchantService, useClass: MerchantService }, { provide: TYPES.IContextService, useClass: ContextService }, diff --git a/backend/src/order/order.service.ts b/backend/src/order/order.service.ts index 1bf26f6b..969321d3 100644 --- a/backend/src/order/order.service.ts +++ b/backend/src/order/order.service.ts @@ -20,6 +20,7 @@ import { Order } from './order'; import { IOrderResponseDTO } from './order-response.dto'; import { OrderMapper } from './order.mapper'; import { OrderParser } from './order.parser'; +import { ICartItemRepository } from 'src/infrastructure/data_access/repositories/interfaces/cart-item-repository.interface'; export class OrderService implements IOrderService { private context: Context; @@ -29,11 +30,11 @@ export class OrderService implements IOrderService { @Inject(TYPES.IContextService) private readonly contextService: IContextService, private readonly merchantRepository: MerchantRepository, - private readonly cartItemRepository: CartItemRepository, private readonly selectedCartItemRepository: SelectedCartItemRepository, private readonly orderMapper: OrderMapper, private readonly selectedItemMapper: SelectedCartItemMapper, private readonly cartItemMapper: CartItemMapper, + @Inject(TYPES.ICartItemRepository) private readonly cartItemRepository: ICartItemRepository, ) { this.context = this.contextService.getContext(); } @@ -64,6 +65,14 @@ export class OrderService implements IOrderService { const cartItemDataModels: CartItemDataModel[] = items.map((item) => this.cartItemMapper.toPersistence(item)); const savedCartItems: Result = await this.cartItemRepository.insertMany(cartItemDataModels); const savedItems = savedCartItems.getValue(); + savedOrder.cartItems = savedItems; + const orderWithCartItems = await this.orderRepository.upsert( + { _id: orderId }, + this.orderMapper.toPersistence(savedOrder), + ); + if (orderWithCartItems.isSuccess === false) { + throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, `Error while creating order`); + } const cartItemMap = savedItems.reduce((map, item) => { map.set(this.orderRepository.objectIdToString(item.menuId), this.orderRepository.objectIdToString(item.id)); @@ -73,13 +82,12 @@ export class OrderService implements IOrderService { const cartSelectedItems = cartItems.map((item) => item.selectedItems); const flattenedSelectedItems = cartSelectedItems.flat(); flattenedSelectedItems.forEach((item) => { - console.log(item.menuId); if (cartItemMap.has(this.orderRepository.objectIdToString(item.menuId))) { - item.cartItemId = this.orderRepository.stringToObjectId( - cartItemMap.get(this.orderRepository.objectIdToString(item.menuId)), - ); + const cartItemId = cartItemMap.get(this.orderRepository.objectIdToString(item.menuId)); + item.cartItemId = this.orderRepository.stringToObjectId(cartItemId); } }); + const selectedItems = flattenedSelectedItems.map((item) => SelectedCartItem.create({ ...item, audit })); const selectedCartItemsDataModel = selectedItems.map((item) => this.selectedItemMapper.toPersistence(item)); const insertedItems: Result = await this.selectedCartItemRepository.insertMany( @@ -91,12 +99,25 @@ export class OrderService implements IOrderService { } else { throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, `Could not create an order`); } + + const savedSelectedItems = insertedItems.getValue(); + const savedItemsMap = savedSelectedItems.reduce((map, item) => { + const cartItemIdToString = this.cartItemRepository.objectIdToString(item.cartItemId); + !map.has(cartItemIdToString) ? map.set(cartItemIdToString, [item]) : map.get(cartItemIdToString).push(item); + return map; + }, new Map()); + savedItems.forEach((item) => { + if (savedItemsMap.has(this.cartItemRepository.objectIdToString(item.id))) { + item.selectedItems = savedItemsMap.get(this.cartItemRepository.objectIdToString(item.id)); + } + }); + await this.cartItemRepository.updateCartItemSelectedItems(savedItems); + await session.commitTransaction(); return Result.ok(response); } } catch (error) { session.abortTransaction(); } finally { - await session.commitTransaction(); await session.endSession(); } }