v2
This commit is contained in:
parent
eee374359b
commit
38bdf4c3c5
@ -17,6 +17,11 @@ export default function NavBar({ menu, className = '', children }: Props) {
|
|||||||
const [isMenuNavBarActive, setIsMenuNavBarActive] = useState(false)
|
const [isMenuNavBarActive, setIsMenuNavBarActive] = useState(false)
|
||||||
const [isScrolled, setIsScrolled] = useState(false);
|
const [isScrolled, setIsScrolled] = useState(false);
|
||||||
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
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(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
@ -49,7 +54,7 @@ export default function NavBar({ menu, className = '', children }: Props) {
|
|||||||
isMenuNavBarActive ? 'block' : 'hidden'
|
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`}
|
} 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`}
|
||||||
>
|
>
|
||||||
<NavBarMenuList menu={menu} />
|
<NavBarMenuList menu={menu} cartItemsCount={cartItemsCount} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -14,10 +14,11 @@ import { useRouter } from 'next/router';
|
|||||||
import ClickOutside from "./ClickOutside";
|
import ClickOutside from "./ClickOutside";
|
||||||
|
|
||||||
type Props = {
|
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 router = useRouter();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const excludedRef = useRef(null);
|
const excludedRef = useRef(null);
|
||||||
@ -92,7 +93,7 @@ export default function NavBarItem({ item }: Props) {
|
|||||||
item.isDesktopNoLabel && item.icon ? 'lg:hidden' : ''
|
item.isDesktopNoLabel && item.icon ? 'lg:hidden' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{itemLabel}
|
{itemLabel} {item.label === 'Cart' && cartItemsCount > 0 && `(${cartItemsCount})`}
|
||||||
</span>
|
</span>
|
||||||
{item.isCurrentUser && <UserAvatarCurrentUser className="w-6 h-6 mr-3 inline-flex" />}
|
{item.isCurrentUser && <UserAvatarCurrentUser className="w-6 h-6 mr-3 inline-flex" />}
|
||||||
{item.menu && (
|
{item.menu && (
|
||||||
|
|||||||
@ -3,15 +3,16 @@ import { MenuNavBarItem } from '../interfaces'
|
|||||||
import NavBarItem from './NavBarItem'
|
import NavBarItem from './NavBarItem'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
menu: MenuNavBarItem[]
|
menu: MenuNavBarItem[],
|
||||||
|
cartItemsCount?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NavBarMenuList({ menu }: Props) {
|
export default function NavBarMenuList({ menu, cartItemsCount }: Props) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{menu.map((item, index) => (
|
{menu.map((item, index) => (
|
||||||
<div key={index}>
|
<div key={index}>
|
||||||
<NavBarItem item={item} />
|
<NavBarItem item={item} cartItemsCount={cartItemsCount} />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -10,10 +10,16 @@ import {
|
|||||||
mdiThemeLightDark,
|
mdiThemeLightDark,
|
||||||
mdiGithub,
|
mdiGithub,
|
||||||
mdiVuejs,
|
mdiVuejs,
|
||||||
|
mdiCart
|
||||||
} from '@mdi/js'
|
} from '@mdi/js'
|
||||||
import { MenuNavBarItem } from './interfaces'
|
import { MenuNavBarItem } from './interfaces'
|
||||||
|
|
||||||
const menuNavBar: MenuNavBarItem[] = [
|
const menuNavBar: MenuNavBarItem[] = [
|
||||||
|
{
|
||||||
|
icon: mdiCart,
|
||||||
|
label: 'Cart',
|
||||||
|
href: '/cart',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
isCurrentUser: true,
|
isCurrentUser: true,
|
||||||
menu: [
|
menu: [
|
||||||
|
|||||||
99
frontend/src/pages/cart.tsx
Normal file
99
frontend/src/pages/cart.tsx
Normal file
@ -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 (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>{getPageTitle('Shopping Cart')}</title>
|
||||||
|
</Head>
|
||||||
|
<SectionMain>
|
||||||
|
<SectionTitleLineWithButton icon={mdiCart} title={'Shopping Cart'} main>
|
||||||
|
</SectionTitleLineWithButton>
|
||||||
|
<CardBox>
|
||||||
|
<>
|
||||||
|
<p className={'block font-bold mb-2'}>Order Items</p>
|
||||||
|
<CardBox
|
||||||
|
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||||
|
hasTable
|
||||||
|
>
|
||||||
|
<div className='overflow-x-auto'>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Product</th>
|
||||||
|
<th>Quantity</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Subtotal</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{pendingOrder && pendingOrder.order_items_order && Array.isArray(pendingOrder.order_items_order) &&
|
||||||
|
pendingOrder.order_items_order.map((item: any) => (
|
||||||
|
<tr key={item.id}>
|
||||||
|
<td data-label="product_name">
|
||||||
|
{item.product_name}
|
||||||
|
</td>
|
||||||
|
<td data-label="quantity">
|
||||||
|
{item.quantity}
|
||||||
|
</td>
|
||||||
|
<td data-label="unit_price">
|
||||||
|
{item.unit_price}
|
||||||
|
</td>
|
||||||
|
<td data-label="subtotal">
|
||||||
|
{item.subtotal}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{!pendingOrder?.order_items_order?.length && <div className={'text-center py-4'}>Your cart is empty</div>}
|
||||||
|
</CardBox>
|
||||||
|
</>
|
||||||
|
<BaseButton
|
||||||
|
color='info'
|
||||||
|
label='Checkout'
|
||||||
|
onClick={() => router.push('/checkout')}
|
||||||
|
/>
|
||||||
|
</CardBox>
|
||||||
|
</SectionMain>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
CartPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return (
|
||||||
|
<LayoutAuthenticated
|
||||||
|
>
|
||||||
|
{page}
|
||||||
|
</LayoutAuthenticated>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CartPage;
|
||||||
@ -8,15 +8,51 @@ import Head from 'next/head';
|
|||||||
import SectionMain from '../components/SectionMain';
|
import SectionMain from '../components/SectionMain';
|
||||||
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton';
|
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton';
|
||||||
import { mdiStorefrontOutline } from '@mdi/js';
|
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 IndexPage = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { products, loading } = useAppSelector((state) => state.products);
|
const { products, loading } = useAppSelector((state) => state.products);
|
||||||
|
const { orders } = useAppSelector((state) => state.orders);
|
||||||
|
const { currentUser } = useAppSelector((state) => state.auth);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchProducts({}));
|
dispatch(fetchProducts({}));
|
||||||
}, [dispatch]);
|
}, [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 (
|
return (
|
||||||
@ -44,6 +80,9 @@ const IndexPage = () => {
|
|||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<h4 className="text-xl font-bold">{product.name}</h4>
|
<h4 className="text-xl font-bold">{product.name}</h4>
|
||||||
<p className="text-gray-500">${product.price}</p>
|
<p className="text-gray-500">${product.price}</p>
|
||||||
|
<button onClick={() => handleAddToCart(product)} className="mt-4 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
|
||||||
|
Add to Cart
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</CardBox>
|
</CardBox>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user