mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 22:00:31 +00:00
feat: send invoice receipt preview
This commit is contained in:
@@ -1,33 +1,38 @@
|
||||
import { Box, Group, Stack } from '@/components';
|
||||
import { InvoiceMailReceiptPreview } from '../InvoiceCustomize/InvoiceMailReceiptPreview';
|
||||
import { css } from '@emotion/css';
|
||||
import { useInvoiceSendMailBoot } from './InvoiceSendMailContentBoot';
|
||||
import { useMemo } from 'react';
|
||||
import { x } from '@xstyled/emotion';
|
||||
import { css } from '@emotion/css';
|
||||
import { Box, } from '@/components';
|
||||
import { InvoiceMailReceiptPreview } from '../InvoiceCustomize/InvoiceMailReceiptPreview';
|
||||
import { useInvoiceSendMailBoot } from './InvoiceSendMailContentBoot';
|
||||
import { InvoiceSendMailPreviewWithHeader } from './InvoiceSendMailHeaderPreview';
|
||||
import { useSendInvoiceMailMessage } from './_hooks';
|
||||
|
||||
export function InvoiceMailReceiptPreviewConneceted() {
|
||||
const { invoice } = useInvoiceSendMailBoot();
|
||||
const mailMessage = useSendInvoiceMailMessage();
|
||||
const { invoiceMailState } = useInvoiceSendMailBoot();
|
||||
|
||||
const items = useMemo(
|
||||
() =>
|
||||
invoice.entries.map((entry: any) => ({
|
||||
invoiceMailState?.entries?.map((entry: any) => ({
|
||||
quantity: entry.quantity,
|
||||
total: entry.rate_formatted,
|
||||
label: entry.item.name,
|
||||
total: entry.totalFormatted,
|
||||
label: entry.name,
|
||||
})),
|
||||
[invoice.entries],
|
||||
[invoiceMailState?.entries],
|
||||
);
|
||||
|
||||
return (
|
||||
<InvoiceSendMailPreviewWithHeader>
|
||||
<Box px={4} pt={8} pb={16}>
|
||||
<InvoiceMailReceiptPreview
|
||||
total={invoice.total_formatted}
|
||||
dueDate={invoice.due_date_formatted}
|
||||
invoiceNumber={invoice.invoice_no}
|
||||
companyName={invoiceMailState?.companyName}
|
||||
// companyLogoUri={invoiceMailState?.companyLogoUri}
|
||||
|
||||
primaryColor={invoiceMailState?.primaryColor}
|
||||
total={invoiceMailState?.totalFormatted}
|
||||
dueDate={invoiceMailState?.dueDateFormatted}
|
||||
dueAmount={invoiceMailState?.dueAmountFormatted}
|
||||
|
||||
invoiceNumber={invoiceMailState?.invoiceNo}
|
||||
items={items}
|
||||
message={mailMessage}
|
||||
className={css`
|
||||
@@ -37,4 +42,4 @@ export function InvoiceMailReceiptPreviewConneceted() {
|
||||
</Box>
|
||||
</InvoiceSendMailPreviewWithHeader>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,15 @@ import React, { createContext, useContext } from 'react';
|
||||
import { Spinner } from '@blueprintjs/core';
|
||||
import {
|
||||
GetSaleInvoiceDefaultOptionsResponse,
|
||||
useInvoice,
|
||||
useSaleInvoiceDefaultOptions,
|
||||
useSaleInvoiceMailState,
|
||||
} from '@/hooks/query';
|
||||
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||
|
||||
interface InvoiceSendMailBootValues {
|
||||
invoice: any;
|
||||
invoiceId: number;
|
||||
isInvoiceLoading: boolean;
|
||||
|
||||
invoiceMailOptions: GetSaleInvoiceDefaultOptionsResponse | undefined;
|
||||
isInvoiceMailOptionsLoading: boolean;
|
||||
invoiceMailState: GetSaleInvoiceDefaultOptionsResponse | undefined;
|
||||
isInvoiceMailState: boolean;
|
||||
}
|
||||
interface InvoiceSendMailBootProps {
|
||||
children: React.ReactNode;
|
||||
@@ -28,25 +25,21 @@ export const InvoiceSendMailBoot = ({ children }: InvoiceSendMailBootProps) => {
|
||||
payload: { invoiceId },
|
||||
} = useDrawerContext();
|
||||
|
||||
// Invoice details.
|
||||
const { data: invoice, isLoading: isInvoiceLoading } = useInvoice(invoiceId, {
|
||||
enabled: !!invoiceId,
|
||||
});
|
||||
// Invoice mail options.
|
||||
const { data: invoiceMailOptions, isLoading: isInvoiceMailOptionsLoading } =
|
||||
useSaleInvoiceDefaultOptions(invoiceId);
|
||||
const { data: invoiceMailState, isLoading: isInvoiceMailState } =
|
||||
useSaleInvoiceMailState(invoiceId);
|
||||
|
||||
const isLoading = isInvoiceLoading || isInvoiceMailOptionsLoading;
|
||||
const isLoading = isInvoiceMailState;
|
||||
|
||||
if (isLoading) {
|
||||
return <Spinner size={20} />;
|
||||
}
|
||||
const value = {
|
||||
invoice,
|
||||
isInvoiceLoading,
|
||||
invoiceId,
|
||||
invoiceMailOptions,
|
||||
isInvoiceMailOptionsLoading,
|
||||
|
||||
// # Invoice mail options
|
||||
isInvoiceMailState,
|
||||
invoiceMailState,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -25,13 +25,14 @@ interface InvoiceSendMailFormProps {
|
||||
|
||||
export function InvoiceSendMailForm({ children }: InvoiceSendMailFormProps) {
|
||||
const { mutateAsync: sendInvoiceMail } = useSendSaleInvoiceMail();
|
||||
const { invoiceId, invoiceMailOptions } = useInvoiceSendMailBoot();
|
||||
const { invoiceId, invoiceMailState } = useInvoiceSendMailBoot();
|
||||
|
||||
const { name } = useDrawerContext();
|
||||
const { closeDrawer } = useDrawerActions();
|
||||
|
||||
const _initialValues: InvoiceSendMailFormValues = {
|
||||
...initialValues,
|
||||
...transformToForm(invoiceMailOptions, initialValues),
|
||||
...transformToForm(invoiceMailState, initialValues),
|
||||
};
|
||||
const handleSubmit = (
|
||||
values: InvoiceSendMailFormValues,
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useDrawerActions } from '@/hooks/state';
|
||||
interface ElementCustomizeHeaderProps {
|
||||
label?: string;
|
||||
children?: React.ReactNode;
|
||||
closeButton?: boolean;
|
||||
}
|
||||
|
||||
export function InvoiceSendMailHeader({
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { x } from '@xstyled/emotion';
|
||||
import { Box, Group, Stack } from '@/components';
|
||||
import React from 'react';
|
||||
import { useSendInvoiceMailSubject } from './_hooks';
|
||||
import { useSendInvoiceMailForm, useSendInvoiceMailSubject } from './_hooks';
|
||||
import { useInvoiceSendMailBoot } from './InvoiceSendMailContentBoot';
|
||||
|
||||
export function InvoiceSendMailHeaderPreview() {
|
||||
const mailSubject = useSendInvoiceMailSubject();
|
||||
const { invoiceMailState } = useInvoiceSendMailBoot();
|
||||
const toAddresses = useMailHeaderToAddresses();
|
||||
|
||||
return (
|
||||
<Stack
|
||||
@@ -43,12 +46,12 @@ export function InvoiceSendMailHeaderPreview() {
|
||||
<Group spacing={2}>
|
||||
<Box fontWeight={600}>Ahmed </Box>
|
||||
<Box color={'#738091'}>
|
||||
<messaging-service@post.xero.com>
|
||||
<messaging-service@post.bigcapital.app>
|
||||
</Box>
|
||||
</Group>
|
||||
|
||||
<Box fontSize={'sm'} color={'#738091'}>
|
||||
Reply to: Ahmed <a.m.bouhuolia@gmail.com>
|
||||
Reply to: {invoiceMailState?.companyName} {toAddresses};
|
||||
</Box>
|
||||
</Stack>
|
||||
</Group>
|
||||
@@ -65,8 +68,15 @@ export function InvoiceSendMailPreviewWithHeader({
|
||||
return (
|
||||
<Box>
|
||||
<InvoiceSendMailHeaderPreview />
|
||||
|
||||
<Box>{children}</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export const useMailHeaderToAddresses = () => {
|
||||
const {
|
||||
values: { to },
|
||||
} = useSendInvoiceMailForm();
|
||||
|
||||
return useMemo(() => to?.map((email) => '<' + email + '>').join(' '), [to]);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import { Tab, Tabs } from '@blueprintjs/core';
|
||||
import { lazy, Suspense } from 'react';
|
||||
import { css } from '@emotion/css';
|
||||
import { Tab, Tabs } from '@blueprintjs/core';
|
||||
import { Stack } from '@/components';
|
||||
import { InvoiceMailReceiptPreviewConneceted } from './InvoiceMailReceiptPreviewConnected.';
|
||||
import { InvoiceSendPdfPreviewConnected } from './InvoiceSendPdfPreviewConnected';
|
||||
|
||||
const InvoiceMailReceiptPreviewConneceted = lazy(() =>
|
||||
import('./InvoiceMailReceiptPreviewConnected.').then((module) => ({
|
||||
default: module.InvoiceMailReceiptPreviewConneceted,
|
||||
})),
|
||||
);
|
||||
const InvoiceSendPdfPreviewConnected = lazy(() =>
|
||||
import('./InvoiceSendPdfPreviewConnected').then((module) => ({
|
||||
default: module.InvoiceSendPdfPreviewConnected,
|
||||
})),
|
||||
);
|
||||
|
||||
export function InvoiceSendMailPreview() {
|
||||
return (
|
||||
@@ -39,12 +49,20 @@ export function InvoiceSendMailPreview() {
|
||||
<Tab
|
||||
id={'payment-page'}
|
||||
title={'Payment page'}
|
||||
panel={<InvoiceMailReceiptPreviewConneceted />}
|
||||
panel={
|
||||
<Suspense>
|
||||
<InvoiceMailReceiptPreviewConneceted />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Tab
|
||||
id="pdf-document"
|
||||
title={'PDF document'}
|
||||
panel={<InvoiceSendPdfPreviewConnected />}
|
||||
panel={
|
||||
<Suspense>
|
||||
<InvoiceSendPdfPreviewConnected />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
</Tabs>
|
||||
</Stack>
|
||||
|
||||
@@ -1,25 +1,13 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { Box } from '@/components';
|
||||
import { InvoicePaperTemplate } from '../InvoiceCustomize/InvoicePaperTemplate';
|
||||
import { css } from '@emotion/css';
|
||||
import { useInvoiceSendMailBoot } from './InvoiceSendMailContentBoot';
|
||||
import { InvoiceSendMailPreviewWithHeader } from './InvoiceSendMailHeaderPreview';
|
||||
|
||||
export function InvoiceSendPdfPreviewConnected() {
|
||||
const { invoice } = useInvoiceSendMailBoot();
|
||||
|
||||
return (
|
||||
<InvoiceSendMailPreviewWithHeader>
|
||||
<Box px={4} py={6}>
|
||||
<InvoicePaperTemplate
|
||||
dueDate={invoice.due_date_formatted}
|
||||
dateIssue={invoice.invoice_date_formatted}
|
||||
invoiceNumber={invoice.invoice_no}
|
||||
total={invoice.total_formatted}
|
||||
subtotal={invoice.subtotal}
|
||||
discount={''}
|
||||
paymentMade={''}
|
||||
balanceDue={invoice.due_amount_Formatted}
|
||||
statement={invoice.statement}
|
||||
className={css`
|
||||
margin: 0 auto;
|
||||
`}
|
||||
|
||||
@@ -5,6 +5,10 @@ import { chain, defaultTo, mapKeys, snakeCase, startCase } from 'lodash';
|
||||
import { InvoiceSendMailFormValues } from './_types';
|
||||
import { useInvoiceSendMailBoot } from './InvoiceSendMailContentBoot';
|
||||
|
||||
export const useSendInvoiceMailForm = () => {
|
||||
return useFormikContext<InvoiceSendMailFormValues>();
|
||||
};
|
||||
|
||||
export const useInvoiceMailItems = () => {
|
||||
const { values } = useFormikContext<InvoiceSendMailFormValues>();
|
||||
const cc = values?.cc || [];
|
||||
@@ -21,13 +25,13 @@ export const useInvoiceMailItems = () => {
|
||||
};
|
||||
|
||||
export const useSendInvoiceMailFormatArgs = (): Record<string, string> => {
|
||||
const { invoiceMailOptions } = useInvoiceSendMailBoot();
|
||||
const { invoiceMailState } = useInvoiceSendMailBoot();
|
||||
|
||||
return useMemo(() => {
|
||||
return mapKeys(invoiceMailOptions?.formatArgs, (_, key) =>
|
||||
return mapKeys(invoiceMailState?.formatArgs, (_, key) =>
|
||||
startCase(snakeCase(key).replace('_', ' ')),
|
||||
);
|
||||
}, [invoiceMailOptions]);
|
||||
}, [invoiceMailState]);
|
||||
};
|
||||
|
||||
export const useSendInvoiceMailSubject = (): string => {
|
||||
|
||||
Reference in New Issue
Block a user