Skip to content

Commit

Permalink
feat(edit-pdf): use util pdf-editor for configuration from back-end
Browse files Browse the repository at this point in the history
  • Loading branch information
ngyngcphu committed Dec 5, 2023
1 parent 94c3181 commit bbf92ff
Show file tree
Hide file tree
Showing 13 changed files with 566 additions and 110 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
"@react-oauth/google": "^0.12.1",
"@tanstack/react-query": "^5.8.4",
"@tanstack/react-table": "^8.10.7",
"buffer": "^6.0.3",
"moment": "^2.29.4",
"openapi-fetch": "^0.8.1",
"pdf-lib": "^1.17.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.4",
Expand Down
5 changes: 4 additions & 1 deletion src/components/order/desktop/ConfirmOrderDesktop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { usePrintingRequestQuery } from '@hooks';
import { useOrderPrintStore, useOrderWorkflowStore } from '@states';
import { formatFileSize } from '@utils';
import { usePreviewDocumentDesktop } from './PreviewDocumentDesktop';
import { useOrderSuccessDesktop } from './OrderSuccessDesktop';

export const ConfirmOrderDektop: Component<{ initialTotalCost: MutableRefObject<number> }> = ({
initialTotalCost
Expand All @@ -37,6 +38,7 @@ export const ConfirmOrderDektop: Component<{ initialTotalCost: MutableRefObject<
} = usePrintingRequestQuery();

const { openPreviewDocumentDesktop, PreviewDocumentDesktop } = usePreviewDocumentDesktop();
const { openOrderSuccessDesktop, OrderSuccessDesktop } = useOrderSuccessDesktop();

const { totalCost, setTotalCost } = useOrderPrintStore();
const { setDesktopOrderStep } = useOrderWorkflowStore();
Expand Down Expand Up @@ -240,7 +242,7 @@ export const ConfirmOrderDektop: Component<{ initialTotalCost: MutableRefObject<
? 'blue'
: 'gray'
}
onClick={() => setDesktopOrderStep(4)}
onClick={openOrderSuccessDesktop}
disabled={!remainCoins || remainCoins < totalCost + (serviceFee ?? 0)}
>
Confirm Order
Expand All @@ -249,6 +251,7 @@ export const ConfirmOrderDektop: Component<{ initialTotalCost: MutableRefObject<
</div>
</div>
{<PreviewDocumentDesktop />}
{<OrderSuccessDesktop initialTotalCost={initialTotalCost} serviceFee={serviceFee} />}
</>
);
};
199 changes: 109 additions & 90 deletions src/components/order/desktop/OrderSuccessDesktop.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,45 @@
import { Button, Card, CardBody, Typography } from '@material-tailwind/react';
import { CheckIcon } from '@heroicons/react/24/outline';
import { DocumentChartBarIcon } from '@heroicons/react/24/outline';
import coin from '@assets/coin.png';
import { MutableRefObject, useState } from 'react';
import {
Button,
Card,
CardBody,
Dialog,
DialogBody,
DialogHeader,
IconButton,
Typography
} from '@material-tailwind/react';
import { CheckIcon, DocumentChartBarIcon, XMarkIcon } from '@heroicons/react/24/outline';
import coinImage from '@assets/coin.png';
import { useOrderPrintStore, useOrderWorkflowStore } from '@states';

export function OrderSuccessDesktop() {
// const { setOrderStep } = 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
}
];
return (
<>
<div className='flex flex-col justify-center items-center'>
<Card className='w-[576px]'>
<div className='flex flex-col justify-center items-center pt-6 mb-[64px]'>
<div className='w-[88px] h-[88px] p-5 rounded-full bg-[#DBEAFE]'>
export function useOrderSuccessDesktop() {
const [openDialog, setOpenDialog] = useState<boolean>(false);

const OrderSuccessDesktop: Component<{
initialTotalCost: MutableRefObject<number>;
serviceFee?: number;
}> = ({ initialTotalCost, serviceFee }) => {
const { totalCost, setTotalCost, setIsFileUploadSuccess } = useOrderPrintStore();
const { setDesktopOrderStep } = useOrderWorkflowStore();

const handleExistOrderSuccessForm = () => {
setIsFileUploadSuccess(false);
setTotalCost(0);
initialTotalCost.current = 0;
setDesktopOrderStep(0);
};

return (
<Dialog size='xs' open={openDialog} handler={() => setOpenDialog(false)}>
<DialogHeader className='p-0'>
<IconButton variant='text' onClick={() => setOpenDialog(false)}>
<XMarkIcon className='w-6 h-6' />
</IconButton>
</DialogHeader>
<DialogBody>
<div className='w-full flex flex-col justify-center items-center h-32 overscroll-y-auto'>
<div className='p-5 rounded-full bg-[#DBEAFE]'>
<CheckIcon className='w-12 h-12 text-blue/1' />
</div>
<Typography className='text-blue/1 text-2xl font-bold mt-4'>
Expand All @@ -45,62 +49,77 @@ export function OrderSuccessDesktop() {
<Card className='rounded-none shadow-none'>
<CardBody>
<div className='flex items-center'>
<DocumentChartBarIcon className='w-5 h-5 text-blue/1 mr-2' />
<Typography className='text-gray/4 text-base font-medium '>
Order details
</Typography>
<DocumentChartBarIcon strokeWidth={2} className='w-5 h-5 text-blue/1 mr-2' />
<p className='text-gray/4 text-lg font-medium '>Order details</p>
</div>
</CardBody>
<CardBody className='py-4 relative'>
<hr className='absolute w-[525px] border border-gray/2 top-[94px]' />
<div className='flex flex-col items-start gap-1'>
{detail_order.map((item, index) => (
<div className='flex justify-between' key={index}>
<Typography className='min-w-2/5 text-gray/4 text-base font-normal'>
{`${item.name}:`}
</Typography>
<div className='flex basis-1/2 items-center text-right justify-end'>
{item.coin && (
<img
className={index === 4 ? 'w-4 h-4' : 'w-4 h-4 mix-blend-luminosity'}
src={coin}
></img>
)}
<Typography
className={
index === 4
? 'text-[#D97706] text-base font-bold'
: 'text-gray/4 text-base font-medium '
}
>
{item.detail}
</Typography>
</div>
<div className='py-8'>
<div className='flex flex-col gap-1'>
<div className='flex justify-between items-center'>
<p className='text-gray/4 text-base font-normal'>Order number:</p>
<p className='text-gray/4 text-base font-medium'>{`#1234-5678`}</p>
</div>
<div className='flex justify-between items-center'>
<p className='text-gray/4 text-base font-normal'>Pick-up location:</p>
<p className='text-gray/4 text-base font-medium'>Tiệm in thư viện H3, tầng 1</p>
</div>
))}
<hr className='w-full border border-gray/2 my-2' />
<ul>
<li className='flex justify-between mb-1'>
<Typography variant='paragraph' className='font-medium'>
Print cost:
</Typography>
<p className='flex items-center gap-1 text-sm'>
<img src={coinImage} alt='coinImage' className='grayscale w-6 h-6' />
<span className='text-gray/4 font-normal'>{totalCost}</span>
</p>
</li>
<li className='flex justify-between mb-1'>
<Typography variant='paragraph' className='font-medium'>
Service cost:
</Typography>
<p className='flex items-center gap-1 text-sm'>
<img src={coinImage} alt='coinImage' className='grayscale w-6 h-6' />
<span className='text-gray/4 font-normal'>{serviceFee ?? 0}</span>
</p>
</li>
<li className='flex justify-between'>
<Typography variant='paragraph' className='font-bold'>
Total cost:
</Typography>
<p className='flex items-center gap-1'>
<img src={coinImage} alt='coinImage' className='w-6 h-6' />
<span className='text-yellow/1 font-bold'>
{totalCost + (serviceFee ?? 0)}
</span>
</p>
</li>
</ul>
</div>
</div>
</CardBody>
<div className='mt-4 flex flex-col items-center'>
<Button
className='px-4 py-2 rounded-lg bg-blue/1 h-[40px] normal-case hover:shadow-none'
ripple={false}
// onClick={()}
>
Track this order
</Button>

<Button
className='px-4 py-2 rounded-lg h-[40px] text-gray/3 text-sm font-semibold mt-2 normal-case hover:border hover:border-blue/1 hover:bg-white'
variant='text'
ripple={false}
// onClick={()}
>
Return home
</Button>
</div>
</Card>
</Card>
</div>
</>
);
<div className='flex flex-col items-center'>
<Button
className='px-4 py-2 rounded-lg bg-blue/1 normal-case text-sm hover:shadow-none'
onClick={handleExistOrderSuccessForm}
>
Track this order
</Button>
<Button
className='px-4 py-2 rounded-lg text-gray/3 text-sm font-semibold mt-2 normal-case hover:border hover:border-blue/1 hover:bg-white'
variant='text'
onClick={handleExistOrderSuccessForm}
>
Return home
</Button>
</div>
</DialogBody>
</Dialog>
);
};

return {
openOrderSuccessDesktop: () => setOpenDialog(true),
OrderSuccessDesktop: OrderSuccessDesktop
};
}
42 changes: 41 additions & 1 deletion src/components/order/desktop/UploadAndPreviewDesktop.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChangeEvent, MutableRefObject, useCallback } from 'react';
import { ChangeEvent, MutableRefObject, useCallback, useEffect } from 'react';
import DocViewer, { DocViewerRenderers } from '@cyntler/react-doc-viewer';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import type { Buffer } from 'buffer';
import { Button, IconButton, Input, Option, Radio, Select } from '@material-tailwind/react';
import { XMarkIcon } from '@heroicons/react/24/outline';
import { ExclamationCircleIcon } from '@heroicons/react/24/solid';
Expand All @@ -14,6 +15,8 @@ import {
import { LAYOUT_SIDE, FILE_CONFIG, PAGES_SPECIFIC, PAGES_PER_SHEET, PAGE_SIDE } from '@constants';
import { usePrintingRequestMutation, emitEvent } from '@hooks';
import { useOrderPrintStore, useOrderWorkflowStore } from '@states';
import { editPdf } from '@utils';
import type { PagePerSheet } from '@utils';

export const UploadAndPreviewDesktop: Component<{
initialTotalCost: MutableRefObject<number>;
Expand All @@ -27,6 +30,7 @@ export const UploadAndPreviewDesktop: Component<{
queryFn: () =>
fileIdCurrent ? queryClient.getQueryData<FileMetadata>(['fileMetadata', fileIdCurrent]) : null
});
const fileBuffer = queryClient.getQueryData<Buffer>(['fileBuffer']);

const { openLayoutSide, LayoutSide } = useLayoutSide();
const { openCloseForm, CloseForm } = useCloseForm();
Expand All @@ -50,6 +54,32 @@ export const UploadAndPreviewDesktop: Component<{
clearSpecificPageAndPageBothSide
} = useOrderPrintStore();

const { editPdfPrinting } = editPdf;

useEffect(() => {
const handleEditPdfPrinting = async () => {
if (fileBuffer) {
const fileEditedBuffer = await editPdfPrinting(
fileBuffer,
fileConfig.pageSide,
fileConfig.pages,
fileConfig.layout,
parseInt(fileConfig.pagesPerSheet) as PagePerSheet
);
queryClient.setQueryData(['fileURL'], URL.createObjectURL(new Blob([fileEditedBuffer])));
}
};
handleEditPdfPrinting();
}, [
fileBuffer,
fileConfig.layout,
fileConfig.pageSide,
fileConfig.pages,
fileConfig.pagesPerSheet,
queryClient,
editPdfPrinting
]);

const handlePageBothSide = useCallback(
(event: string) => {
setPageBothSide(event);
Expand Down Expand Up @@ -177,6 +207,16 @@ export const UploadAndPreviewDesktop: Component<{
queryKey: ['fileURL'],
queryFn: () => queryClient.getQueryData<string>(['fileURL'])
});

useEffect(() => {
return () => {
const revokeURL = queryClient.getQueryData<string>(['fileURL']);
if (revokeURL) {
URL.revokeObjectURL(revokeURL);
}
};
}, []);

const PreviewBody = () => {
return (
<DocViewer
Expand Down
21 changes: 14 additions & 7 deletions src/components/order/mobile/ConfirmOrderForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '@heroicons/react/24/solid';
import coinImage from '@assets/coin.png';
import { FormFooter } from '@components/order/common';
import { usePrintingRequestQuery } from '@hooks';
import { usePrintingRequestQuery, usePrintingRequestMutation } from '@hooks';
import { useOrderPrintStore, useOrderWorkflowStore } from '@states';
import { formatFileSize } from '@utils';

Expand All @@ -25,10 +25,13 @@ export const ConfirmOrderForm: Component<{ initialTotalCost: MutableRefObject<nu
}) => {
const queryClient = useQueryClient();
const remainCoins = queryClient.getQueryData<number>(['/api/user/remain-coins']);
const printingRequestId = queryClient.getQueryData<PrintingRequestId>(['printingRequestId']);

const {
listFiles: { data: listFiles, isFetching, isError },
serviceFee: { data: serviceFee }
} = usePrintingRequestQuery();
const { executePrintingRequest } = usePrintingRequestMutation();

const { mobileOrderStep, setMobileOrderStep, setDesktopOrderStep } = useOrderWorkflowStore();
const { totalCost, setIsOrderUpdate, setTotalCost } = useOrderPrintStore();
Expand All @@ -46,6 +49,15 @@ export const ConfirmOrderForm: Component<{ initialTotalCost: MutableRefObject<nu
setDesktopOrderStep(1);
};

const handleExecutePrintingRequest = async () => {
if (!printingRequestId) return;
await executePrintingRequest.mutateAsync(printingRequestId.id);
setMobileOrderStep({
current: 5,
prev: 3
});
};

const ConfirmOrderItem: Component<{ fileExtraMetadata: FileExtraMetadata }> = useMemo(
() =>
({ fileExtraMetadata }) => {
Expand Down Expand Up @@ -217,12 +229,7 @@ export const ConfirmOrderForm: Component<{ initialTotalCost: MutableRefObject<nu
: 'gray'
}
className='rounded-none w-[30%]'
onClick={() =>
setMobileOrderStep({
current: 5,
prev: 3
})
}
onClick={handleExecutePrintingRequest}
disabled={!remainCoins || remainCoins < totalCost + (serviceFee ?? 0)}
>
<span className='text-base'>Confirm</span>
Expand Down
Loading

0 comments on commit bbf92ff

Please sign in to comment.