feat: receipt send mail preview

This commit is contained in:
Ahmed Bouhuolia
2024-11-20 09:42:55 +02:00
parent 3e591beb03
commit 6103f1e4c7
12 changed files with 378 additions and 29 deletions

View File

@@ -1,6 +1,9 @@
import { x } from '@xstyled/emotion';
import { Group, Stack } from '@/components';
import { SendMailReceipt, SendMailReceiptProps } from '../SendMailViewDrawer/SendMailViewReceiptPreview';
import {
SendMailReceipt,
SendMailReceiptProps,
} from '../SendMailViewDrawer/SendMailViewReceiptPreview';
interface EstimateSendMailReceiptProps extends SendMailReceiptProps {
// # Company name.

View File

@@ -3,19 +3,17 @@ import { EstimateSendMailReceipt } from './EstimateSendMailReceipt';
import { EstimateSendMailPreviewHeader } from './EstimateSendMailPreviewHeader';
import { Stack } from '@/components';
export const EstimateSendMailReceiptPreview = () => {
const props = {
companyName: 'Bigcapital Technology, Inc.',
companyLogoUri: ' ',
const defaultEstimateMailReceiptProps = {
companyName: 'Bigcapital Technology, Inc.',
companyLogoUri: ' ',
message: '',
total: '$1,000.00',
subtotal: '$1,000.00',
estimateNumber: 'INV-0001',
expirationDate: '2 Oct 2024',
dueAmount: '$1,000.00',
items: [{ label: 'Web development', total: '$1000.00', quantity: 1 }],
message: `Hi Ahmed Bouhuolia,
total: '$1,000.00',
subtotal: '$1,000.00',
estimateNumber: 'INV-0001',
expirationDate: '2 Oct 2024',
dueAmount: '$1,000.00',
items: [{ label: 'Web development', total: '$1000.00', quantity: 1 }],
message: `Hi Ahmed Bouhuolia,
Here's invoice # INV-00002 for $738.30
@@ -27,15 +25,15 @@ If you have any questions, please let us know.
Thanks,
Bigcapital`,
};
};
export const EstimateSendMailReceiptPreview = () => {
return (
<Stack>
<EstimateSendMailPreviewHeader />
<Stack px={4} py={6}>
<EstimateSendMailReceipt
{...props}
{...defaultEstimateMailReceiptProps}
className={css`
margin: 0 auto;
border-radius: 5px !important;

View File

@@ -1,5 +1,4 @@
import { Spinner } from '@blueprintjs/core';
import { css } from '@emotion/css';
import { Stack } from '@/components';
import { InvoiceSendMailPreviewWithHeader } from './InvoiceSendMailHeaderPreview';
import { useInvoiceHtml } from '@/hooks/query';

View File

@@ -2,7 +2,7 @@
import React, { createContext, useContext } from 'react';
import { Spinner } from '@blueprintjs/core';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { useSaleReceiptMailState } from '@/hooks/query';
import { useSaleInvoiceMailState } from '@/hooks/query';
interface ReceiptSendMailBootValues {
receiptId: number;
@@ -17,22 +17,20 @@ interface ReceiptSendMailBootProps {
const ReceiptSendMailContentBootContext =
createContext<ReceiptSendMailBootValues>({} as ReceiptSendMailBootValues);
export const ReceiptSendMailBoot = ({
children,
}: ReceiptSendMailBootProps) => {
export const ReceiptSendMailBoot = ({ children }: ReceiptSendMailBootProps) => {
const {
payload: { receiptId },
} = useDrawerContext();
// Receipt mail options.
const { data: receiptMailState, isLoading: isReceiptMailState } =
useSaleReceiptMailState(receiptId);
useSaleInvoiceMailState(receiptId);
const isLoading = isReceiptMailState;
if (isLoading) {
return <Spinner size={20} />;
}
// if (isLoading) {
// return <Spinner size={20} />;
// }
const value = {
receiptId,

View File

@@ -1,6 +1,73 @@
import { FCheckbox, FFormGroup, FInputGroup, Group, Stack } from "@/components";
import { SendMailViewToAddressField } from "../../Estimates/SendMailViewDrawer/SendMailViewToAddressField";
import { SendMailViewMessageField } from "../../Estimates/SendMailViewDrawer/SendMailViewMessageField";
import { Button, Intent } from "@blueprintjs/core";
import { useDrawerActions } from "@/hooks/state";
import { useDrawerContext } from "@/components/Drawer/DrawerProvider";
import { useFormikContext } from "formik";
const items: Array<any> = [];
const argsOptions: Array<any> = [];
export function ReceiptSendMailFormFields() {
return null;
return (
<Stack>
<Stack spacing={0} overflow="auto" flex="1" p={'30px'}>
<SendMailViewToAddressField
toMultiSelectProps={{ items }}
ccMultiSelectProps={{ items }}
bccMultiSelectProps={{ items }}
/>
<FFormGroup label={'Submit'} name={'subject'}>
<FInputGroup name={'subject'} large fastField />
</FFormGroup>
<SendMailViewMessageField argsOptions={argsOptions} />
<Group>
<FCheckbox name={'attachPdf'} label={'Attach PDF'} />
</Group>
</Stack>
<ReceiptSendMailFooter />
</Stack>
);
}
function ReceiptSendMailFooter() {
const { isSubmitting } = useFormikContext();
const { name } = useDrawerContext();
const { closeDrawer } = useDrawerActions();
const handleClose = () => {
closeDrawer(name);
};
return (
<Group
py={'12px'}
px={'16px'}
borderTop="1px solid #d8d8d9"
position={'apart'}
>
<Group spacing={10} ml={'auto'}>
<Button
disabled={isSubmitting}
onClick={handleClose}
style={{ minWidth: '65px' }}
>
Close
</Button>
<Button
intent={Intent.PRIMARY}
loading={isSubmitting}
style={{ minWidth: '85px' }}
type="submit"
>
Send Mail
</Button>
</Group>
</Group>
);
}

View File

@@ -0,0 +1,32 @@
import { Stack } from '@/components';
import { ReceiptSendMailPreviewHeader } from './ReceiptSendMailPreviewHeader';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { useGetSaleReceiptHtml } from '@/hooks/query';
import { Spinner } from '@blueprintjs/core';
import { SendMailViewPreviewPdfIframe } from '../../Estimates/SendMailViewDrawer/SendMailViewPreviewPdfIframe';
export function ReceiptSendMailPdfPreview() {
return (
<Stack>
<ReceiptSendMailPreviewHeader />
<Stack px={4} py={6}>
<ReceiptSendPdfPreviewIframe />
</Stack>
</Stack>
);
}
function ReceiptSendPdfPreviewIframe() {
const { payload } = useDrawerContext();
const { data, isLoading } = useGetSaleReceiptHtml(payload?.receiptId);
if (isLoading && data) {
return <Spinner size={20} />;
}
const iframeSrcDoc = data?.htmlContent;
console.log(data, 'data');
return <SendMailViewPreviewPdfIframe srcDoc={iframeSrcDoc} />;
}

View File

@@ -0,0 +1,40 @@
import { Stack } from '@/components';
import { ReceiptSendMailPreviewHeader } from './ReceiptSendMailPreviewHeader';
import { ReceiptSendMailReceipt } from './ReceiptSendMailReceipt';
import { css } from '@emotion/css';
const defaultReceiptMailProps = {
companyLogoUri: 'https://via.placeholder.com/150',
companyName: 'Company Name',
receiptNumber: '1234',
total: '1000',
message: 'Thank you for your business!',
items: [
{ label: 'Item 1', quantity: 1, total: '500' },
{ label: 'Item 2', quantity: 2, total: '500' },
],
subtotal: '1000',
showViewReceiptButton: true,
viewReceiptButtonLabel: 'View Receipt',
};
export function ReceiptSendMailPreview() {
return (
<Stack>
<ReceiptSendMailPreviewHeader />
<Stack px={4} py={6}>
<ReceiptSendMailReceipt
{...defaultReceiptMailProps}
className={css`
margin: 0 auto;
border-radius: 5px !important;
transform: scale(0.9);
transform-origin: top;
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.05) !important;
`}
/>
</Stack>
</Stack>
);
}

View File

@@ -0,0 +1,13 @@
import { SendViewPreviewHeader } from '../../Estimates/SendMailViewDrawer/SendMailViewPreviewHeader';
export function ReceiptSendMailPreviewHeader() {
return (
<SendViewPreviewHeader
companyName="A"
customerName="A"
subject={'adsfsdf'}
from={['a.bouhuolia@gmail.com']}
to={['a.bouhuolia@gmail.com']}
/>
);
}

View File

@@ -1,3 +1,30 @@
import { Suspense } from 'react';
import { Tab } from '@blueprintjs/core';
import { SendMailViewPreviewTabs } from '../../Estimates/SendMailViewDrawer/SendMailViewPreviewTabs';
import { ReceiptSendMailPreview } from './ReceiptSendMailPreview';
import { ReceiptSendMailPdfPreview } from './ReceiptSendMailPdfPreview';
export function ReceiptSendMailPreviewTabs() {
return null;
return (
<SendMailViewPreviewTabs>
<Tab
id={'payment-page'}
title={'Payment page'}
panel={
<Suspense>
<ReceiptSendMailPreview />
</Suspense>
}
/>
<Tab
id="pdf-document"
title={'PDF document'}
panel={
<Suspense>
<ReceiptSendMailPdfPreview />
</Suspense>
}
/>
</SendMailViewPreviewTabs>
);
}

View File

@@ -0,0 +1,142 @@
import { x } from '@xstyled/emotion';
import { Group, Stack } from '@/components';
import {
SendMailReceipt,
SendMailReceiptProps,
} from '../../Estimates/SendMailViewDrawer/SendMailViewReceiptPreview';
interface ReceiptSendMailReceiptProps extends SendMailReceiptProps {
// # Company name.
companyLogoUri?: string;
companyName: string;
// # Receipt number.
receiptNumberLabel?: string;
receiptNumber: string;
// # Total.
total: string;
totalLabel?: string;
// # Message
message: string;
// # Receipt items.
items?: Array<{ label: string; total: string; quantity: string | number }>;
// # Subtotal
subtotal: string;
subtotalLabel?: string;
// # View receipt button
showViewReceiptButton?: boolean;
viewReceiptButtonLabel?: string;
viewReceiptButtonOnClick?: () => void;
}
export function ReceiptSendMailReceipt({
// # Company name.
companyLogoUri,
companyName,
// # Receipt number.
receiptNumberLabel = 'Receipt #',
receiptNumber,
// # Total.
total,
totalLabel = 'Total',
// # Message
message,
// # Items
items,
subtotal,
subtotalLabel = 'Subtotal',
// # View receipt button
showViewReceiptButton,
viewReceiptButtonLabel,
viewReceiptButtonOnClick,
...rest
}: ReceiptSendMailReceiptProps) {
return (
<SendMailReceipt {...rest}>
<Stack spacing={16} textAlign={'center'}>
{companyLogoUri && <SendMailReceipt.CompanyLogo src={companyLogoUri} />}
<Stack spacing={8}>
<x.h1 m={0} fontSize={'18px'} fontWeight={500} color="#404854">
{companyName}
</x.h1>
<x.h3 color="#383E47" fontWeight={500}>
{total}
</x.h3>
<x.span fontSize={'13px'} color="#404854">
{receiptNumberLabel} {receiptNumber}
</x.span>
</Stack>
{showViewReceiptButton && (
<SendMailReceipt.PrimaryButton
primaryColor={'#000'}
onClick={viewReceiptButtonOnClick}
>
{viewReceiptButtonLabel}
</SendMailReceipt.PrimaryButton>
)}
<Stack spacing={0}>
{items?.map((item, key) => (
<Group
key={key}
h={'40px'}
position={'apart'}
borderBottomStyle="solid"
borderBottomWidth={'1px'}
borderBottomColor={'#D9D9D9'}
borderTopStyle="solid"
borderTopColor={'#D9D9D9'}
borderTopWidth={'1px'}
>
<x.span>{item.label}</x.span>
<x.span>
{item.quantity} x {item.total}
</x.span>
</Group>
))}
<Group
h={'40px'}
position={'apart'}
borderBottomStyle="solid"
borderBottomWidth={'1px'}
borderBottomColor={'#000'}
>
<x.span fontWeight={500}>{subtotalLabel}</x.span>
<x.span fontWeight={600} fontSize={15}>
{subtotal}
</x.span>
</Group>
<Group
h={'40px'}
position={'apart'}
borderBottomStyle="solid"
borderBottomWidth={'1px'}
borderColor={'#000'}
>
<x.span fontWeight={500}>{totalLabel}</x.span>
<x.span fontWeight={600} fontSize={15}>
{total}
</x.span>
</Group>
</Stack>
</Stack>
</SendMailReceipt>
);
}

View File

@@ -89,7 +89,7 @@ function ReceiptsDataTable({
// Handle send mail receipt.
const handleSendMailReceipt = ({ id }) => {
openDialog(DialogsName.ReceiptMail, { receiptId: id });
openDrawer(DRAWERS.RECEIPT_SEND_MAIL, { receiptId: id });
};
// Local storage memorizing columns widths.

View File

@@ -269,3 +269,33 @@ export function useGetReceiptState(
{ ...options },
);
}
interface GetReceiptHtmlResponse {
htmlContent: string;
}
/**
* Retrieves the sale receipt html content.
* @param {number} receiptId
* @param {UseQueryOptions<string, Error>} options
* @returns {UseQueryResult<GetReceiptHtmlResponse, Error>}
*/
export const useGetSaleReceiptHtml = (
receiptId: number,
options?: UseQueryOptions<string, Error>,
): UseQueryResult<GetReceiptHtmlResponse, Error> => {
const apiRequest = useApiRequest();
return useQuery<GetReceiptHtmlResponse, Error>(
['SALE_RECEIPT_HTML', receiptId],
() =>
apiRequest
.get(`sales/receipts/${receiptId}`, {
headers: {
Accept: 'application/json+html',
},
})
.then((res) => transformToCamelCase(res.data)),
{ ...options },
);
};