diff --git a/libs/services/common/src/index.ts b/libs/services/common/src/index.ts index d25279e..b2d3906 100644 --- a/libs/services/common/src/index.ts +++ b/libs/services/common/src/index.ts @@ -1,5 +1,7 @@ export * from './lib/services-common'; export * from './lib/group/groupService'; +export * from './lib/offer/catalogue.service'; +export * from './lib/offer/offer.service'; export * from './lib/table/table.service'; export * from './lib/apis/diningApiService'; export * from './lib/container'; diff --git a/libs/services/common/src/lib/container.ts b/libs/services/common/src/lib/container.ts index 3b35536..2db79fe 100644 --- a/libs/services/common/src/lib/container.ts +++ b/libs/services/common/src/lib/container.ts @@ -6,6 +6,7 @@ import { TYPES } from "./types"; import { MenuApiService } from "./apis/menuApiService"; import { OfferService } from "./offer/offer.service"; import { GroupServiceWorkflow } from "./group/groupServiceWorkflow"; +import { CatalogService } from "./offer/catalogue.service"; import { GroupService } from "./group/groupService"; const container = new Container(); @@ -14,5 +15,6 @@ container.bind(TYPES.TableService).to(TableService).inSingletonSco container.bind(TYPES.DiningApiService).to(DiningApiService).inSingletonScope(); container.bind(TYPES.MenuApiService).to(MenuApiService).inSingletonScope(); container.bind(TYPES.OfferService).to(OfferService).inSingletonScope(); +container.bind(TYPES.CatalogService).to(CatalogService).inSingletonScope(); export { container }; diff --git a/libs/services/common/src/lib/offer/catalogue.service.ts b/libs/services/common/src/lib/offer/catalogue.service.ts index e42b337..1bba148 100644 --- a/libs/services/common/src/lib/offer/catalogue.service.ts +++ b/libs/services/common/src/lib/offer/catalogue.service.ts @@ -18,7 +18,7 @@ export class CatalogService { async getFilteredCatalog(offerName: string) { const offer = await this.offerService.getOffers().then(response => - response.find(element => element.name.toLowerCase() === offerName.toLowerCase()) + response.find(element => element.name?.toLowerCase() === offerName?.toLowerCase()) ); if (!offer) return {}; @@ -27,17 +27,22 @@ export class CatalogService { item => offer.availableItems.includes(item._id) ); - const categorizedCatalog : CategorizedCatalog = {}; + const categorizedCatalog: CategorizedCatalog = {}; availableCatalog.forEach(element => { - if (element.category in categorizedCatalog) { - categorizedCatalog[element.category] = [element]; - } - else { - categorizedCatalog[element.category].push(element); + if (!categorizedCatalog[element.category]) { + categorizedCatalog[element.category] = []; } + categorizedCatalog[element.category].push(element); }); return categorizedCatalog; } + + + async getFullItemFromItemIdsArray(idList: string[]) { + return (await this.menuApiService.getMenuApi().menusControllerGetFullMenu()).data.filter( + item => idList.includes(item._id) + ); + } } diff --git a/libs/services/common/src/lib/types.ts b/libs/services/common/src/lib/types.ts index 007c0a3..4f114b9 100644 --- a/libs/services/common/src/lib/types.ts +++ b/libs/services/common/src/lib/types.ts @@ -1,11 +1,10 @@ -import { OfferService } from "./offer/offer.service"; - export const TYPES = { GroupService: Symbol.for('GroupService'), TableService: Symbol.for('TableService'), DiningApiService: Symbol.for('DiningApiService'), MenuApiService: Symbol.for('MenuApiService'), OfferService: Symbol.for('OfferService'), + CatalogService: Symbol.for('CatalogService'), BackendBffApiService: Symbol.for('BackendBffApiService'), }; diff --git a/libs/ui/common/src/lib/commandsR/commands.tsx b/libs/ui/common/src/lib/commandsR/commands.tsx index 7704bc0..7767486 100644 --- a/libs/ui/common/src/lib/commandsR/commands.tsx +++ b/libs/ui/common/src/lib/commandsR/commands.tsx @@ -1,9 +1,9 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import { Box, SpeedDial } from '@mui/material'; import NavBar from '../utils/navbar'; import Orders from '../orders/orders'; import BackButton from '../utils/backButton'; -import OrderingChoices from './orederingChoices'; +import OrderingChoices from './orderingChoices'; import { setSelectedTableById, tablesMenu } from '../utils/tableUtils'; //SpeedDial imports import SpeedDialIcon from '@mui/material/SpeedDialIcon'; @@ -13,14 +13,16 @@ import GroupsIcon from '@mui/icons-material/Groups'; import CloseIcon from '@mui/icons-material/Close'; import DollarIcon from '@mui/icons-material/AttachMoney'; import { useNavigate, useParams } from 'react-router-dom'; -import { useTableSummary } from './stores/tableSummary'; import Summary from '../summary/summary'; +import { useCarts } from './stores/cart'; export function Commands() { const navigate = useNavigate(); const {groupId} = useParams(); const [selectedTable, setSelectedTable] = useState(tablesMenu[0]); - const haveCurrentCommand = useTableSummary(state=>state.tables).length > 0; + const haveCurrentCommand = (useCarts(state => state.carts)[selectedTable.id] ?? []).length > 0; + + const offerType = "Classic"; const speedDialActions = [ { icon: , name: 'Table Payment', operation: onClickTableBilling }, @@ -78,9 +80,9 @@ export function Commands() { - {selectedTable && } - {haveCurrentCommand && } - {!haveCurrentCommand && } + {selectedTable && } + {haveCurrentCommand && } + {!haveCurrentCommand && } diff --git a/libs/ui/common/src/lib/commandsR/orderingChoices.tsx b/libs/ui/common/src/lib/commandsR/orderingChoices.tsx new file mode 100644 index 0000000..ff47e69 --- /dev/null +++ b/libs/ui/common/src/lib/commandsR/orderingChoices.tsx @@ -0,0 +1,156 @@ +import React, { useState } from 'react'; +import { Box, Button, Typography } from '@mui/material'; +import './orderingChoices.css'; +import { useCarts } from './stores/cart'; +import { useQuery } from '@tanstack/react-query'; +import { ContainerContext } from '../containerHook/containerContext'; +import { CatalogService, TYPES } from '@spos/services/common'; + +interface OrderingChoicesProps { + tableNumber: number, + offerType: string +} + +type Cart = { + itemId: string; + quantity: number; +}[] + +export function OrderingChoices(props: Readonly) { + const currentTableCart: Cart = (useCarts(state => state.carts)[props.tableNumber] || []); + console.table(currentTableCart); + const container = React.useContext(ContainerContext); + + const updateItem = useCarts(state => state.updateItem); + + const { + data: catalog, + isLoading, + isError, + error, + } = useQuery({ + queryKey: ['catalog'], + queryFn: async () => { + const catalogService : CatalogService = container.get(TYPES.CatalogService); + console.log('', catalogService); + return catalogService.getFilteredCatalog(props.offerType); + }, + refetchOnWindowFocus: 'always', + }); + + if(isError) { + console.log(error); + return ( + + Help + + ); + } + + if (isLoading) { + return ( + + Loading + + ); + } + + if (!catalog) { + return ( + + Loading + + ); + } + + function handleSelectItem(itemId: string) { + if (currentTableCart.find(element => element.itemId === itemId) !== undefined) { + updateItem(props.tableNumber, itemId, 0); + } + else { + updateItem(props.tableNumber, itemId, 1); + } + } + + function handleDecrease(itemId: string) { + const quantity = currentTableCart.find(element => element.itemId === itemId)?.quantity; + if (quantity !== undefined && quantity > 0) { + updateItem(props.tableNumber, itemId, quantity-1); + } + } + + function handleIncrease(itemId: string) { + const quantity = currentTableCart.find(element => element.itemId === itemId)?.quantity; + updateItem(props.tableNumber, itemId,(quantity !== undefined) ? quantity+1 : 1); + } + + return ( + + {Object.keys(catalog).map((category) => ( + + {category} + + {catalog[category].length > 0 ? ( + catalog[category].map((item) => { + const count = currentTableCart.find(element => element.itemId === item._id)?.quantity ?? 0; + const isSelected = Boolean(currentTableCart.find(element => element.itemId === item._id)); + + return ( + + + {isSelected && ( + + + {count} + + + )} + + ); + }) + ) : ( + No Choices + )} + + + ))} + + ); +}; + +export default OrderingChoices; + diff --git a/libs/ui/common/src/lib/commandsR/orederingChoices.tsx b/libs/ui/common/src/lib/commandsR/orederingChoices.tsx deleted file mode 100644 index f19a6d8..0000000 --- a/libs/ui/common/src/lib/commandsR/orederingChoices.tsx +++ /dev/null @@ -1,184 +0,0 @@ -import React, { useState } from 'react'; -import { Box, Button, Typography } from '@mui/material'; -import './orderingChoices.css'; -import { useCurrentSelectedOrder } from './stores/currentSelectedOrder'; -import { useTableSummary } from './stores/tableSummary'; -import { classicMenu } from '../utils/tableUtils'; - -export const OrderingChoices = ({ selectedTable }) => { - const { orders, id: tableId } = selectedTable; - const { setOrder } = useCurrentSelectedOrder(); - - const [selectedOrders, setSelectedOrders] = useState({}); - const addOrUpdateOrder = useTableSummary(state=>state.addOrUpdateOrder); - const decreaseOrderQuantity = useTableSummary(state=>state.decreaseOrderQuantity); - const tables = useTableSummary(state=>state.tables); - console.log(tables); - - const handleSelectOrder = (category, index) => { - - setSelectedOrders(prev => { - const isSelected = prev[tableId]?.[category]?.[index]; - - if (isSelected) { - const { [index]: removed, ...rest } = prev[tableId][category]; - return { - ...prev, - [tableId]: { - ...prev[tableId], - [category]: rest, - }, - }; - } else { - return { - ...prev, - [tableId]: { - ...prev[tableId], - [category]: { - ...prev[tableId]?.[category], - [index]: { count: 0 } - } - } - }; - } - }); - }; - - const handleIncrease = (category, index) => { - setSelectedOrders(prev => { - const currentCount = prev[tableId]?.[category]?.[index]?.count || 0; - const newCount = currentCount + 1; - - setOrder(category, index, newCount); - const order = { - category: category, - name: classicMenu?.[category]?.[index], - quantity: 1, - price: 2.5, - } - addOrUpdateOrder(tableId, order); - - //const [tableSummaryContent, arrayId] = getTableIfExist(summaryContent); - //Add to orders - - //summaryContent[arrayId] = tableSummaryContent; - //setSummaryContent(summaryContent); - - - - return { - ...prev, - [tableId]: { - ...prev[tableId], - [category]: { - ...prev[tableId]?.[category], - [index]: { count: newCount } - } - } - }; - }); - }; - - const handleDecrease = (category, index) => { - setSelectedOrders(prev => { - const currentCount = prev[tableId]?.[category]?.[index]?.count || 0; - const newCount = Math.max(0, currentCount - 1); - - setOrder(category, index, newCount); - const order = { - category: category, - name: classicMenu?.[category]?.[index], - quantity: 1, - price: 2.5, - } - decreaseOrderQuantity(tableId, order) - - return { - ...prev, - [tableId]: { - ...prev[tableId], - [category]: { - ...prev[tableId]?.[category], - [index]: { count: newCount } - } - } - }; - }); - }; - - return ( - - {Object.keys(orders).map((category) => ( - - {category} - - {orders[category].length > 0 ? ( - orders[category].map((order, index) => { - const count = selectedOrders[tableId]?.[category]?.[index]?.count || 0; - const isSelected = Boolean(selectedOrders[tableId]?.[category]?.[index]); - - return ( - - - {isSelected && ( - - - {count} - - - )} - - ); - }) - ) : ( - No Choices - )} - - - ))} - - ); -}; - -export default OrderingChoices; - - - -function getTableIfExist(summaryContent): [any, any] { - throw new Error('Function not implemented.'); -} - diff --git a/libs/ui/common/src/lib/commandsR/stores/cart.ts b/libs/ui/common/src/lib/commandsR/stores/cart.ts index ce8516c..6094dd8 100644 --- a/libs/ui/common/src/lib/commandsR/stores/cart.ts +++ b/libs/ui/common/src/lib/commandsR/stores/cart.ts @@ -16,16 +16,16 @@ export const useCarts = create((set) => ({ return { carts: { ...state.carts, - tableNumber: + [tableNumber]: // Use square brackets to use the variable `tableNumber` as a key (itemIndex === -1) ? [...currentCart, {itemId, quantity}].filter(element => element.quantity > 0) : currentCart.map(element => { if (element.itemId === itemId) { - element.quantity = quantity + element.quantity = quantity; } - return element + return element; }).filter(element => element.quantity > 0) } - } + }; }), resetCart: (tableNumber) => set((state) => ({ diff --git a/libs/ui/common/src/lib/commandsR/stores/tableSummary.tsx b/libs/ui/common/src/lib/commandsR/stores/tableSummary.tsx deleted file mode 100644 index b2163f3..0000000 --- a/libs/ui/common/src/lib/commandsR/stores/tableSummary.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { TableView } from "@mui/icons-material"; -import { create } from "zustand"; - - -// Represents an order for a specific item -interface Order { - category: string; - name: string; - quantity: number; - price: number; -} - -// Represents a table with its orders -interface Table { - id: number; // This is the table number - orders: Order[]; -} - -export interface TableState { - tables: Table[]; - addOrUpdateOrder: (tableId: number, newOrder: Order) => void; - decreaseOrderQuantity: (tableId: number, newOrder: Order) => void; -} - -export const useTableSummary = create((set) => ({ - tables: [], - addOrUpdateOrder: (tableId, newOrder) => - set((state) => ({ - tables: updateTable(state, tableId, newOrder) - })), - decreaseOrderQuantity: (tableId, newOrder) => - set((state) => ({ - tables: decreaseItem(state, tableId, newOrder) - })) -})); - -const updateTable = (state: TableState, tableId: number, newOrder: Order) => { - let tableFound = false; - for(const tableKey in state.tables){ - const table = state.tables[tableKey] - if(table.id === tableId){ - console.log(tableId) - tableFound = true; - const existingOrder = table.orders.find( - (order) => - order.name === newOrder.name && - order.category === newOrder.category - ); - if (existingOrder) { - - return mergeTables(state.tables, { - ...table, - orders: table.orders.map((order) => - order === existingOrder - ? { ...order, quantity: order.quantity + newOrder.quantity } - : order - ) - }); - } else { - // Add new order if not found - return mergeTables(state.tables, { - ...table, - orders: [...table.orders, newOrder] - }); - } - } - } - if(tableFound==false){ - return mergeTables(state.tables, { - "id": tableId, - "orders":[ - newOrder - ] - }) - } - -} - -const decreaseItem = (state: TableState, tableId: number, newOrder: Order) => { - for(const tableKey in state.tables){ - const table = state.tables[tableKey] - if (table.id === tableId) { - const newTable = { - ...table, - orders: table.orders - .map((order) => { - if (order.name === newOrder.name && order.category === newOrder.category) { - // Decrease the quantity or remove the order if the quantity is zero or below - const updatedQuantity = order.quantity - newOrder.quantity; - if (updatedQuantity > 0) { - return { ...order, quantity: updatedQuantity }; - } - return null; // Remove order if quantity becomes zero or less - } - return order; - }) - .filter(Boolean) as Order[] // Remove null values (orders with quantity 0) - }; - return mergeTables(state.tables, newTable); - } - } -} - - - -function mergeTables(tables: Table[], table: Table): any { - // Check if the table with the same id exists - const tableIndex = tables.findIndex(t => t.id === table.id); - if (table.orders.length <1){ - return [ - ...tables.slice(0, tableIndex), - ...tables.slice(tableIndex + 1) - ]; - } - if (tableIndex !== -1) { - // Replace the existing table with the new one - return [ - ...tables.slice(0, tableIndex), - table, - ...tables.slice(tableIndex + 1) - ]; - } else { - // Append the new table to the list - return [...tables, table]; - } -} diff --git a/libs/ui/common/src/lib/orders/orders.tsx b/libs/ui/common/src/lib/orders/orders.tsx index 099d41a..a0d3356 100644 --- a/libs/ui/common/src/lib/orders/orders.tsx +++ b/libs/ui/common/src/lib/orders/orders.tsx @@ -5,9 +5,13 @@ import Section from './section'; import BackButton from '../utils/backButton'; import useStore from './stores/serve'; -export function Orders() { +interface OrdersProps { + groupId: string +} + +export function Orders(props: OrdersProps) { const [open, setOpen] = useState(false); - const [selectedOrder, setSelectedOrder] = useState(null); + const [selectedOrder, setSelectedOrder] = useState(null); const { ordersData, setServed } = useStore(); @@ -30,12 +34,12 @@ export function Orders() { console.log("Selected order:", selectedOrder); const { section, table, orderId } = selectedOrder; setServed(section, table, orderId, true); - console.log("After serving:", ordersData); + console.log("After serving:", ordersData); - setSelectedOrder(null); + setSelectedOrder(null); } }; - + return ( @@ -45,10 +49,10 @@ export function Orders() { variant="contained" color="primary" style={{ - padding: '20px 50px', - borderRadius: '50px', - fontSize: '4vw', - backgroundColor: '#003366' + padding: '20px 50px', + borderRadius: '50px', + fontSize: '4vw', + backgroundColor: '#003366' }} > Orders @@ -57,40 +61,40 @@ export function Orders() { {open && ( - setOpen(false)} color={'white'} top={20} left={20}/> - setOpen(false)} color={'white'} top={20} left={20}/> + Orders - - - - + {Object.keys(ordersData).map((section) => (
))} @@ -101,12 +105,12 @@ export function Orders() { variant="contained" style={{ backgroundColor: '#003366', - padding: '20px 50px', - borderRadius: '50px', - fontSize: '4vw', + padding: '20px 50px', + borderRadius: '50px', + fontSize: '4vw', }} - onClick={handleServe} - disabled={!selectedOrder} + onClick={handleServe} + disabled={!selectedOrder} > Serve diff --git a/libs/ui/common/src/lib/summary/summary.tsx b/libs/ui/common/src/lib/summary/summary.tsx index 55677b5..e06c65f 100644 --- a/libs/ui/common/src/lib/summary/summary.tsx +++ b/libs/ui/common/src/lib/summary/summary.tsx @@ -1,125 +1,144 @@ -import { Category, CenterFocusStrong } from '@mui/icons-material'; import './summary.css'; -import { useNavigate } from "react-router-dom"; -import { Button, Typography, ButtonGroup, Box, Card, CardContent } from "@mui/material"; -import { red } from '@mui/material/colors'; +import { Button, Typography, Box } from "@mui/material"; import * as React from 'react'; import { useState } from 'react'; -import { Router } from 'react-router-dom'; -import NavBar from '../utils/navbar'; -import { setSelectedTableById, tablesMenu } from '../utils/tableUtils'; import BackButton from '../utils/backButton'; -import { useTableSummary, TableState } from '../commandsR/stores/tableSummary' +import { useCarts } from '../commandsR/stores/cart'; +import { ContainerContext } from '../containerHook/containerContext'; +import { useQuery } from '@tanstack/react-query'; +import { CatalogService, TYPES } from '@spos/services/common'; -export function Summary() { - const [open, setOpen] = useState(false); - const navigate = useNavigate(); - const [selectedTable, setSelectedTable] = useState(tablesMenu[1]); - const tablesSummary = useTableSummary(state=>state.tables); - const summaryContent = summaryContentAdapt(tablesSummary); - - function togglePopup(): void { - setOpen(true); - } +interface SummaryProps { + tableNumber: number, + offerType: string +} - return ( - - - - +export function Summary(props: Readonly) { + const [open, setOpen] = useState(false); - {open && ( - < Box className="popup-fullscreen"> - setOpen(false)} color={'white'} top={20} left={20}/> - - Summary - + const cart = useCarts(); + const currentTableCart = cart.carts[props.tableNumber] || []; - - console.log(summaryContent) - console.log("------") - {Object.keys(summaryContent).map((category) => ( - - {category} - {summaryContent[category].map((item, index) => ( - - {item.name}: {item.quantity} - - ))} - - ))} - - - Total : 15€ - - - + function togglePopup(): void { + setOpen(true); + } + const container = React.useContext(ContainerContext); + const { + data: catalog, + isLoading, + isError, + error, + } = useQuery({ + queryKey: ['catalog'], + queryFn: async () => { + const catalogService : CatalogService = container.get(TYPES.CatalogService); + console.log('', catalogService); + return catalogService.getFilteredCatalog(props.offerType); + }, + refetchOnWindowFocus: 'always', + }); + if (isLoading) { + return ( + + Loading... + + ); + } + if (!catalog || isError) { + console.error(error); + return ( + + Error + + ); + } + + console.log("---------- fetched catalog -----------") + console.table(catalog); + let totalPrice = 0; + currentTableCart.forEach(element => { + Object.keys(catalog).forEach(category => { + catalog[category].forEach(item => { + if(item._id === element.itemId) { + totalPrice += element.quantity * item.price; + } + }) + })}); - - , + return ( + + + + + + {open && ( + < Box className="popup-fullscreen"> + setOpen(false)} color={'white'} top={20} left={20}/> + + Summary + + + + {Object.keys(catalog).map((category) => ( + (catalog[category].filter(element => currentTableCart.map(element => element.itemId).includes(element._id)) ? + + {category} + {catalog[category].map((item) => ( + (currentTableCart.map(element => element.itemId).includes(item._id)) ? + + {item.shortName}: {currentTableCart.find(element => element.itemId === item._id)?.quantity ?? 0} + : "" + ))} + : '') + ))} + + + Total : ${totalPrice} + - - )} - - ); -} - -const summaryContentAdapt = (tablesSummary) => { - const transformed = {}; - // Iterate through the orders - tablesSummary.forEach(item => { - item.orders.forEach(order => { - const { category, name, quantity } = order; + + , + + - // Add the order details to the category array - transformed[category].push({ - name, - quantity: Number(quantity) // Convert Quantity to a number - }); - }); - }); - console.log(transformed) - return transformed; + )} + + ); } - -export default Summary; \ No newline at end of file +export default Summary; diff --git a/libs/ui/common/src/lib/utils/navbar.tsx b/libs/ui/common/src/lib/utils/navbar.tsx index 56a5ebe..f2198d4 100644 --- a/libs/ui/common/src/lib/utils/navbar.tsx +++ b/libs/ui/common/src/lib/utils/navbar.tsx @@ -13,7 +13,7 @@ interface NavBarProps { export function NavBar({ groupId, setSelectedTable, setSelectedTableParentFunction }: Readonly) { const container = useContext(ContainerContext); - const { data: group, isLoading } = useQuery({ + const { data: group, isLoading, isError, error } = useQuery({ queryKey: ["group", groupId], queryFn: async () => { const groupService = container.get(TYPES.GroupService); @@ -22,8 +22,26 @@ export function NavBar({ groupId, setSelectedTable, setSelectedTableParentFuncti refetchOnWindowFocus: "always", }); - const tables = isLoading ? [] : group.tables.map((table) => table.number); + const tables = isLoading ? [] : (group ?? {tables:[]}).tables.map((table) => table.number); const [tableSelected, setTableSelected] = useState(tables[0]); + + if(isError) { + console.log(error); + return ( + + Help + + ); + } + + if(!group) { + return ( + + Loading + + ); + } + const handleTableSelection = (tableId: number) => { setTableSelected(tableId); setSelectedTable(tables, tableId, setSelectedTableParentFunction);