From 47834f2f17fae4d24569827018d22ab259dc2939 Mon Sep 17 00:00:00 2001 From: ngyngcphu Date: Mon, 4 Dec 2023 19:38:29 +0700 Subject: [PATCH] feat(order-success): create ui for Order Success Form version mobile --- src/components/home/Orders.tsx | 19 +- src/components/order/common/OrderWorkflow.tsx | 9 +- .../order/mobile/ConfirmOrderForm.tsx | 38 ++-- .../order/mobile/OrderSuccessForm.tsx | 182 +++++++++--------- .../order/mobile/TopupWalletForm.tsx | 137 +++++++------ src/hooks/index.ts | 1 - src/hooks/useExchangeRateQuery.hook.ts | 21 -- src/hooks/usePrintingRequestMutation.hook.ts | 26 ++- src/hooks/usePrintingRequestQuery.hook.ts | 27 ++- src/services/configuration.service.ts | 3 +- src/types/home.d.ts | 11 ++ 11 files changed, 274 insertions(+), 200 deletions(-) delete mode 100644 src/hooks/useExchangeRateQuery.hook.ts create mode 100644 src/types/home.d.ts diff --git a/src/components/home/Orders.tsx b/src/components/home/Orders.tsx index 26f0497..74a122e 100644 --- a/src/components/home/Orders.tsx +++ b/src/components/home/Orders.tsx @@ -9,6 +9,11 @@ import { printingRequestService } from '@services'; import { retryQueryFn } from '@utils'; export function Orders() { + const { data: orders } = useQuery({ + queryKey: ['/api/printRequest'], + queryFn: () => printingRequestService.getPrintingRequest(), + retry: retryQueryFn + }); const sliderRef = useRef(null); const scrollLeft = () => { @@ -22,12 +27,6 @@ export function Orders() { } }; - const { data: orders } = useQuery({ - queryKey: ['/api/printRequest'], - queryFn: () => printingRequestService.getPrintingRequest(), - retry: retryQueryFn - }); - return (
@@ -49,7 +48,7 @@ export function Orders() { {order.status} - {order.id.slice(8, order.id.length)} + {`#${order.id.slice(0, 4)}-${order.id.slice(4, 8)}`}
{order.filesName[0]} @@ -57,7 +56,11 @@ export function Orders() {
- {order.location} + + {order.location.length > 0 + ? order.location.length + : 'Tiệm in thư viện H3, tầng 1'} +

diff --git a/src/components/order/common/OrderWorkflow.tsx b/src/components/order/common/OrderWorkflow.tsx index 924a227..93e756a 100644 --- a/src/components/order/common/OrderWorkflow.tsx +++ b/src/components/order/common/OrderWorkflow.tsx @@ -52,11 +52,16 @@ export function useOrderWorkflow() { /> ); } else if (mobileOrderStep.current === 3) { - return ; + return ; } else if (mobileOrderStep.current === 4) { return ; } else if (mobileOrderStep.current === 5) { - return ; + return ( + setOpenDialog(false)} + initialTotalCost={initialTotalCost} + /> + ); } } else { if (desktopOrderStep === 0) { diff --git a/src/components/order/mobile/ConfirmOrderForm.tsx b/src/components/order/mobile/ConfirmOrderForm.tsx index 22594c1..6e5a029 100644 --- a/src/components/order/mobile/ConfirmOrderForm.tsx +++ b/src/components/order/mobile/ConfirmOrderForm.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { MutableRefObject, useEffect, useMemo } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { Alert, Button, Typography } from '@material-tailwind/react'; import { @@ -20,15 +20,22 @@ import { usePrintingRequestQuery } from '@hooks'; import { useOrderPrintStore, useOrderWorkflowStore } from '@states'; import { formatFileSize } from '@utils'; -export function ConfirmOrderForm() { +export const ConfirmOrderForm: Component<{ initialTotalCost: MutableRefObject }> = ({ + initialTotalCost +}) => { const queryClient = useQueryClient(); const remainCoins = queryClient.getQueryData(['/api/user/remain-coins']); const { - listFiles: { data: listFiles, isFetching, isError } + listFiles: { data: listFiles, isFetching, isError }, + serviceFee: { data: serviceFee } } = usePrintingRequestQuery(); const { mobileOrderStep, setMobileOrderStep, setDesktopOrderStep } = useOrderWorkflowStore(); - const { totalCost, setIsOrderUpdate } = useOrderPrintStore(); + const { totalCost, setIsOrderUpdate, setTotalCost } = useOrderPrintStore(); + + useEffect(() => { + setTotalCost(initialTotalCost.current); + }, [initialTotalCost, setTotalCost]); const handleExistConfirmOrder = () => { setIsOrderUpdate(true); @@ -187,7 +194,7 @@ export function ConfirmOrderForm() {

coinImage - 2 + {serviceFee ?? 0}

  • @@ -196,22 +203,31 @@ export function ConfirmOrderForm() {

    coinImage - {totalCost + 2} + {totalCost + (serviceFee ?? 0)}

  • - + ); -} +}; diff --git a/src/components/order/mobile/OrderSuccessForm.tsx b/src/components/order/mobile/OrderSuccessForm.tsx index 9dab96c..4189e47 100644 --- a/src/components/order/mobile/OrderSuccessForm.tsx +++ b/src/components/order/mobile/OrderSuccessForm.tsx @@ -1,114 +1,108 @@ -//import { useOrderWorkflowStore } from '@states'; -import { Button, Card, CardBody, Typography } from '@material-tailwind/react'; +import { MutableRefObject } from 'react'; +import { Button, Card, CardBody, IconButton, Typography } from '@material-tailwind/react'; +import { CheckIcon, DocumentChartBarIcon } from '@heroicons/react/24/outline'; import { XMarkIcon } from '@heroicons/react/24/solid'; -import { CheckIcon } from '@heroicons/react/24/outline'; -import { DocumentChartBarIcon } from '@heroicons/react/24/outline'; -import coin from '@assets/coin.png'; -// Tue's second-task in here. -export function OrderSuccessForm() { - //const { setMobileOrderStep } = useOrderWorkflowStore(); - const detail_order = [ - { - name: 'Order number', - detail: '#1234-5678' - }, - { - name: 'Pick-up location', - detail: 'Tiệm in thư viện H3, tầng 1' - }, - { - name: 'Print cost', - detail: '2.400', - coin: true - }, - { - name: 'Service cost', - detail: '2', - coin: true - }, - { - name: 'Total', - detail: '2.402', - coin: true - } - ]; +import coinImage from '@assets/coin.png'; +import { usePrintingRequestQuery } from '@hooks'; +import { useOrderPrintStore } from '@states'; + +export const OrderSuccessForm: Component<{ + handleCloseOrderForm: () => void; + initialTotalCost: MutableRefObject; +}> = ({ handleCloseOrderForm, initialTotalCost }) => { + const { + serviceFee: { data: serviceFee } + } = usePrintingRequestQuery(); + const { totalCost, setIsFileUploadSuccess, setTotalCost } = useOrderPrintStore(); + + const handleExistOrderSuccessForm = () => { + setIsFileUploadSuccess(false); + setTotalCost(0); + initialTotalCost.current = 0; + handleCloseOrderForm(); + }; + return ( <> - - -
    - Other success - { - // setOrderStep(1); - // }} - /> -
    -
    -
    +
    + Other success + + + +
    - Your payment success' + Your payment success
    - - Order details + +

    Order details

    -
    - -
    -
    - {detail_order.map((item, index) => ( -
    - - {`${item.name}:`} - -
    - {item.coin && ( - - )} - - {item.detail} - -
    +
    +
    +
    +

    Order number:

    +

    {`#1234-5678`}

    - ))} +
    +

    Pick-up location:

    +

    Tiệm in thư viện H3, tầng 1

    +
    +
    +
      +
    • + + Print cost: + +

      + coinImage + {totalCost} +

      +
    • +
    • + + Service cost: + +

      + coinImage + {serviceFee ?? 0} +

      +
    • +
    • + + Total cost: + +

      + coinImage + {totalCost + (serviceFee ?? 0)} +

      +
    • +
    +
    -
    - - -
    +
    + + +
    ); -} +}; diff --git a/src/components/order/mobile/TopupWalletForm.tsx b/src/components/order/mobile/TopupWalletForm.tsx index 423e30f..b5a5e51 100644 --- a/src/components/order/mobile/TopupWalletForm.tsx +++ b/src/components/order/mobile/TopupWalletForm.tsx @@ -1,5 +1,6 @@ -import { ReactElement, useState, useRef } from 'react'; +import { ReactElement, useState, useRef, useMemo } from 'react'; import { useQueryClient } from '@tanstack/react-query'; +import { PayPalButtons } from '@paypal/react-paypal-js'; import { Alert, Button, Card, CardBody, Input, Typography } from '@material-tailwind/react'; import { BanknotesIcon, @@ -18,37 +19,42 @@ import { import coinImage from '@assets/coin.png'; import paypal from '@assets/paypal.png'; import { SUGGEST_AMOUNT } from '@constants'; -import { useExchangeRateQuery } from '@hooks'; +import { usePrintingRequestQuery, usePrintingRequestMutation } from '@hooks'; +import { useOrderWorkflowStore } from '@states'; export function TopupWalletForm() { const queryClient = useQueryClient(); const { exchangeRate: [coinPerPage, coinPerDollar] - } = useExchangeRateQuery(); + } = usePrintingRequestQuery(); + const { createPayPalOrder, approvePayPalOrder } = usePrintingRequestMutation(); + const { setMobileOrderStep } = useOrderWorkflowStore(); + const inputRef = useRef(null); const ExchangeRateInfo = () => { const CHEVRON_CLASSNAME = 'w-5 h-5 opacity-40 hover:text-[#0F172A] hover:opacity-100 focus:opacity-100 active:opacity-100'; const [chevronIcon, setChevronIcon] = useState(false); - const ExchangeRateRow: Component<{ title: string; coins?: number; children: ReactElement }> = ({ - title, - coins, - children - }) => ( -
    -

    {title}

    -
    - {coins !== undefined &&

    {coins}

    } - coinImage -

    =

    -
    -

    1

    - {children} -
    -
    -
    - ); + const ExchangeRateRow: Component<{ title: string; coins?: number; children: ReactElement }> = + useMemo( + () => + ({ title, coins, children }) => ( +
    +

    {title}

    +
    + {coins !== undefined &&

    {coins}

    } + coinImage +

    =

    +
    +

    1

    + {children} +
    +
    +
    + ), + [] + ); return ( @@ -93,9 +99,8 @@ export function TopupWalletForm() { const TopupAmountInput = () => { const remainCoins = queryClient.getQueryData(['/api/user/remain-coins']); + const [amountInputValue, setAmountInputValue] = useState(''); const [showInfo, setShowInfo] = useState(false); - const [inputValue, setInputValue] = useState(''); - const inputRef = useRef(null); return ( @@ -119,7 +124,7 @@ export function TopupWalletForm() { !inputRef.current?.value && setShowInfo(false)} onChange={(e) => { - setInputValue(e.target.value); + setAmountInputValue(e.target.value); setShowInfo(true); }} maxLength={10} @@ -142,7 +147,7 @@ export function TopupWalletForm() { { - setInputValue(''); + setAmountInputValue(''); setShowInfo(false); }} /> @@ -152,7 +157,7 @@ export function TopupWalletForm() { coinImage

    {Math.floor( - parseFloat(inputValue.replace(/[^0-9.]/g, '') || '0') * + parseFloat(amountInputValue.replace(/[^0-9.]/g, '') || '0') * (coinPerDollar.data ?? 1) )}

    @@ -165,13 +170,13 @@ export function TopupWalletForm() { alt='coinImage' > - {Math.floor(parseInt(inputValue.replace(/[^0-9.]/g, '') || '0') / 10) * + {Math.floor(parseInt(amountInputValue.replace(/[^0-9.]/g, '') || '0') / 10) * (coinPerDollar.data ?? 1)} )
    - {parseFloat(inputValue.replace(/[^0-9.]/g, '')) < 1 && ( + {parseFloat(amountInputValue.replace(/[^0-9.]/g, '') || '0') < 1 && (
    @@ -183,7 +188,7 @@ export function TopupWalletForm() {
    { - setInputValue(item); + setAmountInputValue(item); setShowInfo(true); }} > @@ -205,7 +210,7 @@ export function TopupWalletForm() { Bonus: coinImage - {coinPerDollar.data} + {coinPerDollar.data ? coinPerDollar.data : 0} (for every 10$) @@ -216,24 +221,27 @@ export function TopupWalletForm() { ); }; - const PaymentMethod = () => ( - - -
    - -

    Payment Method

    -
    -
    -
    - paypal -
    -

    Pay with PayPal wallet

    -

    Redirect to PayPal

    + const PaymentMethod = useMemo( + () => () => ( + + +
    + +

    Payment Method

    +
    +
    +
    + paypal +
    +

    Pay with PayPal wallet

    +

    Redirect to PayPal

    +
    -
    - - + + + ), + [] ); return ( @@ -243,7 +251,12 @@ export function TopupWalletForm() {
    setOrderStep(2)} + onClick={() => + setMobileOrderStep({ + current: 3, + prev: 4 + }) + } /> Top up wallet
    @@ -254,14 +267,24 @@ export function TopupWalletForm() {
    -
    - -
    + + createPayPalOrder.mutateAsync( + parseFloat(inputRef.current?.value.replace(/[^0-9.]/g, '') || '0') + ) + } + onApprove={async () => { + const paypalOrderId = queryClient.getQueryData(['paypalOrderId']); + if (!paypalOrderId) return; + await approvePayPalOrder.mutateAsync(paypalOrderId); + setMobileOrderStep({ + current: 3, + prev: 4 + }); + }} + /> ); } diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 05854d1..478fa76 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -3,7 +3,6 @@ */ export * from './useEvent'; -export * from './useExchangeRateQuery.hook'; export * from './usePrintingRequestMutation.hook'; export * from './usePrintingRequestQuery.hook'; export * from './useScreenSize'; diff --git a/src/hooks/useExchangeRateQuery.hook.ts b/src/hooks/useExchangeRateQuery.hook.ts deleted file mode 100644 index 91ea221..0000000 --- a/src/hooks/useExchangeRateQuery.hook.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useQueries } from '@tanstack/react-query'; -import { configurationService } from '@services'; - -export function useExchangeRateQuery() { - const exchangeRate = useQueries({ - queries: [ - { - queryKey: ['/api/configuration/coinPerPage'], - queryFn: () => configurationService.getCoinPerPage() - }, - { - queryKey: ['/api/configuration/dollarToCoin'], - queryFn: () => configurationService.getCoinPerDollar() - } - ] - }); - - return { - exchangeRate: exchangeRate - }; -} diff --git a/src/hooks/usePrintingRequestMutation.hook.ts b/src/hooks/usePrintingRequestMutation.hook.ts index 1d061ca..ad55f8b 100644 --- a/src/hooks/usePrintingRequestMutation.hook.ts +++ b/src/hooks/usePrintingRequestMutation.hook.ts @@ -1,5 +1,5 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { printingRequestService } from '@services'; +import { printingRequestService, buyCoinService, userService } from '@services'; export function usePrintingRequestMutation() { const queryClient = useQueryClient(); @@ -50,12 +50,34 @@ export function usePrintingRequestMutation() { printingRequestService.cancelPrintingRequest(printingRequestId) }); + const createPayPalOrder = useMutation({ + mutationKey: ['createPayPalOrder'], + mutationFn: (dollar: number) => + buyCoinService.createPayPalOrder(dollar).then((order) => order.id), + onSuccess: (data) => { + queryClient.setQueryData(['paypalOrderId'], data); + } + }); + + const approvePayPalOrder = useMutation({ + mutationKey: ['approvePayPalOrder'], + mutationFn: (orderId: string) => buyCoinService.approvePayPalOrder(orderId), + onSuccess: () => { + queryClient.prefetchQuery({ + queryKey: ['/api/user/remain-coins'], + queryFn: () => userService.getRemainCoins() + }); + } + }); + return { createPrintingRequest: createPrintingRequest, uploadFile: uploadFile, uploadFileConfig: uploadFileConfig, deleteFile: deleteFile, updateAmountFile: updateAmountFile, - cancelPrintingRequest: cancelPrintingRequest + cancelPrintingRequest: cancelPrintingRequest, + createPayPalOrder: createPayPalOrder, + approvePayPalOrder: approvePayPalOrder }; } diff --git a/src/hooks/usePrintingRequestQuery.hook.ts b/src/hooks/usePrintingRequestQuery.hook.ts index 271d096..5fc3ad1 100644 --- a/src/hooks/usePrintingRequestQuery.hook.ts +++ b/src/hooks/usePrintingRequestQuery.hook.ts @@ -1,5 +1,5 @@ -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { printingRequestService } from '@services'; +import { useQuery, useQueries, useQueryClient } from '@tanstack/react-query'; +import { printingRequestService, configurationService } from '@services'; import { retryQueryFn } from '@utils'; export function usePrintingRequestQuery() { @@ -19,7 +19,28 @@ export function usePrintingRequestQuery() { retry: retryQueryFn }); + const exchangeRate = useQueries({ + queries: [ + { + queryKey: ['/api/configuration/coinPerPage'], + queryFn: () => configurationService.getCoinPerPage() + }, + { + queryKey: ['/api/configuration/dollarToCoin'], + queryFn: () => configurationService.getCoinPerDollar() + } + ] + }); + + const serviceFee = useQuery({ + queryKey: ['/api/configuration/serviceFee'], + queryFn: () => configurationService.getServiceFee(), + retry: retryQueryFn + }); + return { - listFiles: listFiles + listFiles: listFiles, + exchangeRate: exchangeRate, + serviceFee: serviceFee }; } diff --git a/src/services/configuration.service.ts b/src/services/configuration.service.ts index a76233d..720d8b1 100644 --- a/src/services/configuration.service.ts +++ b/src/services/configuration.service.ts @@ -2,5 +2,6 @@ import { apiClient, invoke } from './common'; export const configurationService = { getCoinPerPage: () => invoke(apiClient.GET('/api/configuration/coinPerPage')), - getCoinPerDollar: () => invoke(apiClient.GET('/api/configuration/dollarToCoin')) + getCoinPerDollar: () => invoke(apiClient.GET('/api/configuration/dollarToCoin')), + getServiceFee: () => invoke(apiClient.GET('/api/configuration/serviceFee')) }; diff --git a/src/types/home.d.ts b/src/types/home.d.ts new file mode 100644 index 0000000..72325fc --- /dev/null +++ b/src/types/home.d.ts @@ -0,0 +1,11 @@ +type OrderInfo = { + id: string; + status: string; + location: string; + numFiles: number; + filesName: string[]; + numPages: number; + coins: number; + paid: string; + serviceFee: number; +};