diff --git a/frontend/src/components/NavBar.tsx b/frontend/src/components/NavBar.tsx
index cedc7a7..3c09ec4 100644
--- a/frontend/src/components/NavBar.tsx
+++ b/frontend/src/components/NavBar.tsx
@@ -5,7 +5,7 @@ import BaseIcon from './BaseIcon'
import NavBarItemPlain from './NavBarItemPlain'
import NavBarMenuList from './NavBarMenuList'
import { MenuNavBarItem } from '../interfaces'
-import { useAppSelector } from '../stores/hooks';
+import { useAppSelector } from '../stores/hooks';
type Props = {
menu: MenuNavBarItem[]
@@ -17,6 +17,11 @@ export default function NavBar({ menu, className = '', children }: Props) {
const [isMenuNavBarActive, setIsMenuNavBarActive] = useState(false)
const [isScrolled, setIsScrolled] = useState(false);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
+ const { orders } = useAppSelector((state) => state.orders)
+ const { currentUser } = useAppSelector((state) => state.auth)
+
+ const pendingOrder = orders.find(order => order.status === 'pending' && order.customer?.id === currentUser?.id);
+ const cartItemsCount = pendingOrder?.order_items_order?.reduce((acc, item) => acc + item.quantity, 0) || 0;
useEffect(() => {
const handleScroll = () => {
@@ -49,7 +54,7 @@ export default function NavBar({ menu, className = '', children }: Props) {
isMenuNavBarActive ? 'block' : 'hidden'
} flex items-center max-h-screen-menu overflow-y-auto lg:overflow-visible absolute w-screen top-14 left-0 ${bgColor} shadow-lg lg:w-auto lg:flex lg:static lg:shadow-none dark:bg-dark-800`}
>
-
+
diff --git a/frontend/src/components/NavBarItem.tsx b/frontend/src/components/NavBarItem.tsx
index 89370d6..e80061c 100644
--- a/frontend/src/components/NavBarItem.tsx
+++ b/frontend/src/components/NavBarItem.tsx
@@ -14,10 +14,11 @@ import { useRouter } from 'next/router';
import ClickOutside from "./ClickOutside";
type Props = {
- item: MenuNavBarItem
+ item: MenuNavBarItem,
+ cartItemsCount?: number
}
-export default function NavBarItem({ item }: Props) {
+export default function NavBarItem({ item, cartItemsCount }: Props) {
const router = useRouter();
const dispatch = useAppDispatch();
const excludedRef = useRef(null);
@@ -92,7 +93,7 @@ export default function NavBarItem({ item }: Props) {
item.isDesktopNoLabel && item.icon ? 'lg:hidden' : ''
}`}
>
- {itemLabel}
+ {itemLabel} {item.label === 'Cart' && cartItemsCount > 0 && `(${cartItemsCount})`}
{item.isCurrentUser && }
{item.menu && (
diff --git a/frontend/src/components/NavBarMenuList.tsx b/frontend/src/components/NavBarMenuList.tsx
index 0896428..162dedc 100644
--- a/frontend/src/components/NavBarMenuList.tsx
+++ b/frontend/src/components/NavBarMenuList.tsx
@@ -3,15 +3,16 @@ import { MenuNavBarItem } from '../interfaces'
import NavBarItem from './NavBarItem'
type Props = {
- menu: MenuNavBarItem[]
+ menu: MenuNavBarItem[],
+ cartItemsCount?: number
}
-export default function NavBarMenuList({ menu }: Props) {
+export default function NavBarMenuList({ menu, cartItemsCount }: Props) {
return (
<>
{menu.map((item, index) => (
-
+
))}
>
diff --git a/frontend/src/menuNavBar.ts b/frontend/src/menuNavBar.ts
index a5dd956..be5b4b6 100644
--- a/frontend/src/menuNavBar.ts
+++ b/frontend/src/menuNavBar.ts
@@ -10,10 +10,16 @@ import {
mdiThemeLightDark,
mdiGithub,
mdiVuejs,
+ mdiCart
} from '@mdi/js'
import { MenuNavBarItem } from './interfaces'
const menuNavBar: MenuNavBarItem[] = [
+ {
+ icon: mdiCart,
+ label: 'Cart',
+ href: '/cart',
+ },
{
isCurrentUser: true,
menu: [
diff --git a/frontend/src/pages/cart.tsx b/frontend/src/pages/cart.tsx
new file mode 100644
index 0000000..516af72
--- /dev/null
+++ b/frontend/src/pages/cart.tsx
@@ -0,0 +1,99 @@
+
+import React, { ReactElement, useEffect } from 'react';
+import Head from 'next/head'
+import {
+ useAppDispatch,
+ useAppSelector
+} from "../../stores/hooks";
+import { useRouter } from "next/router";
+import { fetch as fetchOrders } from '../../stores/orders/ordersSlice'
+import LayoutAuthenticated from "../../layouts/Authenticated";
+import { getPageTitle } from "../../config";
+import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
+import SectionMain from "../../components/SectionMain";
+import CardBox from "../../components/CardBox";
+import BaseButton from "../../components/BaseButton";
+import { mdiCart } from "@mdi/js";
+
+const CartPage = () => {
+ const router = useRouter()
+ const dispatch = useAppDispatch()
+ const { orders } = useAppSelector((state) => state.orders)
+ const { currentUser } = useAppSelector((state) => state.auth)
+
+ const pendingOrder = orders.find(order => order.status === 'pending' && order.customer?.id === currentUser?.id);
+
+ useEffect(() => {
+ dispatch(fetchOrders({ query: '?status=pending' }));
+ }, [dispatch]);
+
+ return (
+ <>
+
+ {getPageTitle('Shopping Cart')}
+
+
+
+
+
+ <>
+ Order Items
+
+
+
+
+
+ | Product |
+ Quantity |
+ Price |
+ Subtotal |
+
+
+
+ {pendingOrder && pendingOrder.order_items_order && Array.isArray(pendingOrder.order_items_order) &&
+ pendingOrder.order_items_order.map((item: any) => (
+
+ |
+ {item.product_name}
+ |
+
+ {item.quantity}
+ |
+
+ {item.unit_price}
+ |
+
+ {item.subtotal}
+ |
+
+ ))}
+
+
+
+ {!pendingOrder?.order_items_order?.length && Your cart is empty
}
+
+ >
+ router.push('/checkout')}
+ />
+
+
+ >
+ );
+};
+
+CartPage.getLayout = function getLayout(page: ReactElement) {
+ return (
+
+ {page}
+
+ )
+}
+
+export default CartPage;
diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx
index c1a1c4e..cfeca57 100644
--- a/frontend/src/pages/index.tsx
+++ b/frontend/src/pages/index.tsx
@@ -8,15 +8,51 @@ import Head from 'next/head';
import SectionMain from '../components/SectionMain';
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton';
import { mdiStorefrontOutline } from '@mdi/js';
+import { create as createOrder } from '../stores/orders/ordersSlice';
+import { create as createOrderItem } from '../stores/order_items/order_itemsSlice';
const IndexPage = () => {
const dispatch = useAppDispatch();
const { products, loading } = useAppSelector((state) => state.products);
+ const { orders } = useAppSelector((state) => state.orders);
+ const { currentUser } = useAppSelector((state) => state.auth);
useEffect(() => {
dispatch(fetchProducts({}));
}, [dispatch]);
+ const handleAddToCart = async (product) => {
+ if (!currentUser) {
+ alert('Please login to add items to your cart.');
+ return;
+ }
+
+ let pendingOrder = orders.find(order => order.status === 'pending' && order.customer?.id === currentUser.id);
+
+ if (!pendingOrder) {
+ const orderData = {
+ customer: currentUser.id,
+ status: 'pending',
+ };
+ const newOrderAction = await dispatch(createOrder(orderData));
+ if (newOrderAction.payload) {
+ pendingOrder = newOrderAction.payload;
+ }
+ }
+
+ if (pendingOrder) {
+ const orderItemData = {
+ order: pendingOrder.id,
+ product: product.id,
+ quantity: 1,
+ unit_price: product.price,
+ subtotal: product.price,
+ };
+ await dispatch(createOrderItem(orderItemData));
+ }
+ };
+
+
return (
@@ -44,6 +80,9 @@ const IndexPage = () => {
{product.name}
${product.price}
+
))}