Merge branch 'develop' into add-pdf-templates-package

This commit is contained in:
Ahmed Bouhuolia
2024-11-05 17:19:38 +02:00
24 changed files with 315 additions and 247 deletions

View File

@@ -5,7 +5,7 @@
"dependencies": {
"@bigcapital/utils": "*",
"@bigcapital/pdf-templates": "*",
"@blueprintjs-formik/core": "^0.3.6",
"@blueprintjs-formik/core": "^0.3.7",
"@blueprintjs-formik/datetime": "^0.3.7",
"@blueprintjs-formik/select": "^0.3.5",
"@blueprintjs/colors": "4.1.19",

View File

@@ -93,6 +93,7 @@ export function InvoiceMailReceipt({
h="90px"
w="90px"
mx="auto"
borderRadius="3px"
backgroundRepeat="no-repeat"
backgroundPosition="center center"
backgroundSize="contain"

View File

@@ -1,45 +0,0 @@
import { useMemo } from 'react';
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 mailMessage = useSendInvoiceMailMessage();
const { invoiceMailState } = useInvoiceSendMailBoot();
const items = useMemo(
() =>
invoiceMailState?.entries?.map((entry: any) => ({
quantity: entry.quantity,
total: entry.totalFormatted,
label: entry.name,
})),
[invoiceMailState?.entries],
);
return (
<InvoiceSendMailPreviewWithHeader>
<Box px={4} pt={8} pb={16}>
<InvoiceMailReceiptPreview
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`
margin: 0 auto;
`}
/>
</Box>
</InvoiceSendMailPreviewWithHeader>
);
}

View File

@@ -0,0 +1,64 @@
import { useMemo, ComponentType } from 'react';
import { css } from '@emotion/css';
import { Box } from '@/components';
import {
InvoiceMailReceiptPreview,
InvoiceMailReceiptPreviewProps,
} from '../InvoiceCustomize/InvoiceMailReceiptPreview';
import { useInvoiceSendMailBoot } from './InvoiceSendMailContentBoot';
import { InvoiceSendMailPreviewWithHeader } from './InvoiceSendMailHeaderPreview';
import { useSendInvoiceMailMessage } from './_hooks';
export function InvoiceMailReceiptPreviewConnected() {
return (
<InvoiceSendMailPreviewWithHeader>
<Box px={4} pt={8} pb={16}>
<InvoiceMailReceiptPreviewWithProps
className={css`
margin: 0 auto;
`}
/>
</Box>
</InvoiceSendMailPreviewWithHeader>
);
}
/**
* Injects props from invoice mail state into the InvoiceMailReceiptPreview component.
*/
const withInvoiceMailReceiptPreviewProps = <
P extends InvoiceMailReceiptPreviewProps,
>(
WrappedComponent: ComponentType<P & InvoiceMailReceiptPreviewProps>,
) => {
return function WithInvoiceMailReceiptPreviewProps(props: P) {
const message = useSendInvoiceMailMessage();
const { invoiceMailState } = useInvoiceSendMailBoot();
const items = useMemo(
() =>
invoiceMailState?.entries?.map((entry: any) => ({
quantity: entry.quantity,
total: entry.totalFormatted,
label: entry.name,
})),
[invoiceMailState?.entries],
);
const mailReceiptPreviewProps = {
companyName: invoiceMailState?.companyName,
companyLogoUri: invoiceMailState?.companyLogoUri,
primaryColor: invoiceMailState?.primaryColor,
total: invoiceMailState?.totalFormatted,
dueDate: invoiceMailState?.dueDateFormatted,
dueAmount: invoiceMailState?.dueAmountFormatted,
invoiceNumber: invoiceMailState?.invoiceNo,
items,
message,
};
return <WrappedComponent {...mailReceiptPreviewProps} {...props} />;
};
};
export const InvoiceMailReceiptPreviewWithProps =
withInvoiceMailReceiptPreviewProps(InvoiceMailReceiptPreview);

View File

@@ -1,4 +1,3 @@
// @ts-nocheck
import React, { createContext, useContext } from 'react';
import { Spinner } from '@blueprintjs/core';
import {

View File

@@ -1,7 +1,8 @@
// @ts-nocheck
import React from 'react';
import * as R from 'ramda';
import { Drawer, DrawerSuspense } from '@/components';
import withDrawers from '@/containers/Drawer/withDrawers';
import React from 'react';
const InvoiceSendMailContent = React.lazy(() =>
import('./InvoiceSendMailContent').then((module) => ({

View File

@@ -18,9 +18,14 @@ import {
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { useDrawerActions } from '@/hooks/state';
import { useInvoiceMailItems, useSendInvoiceFormatArgsOptions } from './_hooks';
import { InvoiceSendMailFormValues } from './_types';
// Create new account renderer.
const createNewItemRenderer = (query, active, handleClick) => {
const createNewItemRenderer = (
query: string,
active: boolean,
handleClick: React.MouseEventHandler<HTMLElement>,
) => {
return (
<MenuItem
icon="add"
@@ -32,7 +37,7 @@ const createNewItemRenderer = (query, active, handleClick) => {
};
// Create new item from the given query string.
const createNewItemFromQuery = (name) => ({ name });
const createNewItemFromQuery = (text: string): SelectOptionProps => ({ text });
const styleEmailButton = css`
&.bp4-button.bp4-small {
@@ -62,19 +67,19 @@ export function InvoiceSendMailFields() {
const [showCCField, setShowCCField] = useState<boolean>(false);
const [showBccField, setShowBccField] = useState<boolean>(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const { values, setFieldValue } = useFormikContext();
const { values, setFieldValue } =
useFormikContext<InvoiceSendMailFormValues>();
const items = useInvoiceMailItems();
const argsOptions = useSendInvoiceFormatArgsOptions();
const handleClickCcBtn = (event) => {
const handleClickCcBtn = (event: React.MouseEvent<HTMLElement>) => {
event.preventDefault();
event.stopPropagation();
setShowCCField(true);
};
const handleClickBccBtn = (event) => {
const handleClickBccBtn = (event: React.MouseEvent<HTMLElement>) => {
event.preventDefault();
event.stopPropagation();
@@ -82,64 +87,71 @@ export function InvoiceSendMailFields() {
};
const handleCreateToItemSelect = (value: SelectOptionProps) => {
setFieldValue('to', [...values?.to, value?.name]);
setFieldValue('to', [...values?.to, value?.text]);
};
const handleCreateCcItemSelect = (value: SelectOptionProps) => {
setFieldValue('cc', [...values?.cc, value?.name]);
setFieldValue('cc', [...values?.cc, value?.text]);
};
const handleCreateBccItemSelect = (value: SelectOptionProps) => {
setFieldValue('bcc', [...values?.bcc, value?.name]);
setFieldValue('bcc', [...values?.bcc, value?.text]);
};
const rightElementsToField = useMemo(() => (
<Group
spacing={0}
paddingRight={'7px'}
paddingTop={'7px'}
fontWeight={500}
color={'#000'}
>
<Button
onClick={handleClickCcBtn}
minimal
small
className={styleEmailButton}
const rightElementsToField = useMemo(
() => (
<Group
spacing={0}
paddingRight={'7px'}
paddingTop={'7px'}
fontWeight={500}
color={'#000'}
>
CC
</Button>
<Button
onClick={handleClickCcBtn}
minimal
small
className={styleEmailButton}
>
CC
</Button>
<Button
onClick={handleClickBccBtn}
minimal
small
className={styleEmailButton}
>
BCC
</Button>
</Group>
), []);
<Button
onClick={handleClickBccBtn}
minimal
small
className={styleEmailButton}
>
BCC
</Button>
</Group>
),
[],
);
const handleTextareaChange = useCallback((item: SelectOptionProps) => {
const textarea = textareaRef.current;
if (!textarea) return;
const handleTextareaChange = useCallback(
(item: SelectOptionProps) => {
const textarea = textareaRef.current;
if (!textarea) return;
const { selectionStart, selectionEnd, value: text } = textarea;
const insertText = `{${item.value}}`;
const message =
text.substring(0, selectionStart) +
insertText +
text.substring(selectionEnd);
const { selectionStart, selectionEnd, value: text } = textarea;
const insertText = `{${item.value}}`;
const message =
text.substring(0, selectionStart) +
insertText +
text.substring(selectionEnd);
setFieldValue('message', message);
setFieldValue('message', message);
// Move the cursor to the end of the inserted text
setTimeout(() => {
textarea.selectionStart = textarea.selectionEnd =
selectionStart + insertText.length;
textarea.focus();
}, 0);
}, [setFieldValue]);
// Move the cursor to the end of the inserted text
setTimeout(() => {
textarea.selectionStart = textarea.selectionEnd =
selectionStart + insertText.length;
textarea.focus();
}, 0);
},
[setFieldValue],
);
return (
<Stack
@@ -233,7 +245,7 @@ export function InvoiceSendMailFields() {
position: Position.BOTTOM_LEFT,
minimal: true,
}}
input={({ activeItem, text, label, value }) => (
input={() => (
<Button
minimal
rightIcon={

View File

@@ -3,9 +3,9 @@ import { css } from '@emotion/css';
import { Tab, Tabs } from '@blueprintjs/core';
import { Stack } from '@/components';
const InvoiceMailReceiptPreviewConneceted = lazy(() =>
import('./InvoiceMailReceiptPreviewConnected.').then((module) => ({
default: module.InvoiceMailReceiptPreviewConneceted,
const InvoiceMailReceiptPreviewConnected = lazy(() =>
import('./InvoiceMailReceiptPreviewConnected').then((module) => ({
default: module.InvoiceMailReceiptPreviewConnected,
})),
);
const InvoiceSendPdfPreviewConnected = lazy(() =>
@@ -51,7 +51,7 @@ export function InvoiceSendMailPreview() {
title={'Payment page'}
panel={
<Suspense>
<InvoiceMailReceiptPreviewConneceted />
<InvoiceMailReceiptPreviewConnected />
</Suspense>
}
/>

View File

@@ -372,6 +372,7 @@ export function useSendSaleInvoiceMail(
// --------------------------------------
export interface GetSaleInvoiceDefaultOptionsResponse {
companyName: string;
companyLogoUri: string;
dueDate: string;
dueDateFormatted: string;