Skip to content

Commit

Permalink
Port thank you page (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
meisterisk authored and chanbakjsd committed Jun 28, 2023
1 parent a43a14c commit 4f52a32
Show file tree
Hide file tree
Showing 16 changed files with 364 additions and 106 deletions.
1 change: 1 addition & 0 deletions apps/web/.env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
WORDPRESS_API_URL=
NEXT_PUBLIC_MERCH_API_ORIGIN=
NEXT_PUBLIC_FRONTEND_URL='https://clubs.ntu.edu.sg/csec/'
7 changes: 3 additions & 4 deletions apps/web/features/merch/services/api.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Product } from "types/lib/merch";
import { Product } from 'types'

export class Api {
private API_ORIGIN: string;
Expand Down Expand Up @@ -64,8 +64,7 @@ export class Api {
}
}

/*
async getOrder(userId: string, orderId: string) {
async getOrder(orderId: string) {
try {
const res = await this.get(`/orders/${orderId}`);
console.log("Order Summary response:", res);
Expand All @@ -74,7 +73,7 @@ export class Api {
throw new Error(e);
}
}
/*
async getOrderHistory(userId: string) {
try {
const res = await this.get(`/orders/${userId}`);
Expand Down
6 changes: 6 additions & 0 deletions apps/web/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
transpilePackages: ['ui', 'merch-helpers'],
images: {
remotePatterns: [
{
Expand All @@ -19,6 +20,11 @@ const nextConfig = {
hostname: "cdn.ntuscse.com",
pathname: "/merch/products/images/**",
},
{
protocol:"https",
hostname: "api.qrserver.com",
pathname: "/merch/order/**"
}
],
},
transpilePackages: ["ui"],
Expand Down
1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@tanstack/react-query": "^4.26.1",
"@tanstack/react-query-devtools": "^4.26.1",
"framer-motion": "^7.6.4",
"merch-helpers": "*",
"next": "13.4.6",
"react": "18.2.0",
"react-bootstrap": "^2.5.0",
Expand Down
199 changes: 199 additions & 0 deletions apps/web/pages/merch/order-summary/[slug].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import React, { useState } from "react";
import { useRouter } from "next/router";
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 { 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 LoadingScreen from "ui/components/merch/skeleton/LoadingScreen";
import { getOrderStatusColor, renderOrderStatus } from "merch-helpers";
import OrderItem from "ui/components/merch/OrderItem";
const OrderSummary: React.FC = () => {
// 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;

const [showThankYou, setShowThankYou] = useState<boolean>(false);
const [orderState, setOrderState] = useState<Order | null>(null);
// TODO: Fetch subtotal and total from server.
const [total, setTotal] = useState(0);
// Fetch and check if cart item is valid. Number(item.price) set to convert string to num
const { isLoading } = useQuery(
[QueryKeys.ORDER, orderSlug],
() => api.getOrder(orderSlug),
{
onSuccess: (data: Order) => {
console.log(data);
setOrderState(data);
setTotal(
data.items.reduce((acc, item) => {
return Number(item.price) * item.quantity + acc;
}, 0)
);
setShowThankYou(true);
},
}
);

const renderThankYouMessage = () => (
<>
<Heading size="xl">THANK YOU</Heading>
<Text>Thank you for your purchase. We have received your order.</Text>
<Link href={routes.HOME}>
<Button borderRadius={0} size="sm">
CONTINUE SHOPPING
</Button>
</Link>
<Divider my={8} />
</>
);
const renderOrderSummary = () => (
<>
<Flex flexDirection="column" alignItems="center" rowGap={3}>
{showThankYou && renderThankYouMessage()}
</Flex>

<Flex
p={6}
borderWidth="1px"
borderRadius="lg"
overflow="hidden"
flexDir="column"
>
<div>
<Flex display= { { base: "flex", md: "none" } } justifyContent="space-between">
<Flex flexDir="column" w="100%">
<Badge
width="fit-content"
fontSize="sm"
mb={2}
color={getOrderStatusColor(orderState?.status ?? OrderStatus.PENDING_PAYMENT)}
>
{renderOrderStatus(orderState?.status ?? OrderStatus.PENDING_PAYMENT)}
</Badge>
<Heading size="md">Order Number</Heading>
<Heading size="lg">
{orderState?.id.split("-")[0]}
</Heading>
<Flex alignItems="center" mb={2}>
<Text fontSize="sm">{orderState?.id}</Text>
</Flex>
<Text fontSize="sm" color="grey">
Order date:{" "}
{orderState?.transaction_time
? new Date(`${orderState.transaction_time}`).toLocaleString(
"en-sg"
)
: ""}
</Text>
{/*<Text>Last update: {orderState?.lastUpdate}</Text>*/}
</Flex>
</Flex>
</div>
<div>
<Flex display= { { base: "none", md: "flex" } } justifyContent="space-between">
<Flex flexDir="column">
<Flex alignItems="center" gap={6}>
<Heading size="md">Order Number</Heading>
<Badge
width="fit-content"
fontSize="sm"
color={getOrderStatusColor(orderState?.status ?? OrderStatus.PENDING_PAYMENT)}
>
{renderOrderStatus(orderState?.status ?? OrderStatus.PENDING_PAYMENT)}
</Badge>
</Flex>
<Heading size="lg" mb={2}>
{orderState?.id.split("-")[0]}
</Heading>
<Flex alignItems="center">
<Text fontSize="sm">{orderState?.id}</Text>
</Flex>
</Flex>
<Flex flexDir="column" fontSize="sm" color="grey">
<Text>
Order date:{" "}
{orderState?.transaction_time
? new Date(`${orderState.transaction_time}`).toLocaleString(
"en-sg"
)
: ""}
</Text>
{/*<Text>Last update: {orderState?.lastUpdate}</Text>*/}
</Flex>
</Flex>
</div>
<Divider my={4} />
{/*{orderState?.items.map((item) => (*/}
{/* <OrderItem data={item} isMobile={isMobile} />*/}
{/*))}*/}

{orderState? <OrderItem isMobile={isMobile} orderData={orderState}/>: <Text>Order Not Found</Text>}


<Flex alignItems="end" flexDirection="row" gap={1} mt={4}>
<Flex flexDir="column" flex={1} textAlign="end" fontWeight={500}>
<Text>Item Subtotal:</Text>
<Text>Voucher Discount:</Text>
<Text>Total:</Text>
</Flex>
<Flex flexDir="column" textAlign="end">
<Text fontSize="md"> {displayPrice(total)}</Text>
<Text fontSize="md">
{/*{displayPrice(*/}
{/* (orderState?.billing?.subtotal ?? 0) -*/}
{/* (orderState?.billing?.total ?? 0)*/}
{/*)}*/}
0
</Text>
<Text fontSize="md">{displayPrice(total)}</Text>
</Flex>
</Flex>
</Flex>

<Flex
mt={6}
alignItems="center"
py={3}
borderRadius="lg"
borderWidth="1px"
flexDirection="column"
rowGap={4}
>
{/* TODO: QR Code generator based on Param. */}
<Image
src={
orderState
? `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${ process.env.NEXT_PUBLIC_FRONTEND_URL ?? "localhost:3001"}/merch/orderSummary/${orderState?.id}`
: ""
}
alt="QRCode"
width={150}
height={150}
sizes="(max-width: 768px)"
/>
<Text fontWeight="bold">
Please screenshot this QR code and show it at SCSE Lounge to collect your order.
Alternatively, show the email receipt you have received.
</Text>
<Text>
For any assistance, please contact our email address:
merch@ntuscse.com
</Text>
</Flex>
</>
);
const renderSummaryPage = () => {
if (isLoading) return <LoadingScreen text="Fetching order detail" />;
//rmb to change this v
if (orderState === undefined || orderState === null){return <LoadingScreen text="Order Does Not Exist" />;}
return renderOrderSummary();
};
return <Page>{renderSummaryPage()}</Page>;
}
export default OrderSummary
3 changes: 3 additions & 0 deletions packages/merch-helpers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# merch-helpers

todo...
16 changes: 16 additions & 0 deletions packages/merch-helpers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "merch-helpers",
"version": "0.0.1",
"main": "src/index.ts",
"license": "Apache-2.0",
"scripts": {
"lint": "TIMING=1 eslint \"**/*.ts*\"",
"lint:fix": "TIMING=1 eslint --fix \"**/*.ts*\""
},
"devDependencies": {
"eslint": "^7.32.0",
"eslint-config-custom": "*",
"tsconfig": "*",
"typescript": "^4.5.2"
}
}
2 changes: 2 additions & 0 deletions packages/merch-helpers/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./lib/orderstatus";
export * from "./lib/price";
26 changes: 26 additions & 0 deletions packages/merch-helpers/src/lib/orderstatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { OrderStatus } from 'types'
export const renderOrderStatus = (status: OrderStatus) => {
switch (status) {
case OrderStatus.ORDER_COMPLETED:
return "Order Collected";
case OrderStatus.PAYMENT_COMPLETED:
return "Processing";
case OrderStatus.PENDING_PAYMENT:
return "Order Received";
default:
return "Item Delayed";
}
};

export const getOrderStatusColor = (status: OrderStatus) => {
switch (status) {
case OrderStatus.ORDER_COMPLETED:
return "green.500";
case OrderStatus.PAYMENT_COMPLETED:
return "primary.400";
case OrderStatus.PENDING_PAYMENT:
return "primary.600";
default:
return "red.500";
}
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Cart, PricedCart, Product, Promotion } from "types";
import { Cart, PricedCart, Product, Promotion, PromoType } from "types";

export const calculatePricing = (
products: Product[],
Expand Down Expand Up @@ -33,10 +33,10 @@ export const calculatePricing = (
continue;
}
switch (discount.promoType) {
case FIXED_VALUE:
case PromoType.FIXED_VALUE:
itemPrice -= discount.promoValue;
break;
case PERCENTAGE:
case PromoType.PERCENTAGE:
itemPrice *= 1 - discount.promoValue;
itemPrice = Math.floor(itemPrice);
break;
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion packages/types/lib/merch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export interface PricedCart {
}[];
}

enum PromoType {
export enum PromoType {
PERCENTAGE = "PERCENTAGE",
FIXED_VALUE = "FIXED_VALUE",
}
Expand Down
Loading

0 comments on commit 4f52a32

Please sign in to comment.