diff --git a/backend/src/repository/OrderProductRepo.ts b/backend/src/repository/OrderProductRepo.ts index ba0d9165139a7f1e80bb20c05e0e9199afc51ae3..d84d7ade70f9dd30ce8e77696b51d1bd3a09ed55 100644 --- a/backend/src/repository/OrderProductRepo.ts +++ b/backend/src/repository/OrderProductRepo.ts @@ -15,7 +15,9 @@ interface IOrderProductRepo { export default class OrderProductRepo implements IOrderProductRepo { async getAllOrderProduct(): Promise<OrderProduct[]> { try { - return await OrderProduct.findAll(); + return await OrderProduct.findAll({ + order: [["id_product", "ASC"]], + }); } catch (error: any) { throw new Error( `Error while fetching order products: ${error.message}`, diff --git a/backend/src/repository/OrdersRepo.ts b/backend/src/repository/OrdersRepo.ts index 8793ef66cb91e48489dec4e4164ea1f301689fb6..6b8904f93a89d56ef650ef4a9b6e8faad38b3fa8 100644 --- a/backend/src/repository/OrdersRepo.ts +++ b/backend/src/repository/OrdersRepo.ts @@ -14,7 +14,9 @@ interface IOrdersRepo { export default class OrdersRepo implements IOrdersRepo { async getAllOrders(): Promise<Orders[]> { try { - return await Orders.findAll(); + return await Orders.findAll({ + order: [["id", "DESC"]], + }); } catch (error: any) { throw new Error(`Error while fetching orders: ${error.message}`); } diff --git a/backend/src/repository/PaymentsRepo.ts b/backend/src/repository/PaymentsRepo.ts index 296d92404b8ca4a85fa47a470a0700bc5b9dccb2..6b79b9b3ebcca3191826c916438773b313b9cde2 100644 --- a/backend/src/repository/PaymentsRepo.ts +++ b/backend/src/repository/PaymentsRepo.ts @@ -13,7 +13,9 @@ interface IPaymentsRepo { export default class PaymentsRepo implements IPaymentsRepo { async getAllPayments(): Promise<Payments[]> { try { - return await Payments.findAll(); + return await Payments.findAll({ + order: [["id", "DESC"]], + }); } catch (error: any) { throw new Error(`Error while fetching payments: ${error.message}`); } diff --git a/backend/src/repository/ProductsRepo.ts b/backend/src/repository/ProductsRepo.ts index 2e6f27b515344702999a3fd117f386e7cc3b2f69..58bcd9a99e271ab910ff5c4c3fc66bf8a110e095 100644 --- a/backend/src/repository/ProductsRepo.ts +++ b/backend/src/repository/ProductsRepo.ts @@ -13,7 +13,9 @@ interface IProductsRepo { export default class ProductsRepo implements IProductsRepo { async getAllProducts(): Promise<Products[]> { try { - return await Products.findAll(); + return await Products.findAll({ + order: [["id", "ASC"]], + }); } catch (error: any) { throw new Error(`Error while fetching products: ${error.message}`); } diff --git a/backend/src/repository/TablesRepo.ts b/backend/src/repository/TablesRepo.ts index 3b67116b8d4964e3b9a5c3e4605a1d87c6e81fce..588c10e43d74b6cdacb261b86e3fbf4b6daca0bc 100644 --- a/backend/src/repository/TablesRepo.ts +++ b/backend/src/repository/TablesRepo.ts @@ -13,7 +13,9 @@ export default class TablesRepo implements ITablesRepo { async getAllTables(): Promise<Tables[]> { try { console.log("masuk getTables"); - return await Tables.findAll(); + return await Tables.findAll({ + order: [["id", "ASC"]], + }); } catch (error: any) { throw new Error(`Error while fetching tables: ${error.message}`); } diff --git a/backend/src/repository/TenantsRepo.ts b/backend/src/repository/TenantsRepo.ts index 64686d365cb36868f3a3d497124e66333c7b1311..7312d5ea6bb922468d49331b431dad98eb20f604 100644 --- a/backend/src/repository/TenantsRepo.ts +++ b/backend/src/repository/TenantsRepo.ts @@ -13,7 +13,9 @@ interface ITenantRepo { export default class TenantRepo implements ITenantRepo { async getAllTenants(): Promise<Tenants[]> { try { - return await Tenants.findAll(); + return await Tenants.findAll({ + order: [["id", "ASC"]], + }); } catch (error: any) { throw new Error(`Error while fetching tenants: ${error.message}`); } diff --git a/backend/src/repository/UsersRepo.ts b/backend/src/repository/UsersRepo.ts index d97d3ccc6ec263cb86427b99302c1c9e0217fa3f..6a866c7edac114c2f7983429ee55523c58f88687 100644 --- a/backend/src/repository/UsersRepo.ts +++ b/backend/src/repository/UsersRepo.ts @@ -14,7 +14,9 @@ interface IUsersRepo { export default class UsersRepo implements IUsersRepo { async getAllUsers(): Promise<Users[]> { try { - return await Users.findAll(); + return await Users.findAll({ + order: [["id", "ASC"]], + }); } catch (error: any) { throw new Error(`Error while fetching users: ${error.message}`); } diff --git a/frontend/src/components/ProductCard.tsx b/frontend/src/components/ProductCard.tsx index 36924d4f37f1a0664dd5e2e631619d87370af098..b3af0d26b159ff7b0c78abd8186efcd590c67ed7 100644 --- a/frontend/src/components/ProductCard.tsx +++ b/frontend/src/components/ProductCard.tsx @@ -1,7 +1,6 @@ -import { useState, useEffect } from "react"; -import { useShoppingCart } from "../contexts/ShoppingCartContext"; -import { useLocalStorage } from "../hooks/useLocalStorage"; -import ShoppingCart from "../pages/ShoppingCart"; +import { useState, useEffect } from 'react' +import { useShoppingCart } from '../contexts/ShoppingCartContext'; +import { useLocalStorage } from '../hooks/useLocalStorage'; import Axios from "axios"; type ProductCardProps = { @@ -29,9 +28,7 @@ export default function ProductCard({ data }: { data: ProductCardProps[] }) { false, ); - // find cartItem id_tenant - - const [productData, setProductData] = useState<Product[]>([]); + const [productData, setProductData] = useState<Product[]>([]); const getProductData = async () => { const productResponse = await Axios.get( @@ -76,13 +73,40 @@ export default function ProductCard({ data }: { data: ProductCardProps[] }) { return; } } - if (isAdded) { - removeItem(id); - } else { - increaseItemQuantity(id); + }); + + setProductData(result); + + }; + + useEffect(() => { + getProductData(); + }, []); + + console.log(productData); + + useEffect(() => { + const quantity = getItemQuantity(id); + setIsAdded(quantity > 0); + }, [getItemQuantity, id, setIsAdded]); + + const handleClick = () => { + if (cartItems.length > 0) { + const cartItem = cartItems[0]; + const cartTenantId = cartItem && productData.find((product: Product) => product.id === cartItem.id)?.id_tenant; + console.log(cartTenantId); + if (cartTenantId !== id_tenant) { + alert("You can't add items from different tenants to the cart!"); + return; } - setIsAdded(!isAdded); - }; + } + if (isAdded) { + removeItem(id); + } else { + increaseItemQuantity(id); + } + setIsAdded(!isAdded); + }; const priceidr = price .toString() diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 7efbeaec54fc69ea12075c913e8dadc2be96a61b..4e385488e25fff977c3fa2e30b713d9d8c174c37 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -136,21 +136,49 @@ export default function Sidebar(props: any) { </ul> </div> {props.customer === true ? ( - <a onClick={logout}> - <div className="flex flex-col px-10 py-3.5 mt-auto mb-10"> + <a onClick={logout} href="/role"> + <div className="flex flex-col px-10 py-3.5 mt-auto mb-8"> <button type="button" className="flex text-mealshub-red bg-white hover:bg-mealshub-red hover:text-white font-medium rounded-2xl p-4 inline-flex group" > - <div className="flex flex-col w-52"> - <span className="flex whitespace-nowrap text-lg text-left"> + <div className="flex flex-col justify-center w-52"> + <div className="absolute group text-mealshub-red"> + <svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 28 33" + className="h-auto w-7 text-mealshub-red group-hover:hidden" + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M15.5554 24.0346L17.7292 26.2083L25.4375 18.5L17.7292 10.7917L15.5554 12.9654L19.5329 16.9583H4.625V20.0417H19.5329L15.5554 24.0346ZM29.2917 4.625H7.70833C6.89058 4.625 6.10632 4.94985 5.52809 5.52809C4.94985 6.10632 4.625 6.89058 4.625 7.70833V13.875H7.70833V7.70833H29.2917V29.2917H7.70833V23.125H4.625V29.2917C4.625 30.1094 4.94985 30.8937 5.52809 31.4719C6.10632 32.0501 6.89058 32.375 7.70833 32.375H29.2917C30.9875 32.375 32.375 30.9875 32.375 29.2917V7.70833C32.375 6.0125 30.9875 4.625 29.2917 4.625Z" + fill="currentcolor" + /> + </svg> + <svg + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 28 33" + className="h-auto w-7 text-white hidden group-hover:block group-hover:shadow-xl" + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M15.5554 24.0346L17.7292 26.2083L25.4375 18.5L17.7292 10.7917L15.5554 12.9654L19.5329 16.9583H4.625V20.0417H19.5329L15.5554 24.0346ZM29.2917 4.625H7.70833C6.89058 4.625 6.10632 4.94985 5.52809 5.52809C4.94985 6.10632 4.625 6.89058 4.625 7.70833V13.875H7.70833V7.70833H29.2917V29.2917H7.70833V23.125H4.625V29.2917C4.625 30.1094 4.94985 30.8937 5.52809 31.4719C6.10632 32.0501 6.89058 32.375 7.70833 32.375H29.2917C30.9875 32.375 32.375 30.9875 32.375 29.2917V7.70833C32.375 6.0125 30.9875 4.625 29.2917 4.625Z" + fill="currentcolor" + /> + </svg> + </div> + <span className="flex ms-14 whitespace-nowrap text-lg text-left"> Log Out </span> </div> </button> </div> </a> - ) : null} + ) : ( + null + )} </div> </div> ); diff --git a/frontend/src/components/TenantCard.tsx b/frontend/src/components/TenantCard.tsx index 0d0d92d5d74189f2c4b3ed285af5c403568c1898..dbb4072a6d72456edbf53dc6b8919e95491d73cb 100644 --- a/frontend/src/components/TenantCard.tsx +++ b/frontend/src/components/TenantCard.tsx @@ -39,7 +39,8 @@ export default function TenantCard({ data }: { data: TenantCardProps[] }) { <span className="px-3 font-light">Rp.{lowestpriceidr} - Rp.{highestpriceidr}</span> </div> </div> - </a> + </div> + </a> ); }, ); diff --git a/frontend/src/hooks/useAuth.tsx b/frontend/src/hooks/useAuth.tsx index 72fb43cc4c535cd971b415877512e95c68db0db6..6a5b6a5d219c7c78320321ae7cd182f40c4a96f9 100644 --- a/frontend/src/hooks/useAuth.tsx +++ b/frontend/src/hooks/useAuth.tsx @@ -2,7 +2,7 @@ import React, { useState, createContext, useContext, ReactNode } from "react"; import * as userService from "../services/userService"; import { toast } from "react-toastify"; -interface AuthUser { +export interface AuthUser { id: number; username: string; fullname: string; @@ -11,7 +11,7 @@ interface AuthUser { token: string; } -interface AuthTable { +export interface AuthTable { num_seat: number; id_table: number; fullname: string; diff --git a/frontend/src/pages/Homepage.tsx b/frontend/src/pages/Homepage.tsx index 57713d4f5a4f6e88257eb143793ca08c05f9960c..9b68fade4f921fe8b89bc408a458a90d7bbca858 100644 --- a/frontend/src/pages/Homepage.tsx +++ b/frontend/src/pages/Homepage.tsx @@ -4,7 +4,7 @@ import Sidebar from "../components/Sidebar"; import TenantCard from "../components/TenantCard"; import Search from "../components/Search"; import WelcomingText from "../components/WelcomingText"; -import { useAuth } from "../hooks/useAuth"; +import { useAuth, AuthTable } from "../hooks/useAuth"; interface Tenant { id: number; @@ -79,7 +79,7 @@ export default function Homepage() { } }; - const tableid = 1; + const tableid = (user as AuthTable).id; return ( <div className="grid grid-cols-5 grid-rows-8 bg-mealshub-cream min-h-screen"> diff --git a/frontend/src/pages/ManageOrderTenant.tsx b/frontend/src/pages/ManageOrderTenant.tsx index 0f6bbe980b4755481a51fa1dcc122440a6261678..054ca274e12ccba78339f814d632a9d397efab17 100644 --- a/frontend/src/pages/ManageOrderTenant.tsx +++ b/frontend/src/pages/ManageOrderTenant.tsx @@ -9,6 +9,7 @@ import ProfileDropDown from "../components/ProfileDropDown"; import Axios from "axios"; import { useParams } from "react-router-dom"; import crypto from "crypto-js"; +import { useAuth } from "../hooks/useAuth"; interface Order { id: number; @@ -57,6 +58,7 @@ interface OrderDetails { } export default function OrderDetails() { + const { user } = useAuth(); const { orderid } = useParams(); const [showProfileDropDown, setShowProfileDropDown] = useState(false); @@ -277,7 +279,7 @@ export default function OrderDetails() { {/* Header */} <div className="col-span-4"> <div className="row-span-1 ms-20 mt-9 py-3 w-11/12"> - <Welcome user="Aldaebaran" /> + <Welcome user={user ? user!.fullname : ""} /> </div> <div className="absolute top-0 right-0 mt-9 mx-12"> <Profile diff --git a/frontend/src/pages/ManagePayment.tsx b/frontend/src/pages/ManagePayment.tsx index 6d694bb4cba16ad02c2005edee06b9d3d63a6568..1b3f078ec25e33860268c3cab91affc19d330d0c 100644 --- a/frontend/src/pages/ManagePayment.tsx +++ b/frontend/src/pages/ManagePayment.tsx @@ -10,6 +10,7 @@ import ConfirmPopUp from "../components/ConfirmPopUp"; import Axios from "axios"; import { useParams } from "react-router-dom"; import crypto from "crypto-js"; +import { useAuth } from "../hooks/useAuth"; interface Order { id: number; @@ -58,6 +59,7 @@ interface OrderDetails { } const ManagePayment = () => { + const { user } = useAuth(); const { orderid } = useParams(); const paymentid = orderid; const [showProfileDropDown, setShowProfileDropDown] = useState(false); @@ -218,7 +220,7 @@ const ManagePayment = () => { {/* Header */} <div className="col-span-4"> <div className="row-span-1 ms-20 mt-9 py-3 w-11/12"> - <Welcome user="Aldaebaran" /> + <Welcome user={user ? user!.fullname : ""} /> </div> <div className="absolute top-0 right-0 mt-9 mx-12"> <Profile diff --git a/frontend/src/pages/OrderList.tsx b/frontend/src/pages/OrderList.tsx index 9481001dd3b9e6cb67114d91cecdd82dad6907e2..7cac2928609fba0bcd2bc17c22f9027c99e07f93 100644 --- a/frontend/src/pages/OrderList.tsx +++ b/frontend/src/pages/OrderList.tsx @@ -3,6 +3,8 @@ import OrderCard from "../components/OrderCard"; import WelcomingText from "../components/WelcomingText"; import { useEffect, useState } from "react"; import Axios from "axios"; +import { useAuth, AuthTable } from "../hooks/useAuth"; +import { useParams } from "react-router-dom"; interface Tenant { id: number, @@ -44,7 +46,9 @@ interface joinedData { } export default function OrderList() { - const tableid = 101; + const { user } = useAuth(); + const tableid = (user as AuthTable).id; + const [joinedData, setJoinedData] = useState<joinedData[]>([]); const getData = async () => { @@ -116,7 +120,7 @@ export default function OrderList() { <div className="col-span-4"> <div className="ms-20"> <div className="row-span-1 mt-9 py-3 w-11/12"> - <WelcomingText name="Table 1" /> + <WelcomingText name={user ? user!.fullname : ""} /> </div> <div className="row-span-7 mt-6 mb-9 py-12 w-11/12 bg-white rounded-3xl"> <div className=""> diff --git a/frontend/src/pages/OrderSummary.tsx b/frontend/src/pages/OrderSummary.tsx index 88af4d03fc26faea669326042cb7add27dde56eb..d0681cf1a52ec3a018ede523e5e2c640be6d3fc8 100644 --- a/frontend/src/pages/OrderSummary.tsx +++ b/frontend/src/pages/OrderSummary.tsx @@ -7,6 +7,7 @@ import { useEffect, useState } from "react"; import Axios from "axios"; import { useParams } from "react-router-dom"; import crypto from "crypto-js"; +import { useAuth, AuthTable } from "../hooks/useAuth"; interface Order { id: number; @@ -55,6 +56,7 @@ interface OrderDetails { } export default function OrderSummary() { + const { user } = useAuth(); const { orderid } = useParams(); const [joinedOrderSummaryData, setJoinedOrderSummaryData] = useState< OrderSummary[] @@ -167,7 +169,7 @@ export default function OrderSummary() { console.log(joinedOrderDetailsData); - const tableid = 1; + const tableid = (user as AuthTable).id; return ( // Create grid layout for sidebard, header, and main content @@ -192,7 +194,7 @@ export default function OrderSummary() { {/* Header */} <div className="col-span-4"> <div className="row-span-1 ms-20 mt-9 py-3 w-11/12"> - <WelcomingText name="Table 1" /> + <WelcomingText name={user ? user!.fullname : ""}/> </div> <div className="row-span-7 mt-6 mb-9 w-11/12"> <div className="ms-4"> @@ -203,10 +205,7 @@ export default function OrderSummary() { Order Summary </h2> <OrderDetailsCard data={joinedOrderDetailsData} /> - <OrderSummaryCard - data={joinedOrderSummaryData} - customer={true} - /> + <OrderSummaryCard data={joinedOrderSummaryData} customer={true} /> {joinedOrderDetailsData.map((order) => { if ( order.paymentstatus === diff --git a/frontend/src/pages/ShoppingCart.tsx b/frontend/src/pages/ShoppingCart.tsx index a86c281038eccaa6403eabb5fd576b2c4566657d..6acd49488e0d22b57047b41f58be5f627e940153 100644 --- a/frontend/src/pages/ShoppingCart.tsx +++ b/frontend/src/pages/ShoppingCart.tsx @@ -5,7 +5,8 @@ import WelcomingText from "../components/WelcomingText"; import { useShoppingCart } from "../contexts/ShoppingCartContext"; import { useState, useEffect } from "react"; import Axios from "axios"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; +import { useAuth, AuthTable } from "../hooks/useAuth"; interface cartItem { id: number; @@ -29,6 +30,7 @@ interface Tenant { export default function ShoppingCart() { + const { user } = useAuth(); const { clearCart, cartItems } = useShoppingCart(); const [tenantData, setTenantData] = useState<Tenant[]>([]); @@ -84,7 +86,8 @@ export default function ShoppingCart() { console.log(productData); - const tableid = 1; + const tableid = (user as AuthTable).id; + console.log(tableid); const getTenantId = (cartItem: cartItem) => { const item = productData.find((i) => i.id === cartItem.id); @@ -154,7 +157,7 @@ export default function ShoppingCart() { <div className="col-span-4"> <div className="ms-20"> <div className="row-span-1 mt-9 py-3 w-11/12"> - <WelcomingText name="Table 1" /> + <WelcomingText name={user ? user!.fullname : ""} /> </div> <div className="row-span-7 mt-6 mb-9 py-12 w-11/12 bg-white rounded-3xl"> <div className=""> diff --git a/frontend/src/pages/TenantInfo.tsx b/frontend/src/pages/TenantInfo.tsx index eced36039663706f68994481fb78eb3c2bb98707..edef135b738fd1c6606e1e29fcb17170aebe59cb 100644 --- a/frontend/src/pages/TenantInfo.tsx +++ b/frontend/src/pages/TenantInfo.tsx @@ -6,6 +6,7 @@ import BackButton from "../components/BackButton"; import { useState, useEffect } from "react"; import Axios from "axios"; import { useParams } from "react-router-dom"; +import { useAuth, AuthTable } from "../hooks/useAuth"; interface Tenant { id : number, @@ -42,10 +43,12 @@ interface ProductCard { image: string, name: string, description: string, - price: number + price: number, + id_tenant: number } export default function TenantInfo() { + const { user } = useAuth(); const { tenantid } = useParams(); const [joinedTenantHeaderData, setJoinedTenantHeaderData] = useState<TenantHeader[]>([]); @@ -103,7 +106,8 @@ export default function TenantInfo() { image: product.image, name: product.name, description: product.description, - price: product.price + price: product.price, + id_tenant: product.id_tenant } }); @@ -117,7 +121,7 @@ export default function TenantInfo() { console.log(joinedProductCardData); - const tableid = 1; + const tableid = (user as AuthTable).id; return ( // Create grid layout for sidebard, header, and main content @@ -129,7 +133,7 @@ export default function TenantInfo() { {/* Header */} <div className="col-span-4"> <div className="row-span-1 ms-20 mt-9 py-3 w-11/12"> - <WelcomingText name="Table 1"/> + <WelcomingText name={user ? user!.fullname : ""}/> </div> <div className="row-span-7 mt-6 mb-9 w-11/12"> <div className="ms-4"> diff --git a/frontend/src/pages/ViewPaymentHistory.tsx b/frontend/src/pages/ViewPaymentHistory.tsx index 0ef954b54897e4381b77bcb11be738873930b553..86983f96bb1db00aa3d5aed95383dd1e323e6742 100644 --- a/frontend/src/pages/ViewPaymentHistory.tsx +++ b/frontend/src/pages/ViewPaymentHistory.tsx @@ -5,10 +5,11 @@ import { useState } from "react"; import ProfileDropDown from "../components/ProfileDropDown"; import joinedOrderPayment from "../../../backend/src/services/api/joinedOrderPayment"; import TablePayment from "../components/TablePayment"; +import { useAuth } from "../hooks/useAuth"; export default function ViewPaymentHistory() { - const cashierid = 1; + const { user } = useAuth(); const [showProfileDropDown, setShowProfileDropDown] = useState(false); const handleProfileClick = () => { @@ -32,7 +33,7 @@ export default function ViewPaymentHistory() { {/* Header */} <div className="col-span-4"> <div className="ms-20 row-span-1 mt-9 py-3 w-11/12"> - <Welcome user="Aldaebaran" /> + <Welcome user={user ? user!.fullname : ""} /> </div> <div className="absolute top-0 right-0 mt-9 mx-12"> <Profile