feat: payment received mail receipt

This commit is contained in:
Ahmed Bouhuolia
2024-11-25 11:51:13 +02:00
parent 459bf4cd55
commit df41de7239
12 changed files with 221 additions and 181 deletions

View File

@@ -1,12 +1,20 @@
import { css } from '@emotion/css';
import { ComponentType, useMemo } from 'react';
import { EstimateSendMailReceipt, EstimateSendMailReceiptProps } from './EstimateSendMailReceipt';
import { ComponentType } from 'react';
import {
EstimateSendMailReceipt,
EstimateSendMailReceiptProps,
} from './EstimateSendMailReceipt';
import { EstimateSendMailPreviewHeader } from './EstimateSendMailPreviewHeader';
import { withEstimateMailReceiptPreviewProps } from './withEstimateMailReceiptPreviewProps';
import { Stack } from '@/components';
import { useEstimateSendMailBoot } from './EstimateSendMailBoot';
import { useSendEstimateMailMessage } from './hooks';
import { defaultEstimateMailReceiptProps } from './_constants';
const estimatePreviewCss = 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;
`;
export const EstimateSendMailReceiptPreview = () => {
return (
@@ -14,57 +22,12 @@ export const EstimateSendMailReceiptPreview = () => {
<EstimateSendMailPreviewHeader />
<Stack px={4} py={6}>
<EstimateSendMailReceiptConnected
className={css`
margin: 0 auto;
border-radius: 5px !important;
transform: scale(0.9);
transform-origin: top;
boxshadow: 0 10px 15px rgba(0, 0, 0, 0.05) !important;
`}
/>
<EstimateSendMailReceiptConnected className={estimatePreviewCss} />
</Stack>
</Stack>
);
};
/**
* Injects props from estimate mail state into the `EstimateSendMailReceipt` component.
*/
const withEstimateMailReceiptPreviewProps = <
P extends EstimateSendMailReceiptProps,
>(
WrappedComponent: ComponentType<P & EstimateSendMailReceiptProps>,
) => {
return function WithInvoiceMailReceiptPreviewProps(props: P) {
const { estimateMailState } = useEstimateSendMailBoot();
const message = useSendEstimateMailMessage();
const items = useMemo(
() =>
estimateMailState?.entries?.map((entry: any) => ({
quantity: entry.quantity,
total: entry.totalFormatted,
label: entry.name,
})),
[estimateMailState?.entries],
);
const mailReceiptPreviewProps = {
...defaultEstimateMailReceiptProps,
companyName: estimateMailState?.companyName,
companyLogoUri: estimateMailState?.companyLogoUri,
primaryColor: estimateMailState?.primaryColor,
total: estimateMailState?.totalFormatted,
expirationDate: estimateMailState?.expirationDateFormatted,
estimateNumber: estimateMailState?.estimateNumber,
estimateDate: estimateMailState?.estimateDateFormatted,
items,
message
};
return <WrappedComponent {...mailReceiptPreviewProps} {...props} />;
};
};
const EstimateSendMailReceiptConnected = withEstimateMailReceiptPreviewProps(
EstimateSendMailReceipt
);
EstimateSendMailReceipt,
) as ComponentType<Partial<EstimateSendMailReceiptProps>>;

View File

@@ -0,0 +1,43 @@
import { ComponentType, useMemo } from 'react';
import { defaultEstimateMailReceiptProps } from './_constants';
import { useEstimateSendMailBoot } from './EstimateSendMailBoot';
import { useSendEstimateMailMessage } from './hooks';
import { EstimateSendMailReceiptProps } from './EstimateSendMailReceipt';
/**
* Injects props from estimate mail state into the `EstimateSendMailReceipt` component.
*/
export const withEstimateMailReceiptPreviewProps = <
P extends EstimateSendMailReceiptProps,
>(
WrappedComponent: ComponentType<P & EstimateSendMailReceiptProps>,
) => {
return function WithInvoiceMailReceiptPreviewProps(props: P) {
const { estimateMailState } = useEstimateSendMailBoot();
const message = useSendEstimateMailMessage();
const items = useMemo(
() =>
estimateMailState?.entries?.map((entry: any) => ({
quantity: entry.quantity,
total: entry.totalFormatted,
label: entry.name,
})),
[estimateMailState?.entries],
);
const mailReceiptPreviewProps = {
...defaultEstimateMailReceiptProps,
companyName: estimateMailState?.companyName,
companyLogoUri: estimateMailState?.companyLogoUri,
primaryColor: estimateMailState?.primaryColor,
total: estimateMailState?.totalFormatted,
expirationDate: estimateMailState?.expirationDateFormatted,
estimateNumber: estimateMailState?.estimateNumber,
estimateDate: estimateMailState?.estimateDateFormatted,
items,
message,
};
return <WrappedComponent {...mailReceiptPreviewProps} {...props} />;
};
};

View File

@@ -1,4 +1,3 @@
// @ts-nocheck
import { Button, Intent } from '@blueprintjs/core';
import { useFormikContext } from 'formik';
import { FCheckbox, FFormGroup, FInputGroup, Group, Stack } from '@/components';

View File

@@ -1,14 +1,20 @@
import { css } from '@emotion/css';
import { ComponentType, useMemo } from 'react';
import { ComponentType } from 'react';
import {
PaymentReceivedMailReceipt,
PaymentReceivedMailReceiptProps,
} from './PaymentReceivedMailReceipt';
import { PaymentReceivedMailPreviewHeader } from './PaymentReceivedMailPreviewHeader';
import { withPaymentReceivedMailReceiptPreviewProps } from './withPaymentReceivedMailReceiptPreviewProps';
import { Stack } from '@/components';
import { useSendPaymentReceivedtMailMessage } from './_hooks';
import { usePaymentReceivedSendMailBoot } from './PaymentReceivedMailBoot';
import { defaultPaymentReceiptMailProps } from './_constants';
const mailReceiptCss = 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;
`;
export function PaymentReceivedMailPreviewReceipt() {
return (
@@ -17,54 +23,14 @@ export function PaymentReceivedMailPreviewReceipt() {
<Stack px={4} py={6}>
<PaymentReceivedMailReceiptPreviewConnected
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;
`}
className={mailReceiptCss}
/>
</Stack>
</Stack>
);
}
/**
* Injects props from invoice mail state into the InvoiceMailReceiptPreview component.
*/
const withPaymentReceivedMailReceiptPreviewProps = <
P extends PaymentReceivedMailReceiptProps,
>(
WrappedComponent: ComponentType<P & PaymentReceivedMailReceiptProps>,
) => {
return function WithInvoiceMailReceiptPreviewProps(props: P) {
const message = useSendPaymentReceivedtMailMessage();
const { paymentReceivedMailState } = usePaymentReceivedSendMailBoot();
const items = useMemo(
() =>
paymentReceivedMailState?.entries?.map((entry: any) => ({
total: entry.paidAmount,
label: entry.invoiceNumber,
})),
[paymentReceivedMailState?.entries],
);
const mailPaymentReceivedPreviewProps = {
...defaultPaymentReceiptMailProps,
companyName: paymentReceivedMailState?.companyName,
companyLogoUri: paymentReceivedMailState?.companyLogoUri,
primaryColor: paymentReceivedMailState?.primaryColor,
total: paymentReceivedMailState?.totalFormatted,
subtotal: paymentReceivedMailState?.subtotalFormatted,
paymentNumber: paymentReceivedMailState?.paymentNumber,
items,
message,
};
return <WrappedComponent {...mailPaymentReceivedPreviewProps} {...props} />;
};
};
export const PaymentReceivedMailReceiptPreviewConnected =
withPaymentReceivedMailReceiptPreviewProps(PaymentReceivedMailReceipt);
withPaymentReceivedMailReceiptPreviewProps(
PaymentReceivedMailReceipt,
) as ComponentType<Partial<PaymentReceivedMailReceiptProps>>;

View File

@@ -0,0 +1,41 @@
import { ComponentType, useMemo } from 'react';
import { PaymentReceivedMailReceiptProps } from './PaymentReceivedMailReceipt';
import { useSendPaymentReceivedtMailMessage } from './_hooks';
import { usePaymentReceivedSendMailBoot } from './PaymentReceivedMailBoot';
import { defaultPaymentReceiptMailProps } from './_constants';
/**
* Injects props from invoice mail state into the InvoiceMailReceiptPreview component.
*/
export const withPaymentReceivedMailReceiptPreviewProps = <
P extends PaymentReceivedMailReceiptProps,
>(
WrappedComponent: ComponentType<P & PaymentReceivedMailReceiptProps>,
) => {
return function WithInvoiceMailReceiptPreviewProps(props: P) {
const message = useSendPaymentReceivedtMailMessage();
const { paymentReceivedMailState } = usePaymentReceivedSendMailBoot();
const items = useMemo(
() =>
paymentReceivedMailState?.entries?.map((entry: any) => ({
total: entry.paidAmount,
label: entry.invoiceNumber,
})),
[paymentReceivedMailState?.entries],
);
const mailPaymentReceivedPreviewProps = {
...defaultPaymentReceiptMailProps,
companyName: paymentReceivedMailState?.companyName,
companyLogoUri: paymentReceivedMailState?.companyLogoUri,
primaryColor: paymentReceivedMailState?.primaryColor,
total: paymentReceivedMailState?.totalFormatted,
subtotal: paymentReceivedMailState?.subtotalFormatted,
paymentNumber: paymentReceivedMailState?.paymentNumber,
items,
message,
};
return <WrappedComponent {...mailPaymentReceivedPreviewProps} {...props} />;
};
};

View File

@@ -1,14 +1,15 @@
import { ComponentType } from 'react';
import { css } from '@emotion/css';
import { Stack } from '@/components';
import { ReceiptSendMailPreviewHeader } from './ReceiptSendMailPreviewHeader';
import {
ReceiptSendMailReceipt,
ReceiptSendMailReceiptProps,
} from './ReceiptSendMailReceipt';
import { defaultReceiptMailProps } from './_constants';
import { useReceiptSendMailBoot } from './ReceiptSendMailBoot';
import { useSendReceiptMailMessage } from './_hooks';
import { ReceiptMailPreviewConnected } from './withReceiptMailReceiptPreviewProps';
const receiptPreviewCss = 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;
`;
export function ReceiptSendMailPreview() {
return (
@@ -16,58 +17,8 @@ export function ReceiptSendMailPreview() {
<ReceiptSendMailPreviewHeader />
<Stack px={4} py={6}>
<ReceiptMailPreviewConnected
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;
`}
/>
<ReceiptMailPreviewConnected className={receiptPreviewCss} />
</Stack>
</Stack>
);
}
/**
* Injects props from receipt mail state into the `ReceiptMailPreviewConnected` component.
*/
const withReceiptMailReceiptPreviewProps = <
P extends ReceiptSendMailReceiptProps,
>(
WrappedComponent: ComponentType<P & ReceiptSendMailReceiptProps>,
) => {
return function WithInvoiceMailReceiptPreviewProps(props: P) {
const message = useSendReceiptMailMessage();
const { receiptMailState } = useReceiptSendMailBoot();
// const items = useMemo(
// () =>
// invoiceMailState?.entries?.map((entry: any) => ({
// quantity: entry.quantity,
// total: entry.totalFormatted,
// label: entry.name,
// })),
// [invoiceMailState?.entries],
// );
const mailReceiptPreviewProps = {
...defaultReceiptMailProps,
// companyName: receiptMailState?.companyName,
// companyLogoUri: receiptMailState?.companyLogoUri,
// primaryColor: receiptMailState?.primaryColor,
// total: receiptMailState?.totalFormatted,
// dueDate: receiptMailState?.dueDateFormatted,
// dueAmount: invoiceMailState?.dueAmountFormatted,
// invoiceNumber: invoiceMailState?.invoiceNo,
// items,
message,
};
return <WrappedComponent {...mailReceiptPreviewProps} {...props} />;
};
};
export const ReceiptMailPreviewConnected = withReceiptMailReceiptPreviewProps(
ReceiptSendMailReceipt,
);

View File

@@ -0,0 +1,50 @@
import { ComponentType } from 'react';
import {
ReceiptSendMailReceipt,
ReceiptSendMailReceiptProps,
} from './ReceiptSendMailReceipt';
import { useSendReceiptMailMessage } from './_hooks';
import { useReceiptSendMailBoot } from './ReceiptSendMailBoot';
import { defaultReceiptMailProps } from './_constants';
/**
* Injects props from receipt mail state into the `ReceiptMailPreviewConnected` component.
*/
export const withReceiptMailReceiptPreviewProps = <
P extends ReceiptSendMailReceiptProps,
>(
WrappedComponent: ComponentType<P & ReceiptSendMailReceiptProps>,
) => {
return function WithInvoiceMailReceiptPreviewProps(props: P) {
const message = useSendReceiptMailMessage();
const { receiptMailState } = useReceiptSendMailBoot();
// const items = useMemo(
// () =>
// invoiceMailState?.entries?.map((entry: any) => ({
// quantity: entry.quantity,
// total: entry.totalFormatted,
// label: entry.name,
// })),
// [invoiceMailState?.entries],
// );
const mailReceiptPreviewProps = {
...defaultReceiptMailProps,
// companyName: receiptMailState?.companyName,
// companyLogoUri: receiptMailState?.companyLogoUri,
// primaryColor: receiptMailState?.primaryColor,
// total: receiptMailState?.totalFormatted,
// dueDate: receiptMailState?.dueDateFormatted,
// dueAmount: invoiceMailState?.dueAmountFormatted,
// invoiceNumber: invoiceMailState?.invoiceNo,
// items,
message,
};
return <WrappedComponent {...mailReceiptPreviewProps} {...props} />;
};
};
export const ReceiptMailPreviewConnected = withReceiptMailReceiptPreviewProps(
ReceiptSendMailReceipt,
) as ComponentType<Partial<ReceiptSendMailReceiptProps>>;

View File

@@ -5,6 +5,8 @@ import {
UseQueryOptions,
UseQueryResult,
useQuery,
UseMutationOptions,
UseMutationResult,
} from 'react-query';
import useApiRequest from '../useRequest';
import { useRequestQuery } from '../useQueryRequest';
@@ -244,11 +246,45 @@ export function usePdfPaymentReceive(paymentReceiveId) {
return useRequestPdf({ url: `sales/payment_receives/${paymentReceiveId}` });
}
export function useSendPaymentReceiveMail(props?: any) {
interface SendPaymentReceiveMailValues {
to: string[] | string;
cc?: string[] | string,
bcc?: string[] | string,
subject: string;
message: string;
from?: string[] | string;
attachPdf?: boolean;
}
interface SendPaymentReceiveMailResponse {
success: boolean;
message?: string;
}
type SendPaymentReceiveMailMutation = UseMutationResult<
SendPaymentReceiveMailResponse,
Error,
[number, SendPaymentReceiveMailValues],
unknown
>;
export function useSendPaymentReceiveMail(
props?: Partial<
UseMutationOptions<
SendPaymentReceiveMailResponse,
Error,
[number, SendPaymentReceiveMailValues]
>
>,
): SendPaymentReceiveMailMutation {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
return useMutation<
SendPaymentReceiveMailResponse,
Error,
[number, SendPaymentReceiveMailValues]
>(
([id, values]) =>
apiRequest.post(`sales/payment_receives/${id}/mail`, values),
{
@@ -263,15 +299,16 @@ export function useSendPaymentReceiveMail(props?: any) {
export interface GetPaymentReceivedMailStateResponse {
companyName: string;
companyLogoUri?: string;
primaryColor?: string;
customerName: string;
entries: Array<{ paymentAmountFormatted: string }>;
entries: Array<{ invoiceNumber: string; paidAmount: string }>;
from: Array<string>;
fromOptions: Array<{ mail: string; label: string; primary: boolean }>;
paymentAmountFormatted: string;
paymentDate: string;
paymentDateFormatted: string;
@@ -285,8 +322,7 @@ export interface GetPaymentReceivedMailStateResponse {
subtotalFormatted: string;
paymentNumber: string;
companyLogoUri?: string;
primaryColor?: string;
formatArgs: Record<string, any>;
}
export function usePaymentReceivedMailState(