From 135d5d5a5a79e88e46ee124b9eb987fe1f79e37a Mon Sep 17 00:00:00 2001 From: LimIvan336 <71662324+LimIvan336@users.noreply.github.com> Date: Tue, 12 Mar 2024 18:45:56 +0800 Subject: [PATCH] Added status checking for merch routes --- .../layout/components/MerchLayout.tsx | 43 ++++++ apps/web/features/layout/components/index.ts | 3 +- apps/web/pages/merch/cart/index.tsx | 12 +- apps/web/pages/merch/checkout/index.tsx | 143 ++++++++--------- apps/web/pages/merch/index.tsx | 146 ++++++++---------- .../merch/orders/{[slug].tsx => index.tsx} | 94 +++++++---- apps/web/pages/merch/product/[slug].tsx | 30 +++- 7 files changed, 278 insertions(+), 193 deletions(-) create mode 100644 apps/web/features/layout/components/MerchLayout.tsx rename apps/web/pages/merch/orders/{[slug].tsx => index.tsx} (73%) diff --git a/apps/web/features/layout/components/MerchLayout.tsx b/apps/web/features/layout/components/MerchLayout.tsx new file mode 100644 index 00000000..cb5fa449 --- /dev/null +++ b/apps/web/features/layout/components/MerchLayout.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import { Flex, Heading } from "@chakra-ui/react"; +import { QueryKeys } from "features/merch/constants"; +import { useQuery } from "@tanstack/react-query"; +import { api } from "features/merch/services/api"; +import { MerchListSkeleton, Page } from "ui/components/merch"; + +interface MerchLayoutProps { + children: React.ReactNode; +} + +export const MerchLayout = ({ children }: MerchLayoutProps) => { + const { data: status, isLoading: isStatusLoading } = useQuery( + [QueryKeys.STATUS], + () => api.getMerchSaleStatus(), + {} + ); + + const displayText = status?.displayText; + const disabled = status?.disabled; + + if (isStatusLoading) { + return ( + + + + ); + } + + return ( + <> + {disabled ? ( + + + {displayText} + + + ) : ( + <>{children} + )} + + ); +}; diff --git a/apps/web/features/layout/components/index.ts b/apps/web/features/layout/components/index.ts index 0881c3b2..adbd84d3 100644 --- a/apps/web/features/layout/components/index.ts +++ b/apps/web/features/layout/components/index.ts @@ -1 +1,2 @@ -export { WebLayout } from './WebLayout'; +export { WebLayout } from "./WebLayout"; +export { MerchLayout } from "./MerchLayout"; diff --git a/apps/web/pages/merch/cart/index.tsx b/apps/web/pages/merch/cart/index.tsx index 45e2fd33..cb9a937c 100644 --- a/apps/web/pages/merch/cart/index.tsx +++ b/apps/web/pages/merch/cart/index.tsx @@ -1,7 +1,6 @@ /* eslint-disable */ /* eslint-disable @typescript-eslint/no-misused-promises */ - import React, { useRef, useState, FC, useEffect } from "react"; import Link from "next/link"; import { @@ -38,6 +37,7 @@ import { routes, QueryKeys } from "features/merch/constants"; import { displayPrice } from "features/merch/functions"; import { calculatePricing } from "merch-helpers"; import { useRouter } from "next/router"; +import { MerchLayout } from "@/features/layout/components"; type ValidationType = { error: boolean; @@ -369,10 +369,12 @@ const Cart: FC = () => { }, [reroute]); return ( - - {CartHeading} - {renderCartContent()} - + + + {CartHeading} + {renderCartContent()} + + ); }; diff --git a/apps/web/pages/merch/checkout/index.tsx b/apps/web/pages/merch/checkout/index.tsx index 07f44240..dab4953c 100644 --- a/apps/web/pages/merch/checkout/index.tsx +++ b/apps/web/pages/merch/checkout/index.tsx @@ -24,6 +24,7 @@ import { displayPrice } from "@/features/merch/functions"; import { useRouter } from "next/router"; import StripeForm from "@/features/merch/components/checkout/StripeForm"; import { CheckoutResponse } from "types"; +import { MerchLayout } from "@/features/layout/components"; const CheckoutPage = () => { const [isLoading, setIsLoading] = useState(true); @@ -111,79 +112,83 @@ const OrderSummary = () => { ); return ( - - - Order Summary - - {`${noOfItems} item(s) Edit`} - - - {`Name: ${cartState.name}`} - {`Billing email: ${cartState.billingEmail}`} - {cartState.cart.items?.map((item) => { - const product = products?.find(({ id }) => id === item.id); - const subtotal = (product?.price ?? -1) * item.quantity; - return ( - - {product?.name} - - - - {product?.name} - - {displayPrice(subtotal)} - - - {`Color: ${item.color}`} - - - - {`Qty x${item.quantity}`} - - {item.size} - + + + + + Order Summary + + {`${noOfItems} item(s) Edit`} + + + {`Name: ${cartState.name}`} + {`Billing email: ${cartState.billingEmail}`} + {cartState.cart.items?.map((item) => { + const product = products?.find(({ id }) => id === item.id); + const subtotal = (product?.price ?? -1) * item.quantity; + return ( + + {product?.name} + + + + {product?.name} + + {displayPrice(subtotal)} + + + {`Color: ${item.color}`} + + + + {`Qty x${item.quantity}`} + + {item.size} + + + {displayPrice(product?.price ?? 0)} each + - {displayPrice(product?.price ?? 0)} each + ); + })} + + + + + {/* Subtotal: */} + {/* Discount: */} + Grand total: + + + {/* {displayPrice(checkoutState?.price?.subtotal ?? 0)} */} + {/* {displayPrice(checkoutState?.price?.discount ?? 0)} */} + + {displayPrice(checkoutState?.price?.grandTotal ?? 0)} + - ); - })} - - - - - {/* Subtotal: */} - {/* Discount: */} - Grand total: - - - {/* {displayPrice(checkoutState?.price?.subtotal ?? 0)} */} - {/* {displayPrice(checkoutState?.price?.discount ?? 0)} */} - - {displayPrice(checkoutState?.price?.grandTotal ?? 0)} - - - - + + + ); }; diff --git a/apps/web/pages/merch/index.tsx b/apps/web/pages/merch/index.tsx index 41b12b5a..2bb42c81 100644 --- a/apps/web/pages/merch/index.tsx +++ b/apps/web/pages/merch/index.tsx @@ -6,6 +6,7 @@ import { QueryKeys } from "features/merch/constants"; import { api } from "features/merch/services/api"; import { Product } from "types"; import { isOutOfStock } from "features/merch/functions"; +import { MerchLayout } from "@/features/layout/components"; const MerchandiseList = () => { const [selectedCategory, setSelectedCategory] = useState(""); @@ -16,15 +17,6 @@ const MerchandiseList = () => { {} ); - const { data: status, isLoading: isStatusLoading } = useQuery( - [QueryKeys.STATUS], - () => api.getMerchSaleStatus(), - {} - ); - - const displayText = status?.displayText; - const disabled = status?.disabled; - const categories = products?.map((product: Product) => product?.category); const uniqueCategories = categories ?.filter((c, idx) => categories.indexOf(c) === idx) @@ -36,86 +28,70 @@ const MerchandiseList = () => { setSelectedCategory(event.target.value); }; - if (isStatusLoading) { - return ( - - - - ); - } - return ( - - {disabled ? ( - - - {displayText} + + + + + New Drop + - ) : ( - <> - - - New Drop - - - - - {isProductsLoading ? ( - - ) : ( - - {products - ?.filter((product: Product) => { - if (!product?.is_available) return false; - if (selectedCategory === "") return true; - return product?.category === selectedCategory; - }) - ?.map((item: Product, idx: number) => ( - - ))} - - )} - - )} - + + )} + + ); }; diff --git a/apps/web/pages/merch/orders/[slug].tsx b/apps/web/pages/merch/orders/index.tsx similarity index 73% rename from apps/web/pages/merch/orders/[slug].tsx rename to apps/web/pages/merch/orders/index.tsx index 5f9e8a52..397c1836 100644 --- a/apps/web/pages/merch/orders/[slug].tsx +++ b/apps/web/pages/merch/orders/index.tsx @@ -1,20 +1,31 @@ import React, { useState } from "react"; import { useRouter } from "next/router"; -import { Image, Badge, Button, Divider, Flex, Heading, Text, useBreakpointValue } from "@chakra-ui/react"; +import { + Image, + Badge, + Button, + Divider, + Flex, + Heading, + Text, + useBreakpointValue, +} from "@chakra-ui/react"; import { useQuery } from "@tanstack/react-query"; -import { Page } from "ui/components/merch"; +import { Page } from "ui/components/merch"; import { Order, OrderStatus } from "types"; import { api } from "features/merch/services/api"; import { routes } from "features/merch/constants/routes"; import { QueryKeys } from "features/merch/constants/queryKeys"; import { displayPrice } from "features/merch/functions/currency"; -import Link from "next/link" +import Link from "next/link"; import LoadingScreen from "ui/components/merch/skeleton/LoadingScreen"; import { getOrderStatusColor, renderOrderStatus } from "merch-helpers"; import OrderItem from "ui/components/merch/OrderItem"; +import { MerchLayout } from "@/features/layout/components"; const OrderSummary: React.FC = () => { -// Check if break point hit. KIV - const isMobile: boolean = useBreakpointValue({ base: true, md: false }) || false; + // Check if break point hit. KIV + const isMobile: boolean = + useBreakpointValue({ base: true, md: false }) || false; const router = useRouter(); const orderSlug = router.query.slug as string | undefined; @@ -66,20 +77,25 @@ const OrderSummary: React.FC = () => { flexDir="column" >
- + - {renderOrderStatus(orderState?.status ?? OrderStatus.PENDING_PAYMENT)} + {renderOrderStatus( + orderState?.status ?? OrderStatus.PENDING_PAYMENT + )} Order Number - - {orderState?.id.split("-")[0]} - + {orderState?.id.split("-")[0]} {orderState?.id} @@ -87,8 +103,8 @@ const OrderSummary: React.FC = () => { Order date:{" "} {orderState?.transaction_time ? new Date(`${orderState.transaction_time}`).toLocaleString( - "en-sg" - ) + "en-sg" + ) : ""} {/*Last update: {orderState?.lastUpdate}*/} @@ -96,16 +112,23 @@ const OrderSummary: React.FC = () => {
- + Order Number - {renderOrderStatus(orderState?.status ?? OrderStatus.PENDING_PAYMENT)} + {renderOrderStatus( + orderState?.status ?? OrderStatus.PENDING_PAYMENT + )} @@ -120,8 +143,8 @@ const OrderSummary: React.FC = () => { Order date:{" "} {orderState?.transaction_time ? new Date(`${orderState.transaction_time}`).toLocaleString( - "en-sg" - ) + "en-sg" + ) : ""} {/*Last update: {orderState?.lastUpdate}*/} @@ -133,8 +156,11 @@ const OrderSummary: React.FC = () => { {/* */} {/*))}*/} - {orderState? : Order Not Found} - + {orderState ? ( + + ) : ( + Order Not Found + )} @@ -144,12 +170,11 @@ const OrderSummary: React.FC = () => { {displayPrice(total)} - + {/*{displayPrice( TODO*/} {/* (orderState?.billing?.subtotal ?? 0) -*/} {/* (orderState?.billing?.total ?? 0)*/} - {/*)}*/} - 0 + {/*)}*/}0 {displayPrice(total)} @@ -169,7 +194,10 @@ const OrderSummary: React.FC = () => { QRCode { sizes="(max-width: 768px)" /> - Please screenshot this QR code and show it at SCSE Lounge to collect your order. - Alternatively, show the email receipt you have received. + Please screenshot this QR code and show it at SCSE Lounge to collect + your order. Alternatively, show the email receipt you have received. For any assistance, please contact our email address: @@ -191,9 +219,15 @@ const OrderSummary: React.FC = () => { const renderSummaryPage = () => { if (isLoading) return ; //rmb to change this v - if (orderState === undefined || orderState === null){return ;} + if (orderState === undefined || orderState === null) { + return ; + } return renderOrderSummary(); }; - return {renderSummaryPage()}; -} -export default OrderSummary + return ( + + {renderSummaryPage()} + + ); +}; +export default OrderSummary; diff --git a/apps/web/pages/merch/product/[slug].tsx b/apps/web/pages/merch/product/[slug].tsx index 4085d159..a028586a 100644 --- a/apps/web/pages/merch/product/[slug].tsx +++ b/apps/web/pages/merch/product/[slug].tsx @@ -33,7 +33,9 @@ import { QueryKeys, routes } from "features/merch/constants"; import { displayPrice, displayQtyInCart, - displayStock, getDefaultColor, getDefaultSize, + displayStock, + getDefaultColor, + getDefaultSize, getQtyInCart, getQtyInStock, isColorAvailable, @@ -43,6 +45,7 @@ import { import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from "next"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/features/merch/services/api"; +import { MerchLayout } from "@/features/layout/components"; interface GroupTitleProps { children: React.ReactNode; @@ -54,7 +57,9 @@ const GroupTitle = ({ children }: GroupTitleProps) => ( ); -const MerchDetail = (_props: InferGetStaticPropsType) => { +const MerchDetail = ( + _props: InferGetStaticPropsType +) => { // Context hook. const { state: cartState, dispatch: cartDispatch } = useCartStore(); const router = useRouter(); @@ -412,7 +417,7 @@ const MerchDetail = (_props: InferGetStaticPropsType) => return renderMerchDetails(); }; - return {renderMerchPage()}; + return {renderMerchPage()}; }; export default MerchDetail; @@ -424,6 +429,17 @@ export const getStaticProps: GetStaticProps<{ console.log("generating static props for /merch/product/[slug]"); console.log("params", JSON.stringify(params)); + // Had to call this twice + const { disabled: merchDisabled } = await api.getMerchSaleStatus(); + if (merchDisabled) { + return { + redirect: { + destination: "/merch", + permanent: false, + }, + }; + } + // TODO: replace this with trpc/react-query call if (!process.env.NEXT_PUBLIC_MERCH_API_ORIGIN) { throw new Error("NEXT_PUBLIC_MERCH_API_ORIGIN is not defined"); @@ -451,6 +467,14 @@ export const getStaticProps: GetStaticProps<{ export const getStaticPaths: GetStaticPaths = async () => { console.log("generating static paths for /merch/product/[slug]"); + const { disabled: merchDisabled } = await api.getMerchSaleStatus(); + if (merchDisabled) { + return { + paths: [], + fallback: "blocking", + }; + } + // TODO: replace this with trpc/react-query call if (!process.env.NEXT_PUBLIC_MERCH_API_ORIGIN) { throw new Error("NEXT_PUBLIC_MERCH_API_ORIGIN is not defined");