mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
Merge branch 'develop' into add-pdf-templates-package
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
|
import { getUploadedObjectUri } from '@/services/Attachments/utils';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
|
|
||||||
export class PdfTemplate extends TenantModel {
|
export class PdfTemplate extends TenantModel {
|
||||||
|
public readonly attributes: Record<string, any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
*/
|
*/
|
||||||
@@ -47,7 +50,17 @@ export class PdfTemplate extends TenantModel {
|
|||||||
* Virtual attributes.
|
* Virtual attributes.
|
||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return [];
|
return ['companyLogoUri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the company logo uri.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
get companyLogoUri() {
|
||||||
|
return this.attributes.companyLogoKey
|
||||||
|
? getUploadedObjectUri(this.attributes.companyLogoKey)
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,9 +35,12 @@ export class CreditNoteBrandingTemplate {
|
|||||||
...defaultCreditNoteBrandingAttributes,
|
...defaultCreditNoteBrandingAttributes,
|
||||||
...commonOrgBrandingAttrs,
|
...commonOrgBrandingAttrs,
|
||||||
};
|
};
|
||||||
|
const brandingTemplateAttrs = {
|
||||||
|
...template.attributes,
|
||||||
|
companyLogoUri: template.companyLogoUri,
|
||||||
|
};
|
||||||
const attributes = mergePdfTemplateWithDefaultAttributes(
|
const attributes = mergePdfTemplateWithDefaultAttributes(
|
||||||
template.attributes,
|
brandingTemplateAttrs,
|
||||||
organizationBrandingAttrs
|
organizationBrandingAttrs
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||||
import { getTransactionTypeLabel } from '@/utils/transactions-types';
|
import { getTransactionTypeLabel } from '@/utils/transactions-types';
|
||||||
import { getUploadedObjectUri } from '../Attachments/utils';
|
|
||||||
|
|
||||||
export class GetPdfTemplateTransformer extends Transformer {
|
export class GetPdfTemplateTransformer extends Transformer {
|
||||||
/**
|
/**
|
||||||
* Includeded attributes.
|
* Included attributes.
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
@@ -44,20 +43,10 @@ export class GetPdfTemplateTransformer extends Transformer {
|
|||||||
|
|
||||||
class GetPdfTemplateAttributesTransformer extends Transformer {
|
class GetPdfTemplateAttributesTransformer extends Transformer {
|
||||||
/**
|
/**
|
||||||
* Includeded attributes.
|
* Included attributes.
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return ['companyLogoUri'];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the company logo uri.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
protected companyLogoUri(template) {
|
|
||||||
return template.companyLogoKey
|
|
||||||
? getUploadedObjectUri(template.companyLogoKey)
|
|
||||||
: '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ export interface ICreateInvoicePdfTemplateDTO {
|
|||||||
showStatement?: boolean;
|
showStatement?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface CommonOrganizationBrandingAttributes {
|
export interface CommonOrganizationBrandingAttributes {
|
||||||
companyName?: string;
|
companyName?: string;
|
||||||
primaryColor?: string;
|
primaryColor?: string;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export class GetInvoiceMailTemplateAttributesTransformer extends Transformer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public companyLogoUri(): string {
|
public companyLogoUri(): string {
|
||||||
return this.options.brandingTemplate?.attributes?.companyLogoUri;
|
return this.options.brandingTemplate?.companyLogoUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public companyName(): string {
|
public companyName(): string {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ export class GetSaleInvoiceMailState {
|
|||||||
/**
|
/**
|
||||||
* Retrieves the invoice mail state of the given sale invoice.
|
* Retrieves the invoice mail state of the given sale invoice.
|
||||||
* Invoice mail state includes the mail options, branding attributes and the invoice details.
|
* Invoice mail state includes the mail options, branding attributes and the invoice details.
|
||||||
*
|
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {number} saleInvoiceId
|
* @param {number} saleInvoiceId
|
||||||
* @returns {Promise<SaleInvoiceMailState>}
|
* @returns {Promise<SaleInvoiceMailState>}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
|
||||||
import { SaleInvoiceTransformer } from './SaleInvoiceTransformer';
|
import { SaleInvoiceTransformer } from './SaleInvoiceTransformer';
|
||||||
import { ItemEntryTransformer } from './ItemEntryTransformer';
|
import { ItemEntryTransformer } from './ItemEntryTransformer';
|
||||||
|
|
||||||
@@ -11,6 +10,10 @@ export class GetSaleInvoiceMailStateTransformer extends SaleInvoiceTransformer {
|
|||||||
return ['*'];
|
return ['*'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Included attributes.
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return [
|
return [
|
||||||
'invoiceDate',
|
'invoiceDate',
|
||||||
@@ -39,14 +42,26 @@ export class GetSaleInvoiceMailStateTransformer extends SaleInvoiceTransformer {
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the company name.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
protected companyName = () => {
|
protected companyName = () => {
|
||||||
return this.context.organization.name;
|
return this.context.organization.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the company logo uri.
|
||||||
|
* @returns {string | null}
|
||||||
|
*/
|
||||||
protected companyLogoUri = (invoice) => {
|
protected companyLogoUri = (invoice) => {
|
||||||
return invoice.pdfTemplate?.attributes?.companyLogoUri;
|
return invoice.pdfTemplate?.companyLogoUri;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the primary color.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
protected primaryColor = (invoice) => {
|
protected primaryColor = (invoice) => {
|
||||||
return invoice.pdfTemplate?.attributes?.primaryColor;
|
return invoice.pdfTemplate?.attributes?.primaryColor;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,8 +33,12 @@ export class SaleEstimatePdfTemplate {
|
|||||||
...defaultEstimatePdfBrandingAttributes,
|
...defaultEstimatePdfBrandingAttributes,
|
||||||
...commonOrgBrandingAttrs,
|
...commonOrgBrandingAttrs,
|
||||||
};
|
};
|
||||||
|
const brandingTemplateAttrs = {
|
||||||
|
...template.attributes,
|
||||||
|
companyLogoUri: template.companyLogoUri,
|
||||||
|
};
|
||||||
const attributes = mergePdfTemplateWithDefaultAttributes(
|
const attributes = mergePdfTemplateWithDefaultAttributes(
|
||||||
template.attributes,
|
brandingTemplateAttrs,
|
||||||
orgainizationBrandingAttrs
|
orgainizationBrandingAttrs
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -32,8 +32,12 @@ export class SaleInvoicePdfTemplate {
|
|||||||
...defaultInvoicePdfTemplateAttributes,
|
...defaultInvoicePdfTemplateAttributes,
|
||||||
...commonOrgBrandingAttrs,
|
...commonOrgBrandingAttrs,
|
||||||
};
|
};
|
||||||
|
const brandingTemplateAttrs = {
|
||||||
|
...template.attributes,
|
||||||
|
companyLogoUri: template.companyLogoUri,
|
||||||
|
};
|
||||||
const attributes = mergePdfTemplateWithDefaultAttributes(
|
const attributes = mergePdfTemplateWithDefaultAttributes(
|
||||||
template.attributes,
|
brandingTemplateAttrs,
|
||||||
organizationBrandingAttrs
|
organizationBrandingAttrs
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -28,9 +28,7 @@ import { GetInvoicePaymentsService } from './GetInvoicePaymentsService';
|
|||||||
import { SaleInvoiceNotifyBySms } from './SaleInvoiceNotifyBySms';
|
import { SaleInvoiceNotifyBySms } from './SaleInvoiceNotifyBySms';
|
||||||
import { SendInvoiceMailReminder } from './SendSaleInvoiceMailReminder';
|
import { SendInvoiceMailReminder } from './SendSaleInvoiceMailReminder';
|
||||||
import { SendSaleInvoiceMail } from './SendSaleInvoiceMail';
|
import { SendSaleInvoiceMail } from './SendSaleInvoiceMail';
|
||||||
import { GetSaleInvoiceMailReminder } from './GetSaleInvoiceMailReminder';
|
|
||||||
import { GetSaleInvoiceState } from './GetSaleInvoiceState';
|
import { GetSaleInvoiceState } from './GetSaleInvoiceState';
|
||||||
import { GetSaleInvoiceBrandTemplate } from './GetSaleInvoiceBrandTemplate';
|
|
||||||
import { GetSaleInvoiceMailState } from './GetSaleInvoiceMailState';
|
import { GetSaleInvoiceMailState } from './GetSaleInvoiceMailState';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
@@ -366,7 +364,10 @@ export class SaleInvoiceApplication {
|
|||||||
* @param {number} saleInvoiceid
|
* @param {number} saleInvoiceid
|
||||||
* @returns {Promise<SaleInvoiceMailState>}
|
* @returns {Promise<SaleInvoiceMailState>}
|
||||||
*/
|
*/
|
||||||
public getSaleInvoiceMailState(tenantId: number, saleInvoiceid: number) {
|
public getSaleInvoiceMailState(
|
||||||
|
tenantId: number,
|
||||||
|
saleInvoiceid: number
|
||||||
|
): Promise<SaleInvoiceMailState> {
|
||||||
return this.getSaleInvoiceMailStateService.getInvoiceMailState(
|
return this.getSaleInvoiceMailStateService.getInvoiceMailState(
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoiceid
|
saleInvoiceid
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
|
||||||
export const DEFAULT_INVOICE_MAIL_SUBJECT =
|
export const DEFAULT_INVOICE_MAIL_SUBJECT =
|
||||||
'Invoice {Invoice Number} from {Company Name}';
|
'Invoice {Invoice Number} from {Company Name} for {Customer Name}';
|
||||||
export const DEFAULT_INVOICE_MAIL_CONTENT = `
|
export const DEFAULT_INVOICE_MAIL_CONTENT = `Hi {Customer Name},
|
||||||
<p>Dear {Customer Name}</p>
|
|
||||||
<p>Thank you for your business, You can view or print your invoice from attachements.</p>
|
|
||||||
<p>
|
|
||||||
Invoice <strong>#{Invoice Number}</strong><br />
|
|
||||||
Due Date : <strong>{Invoice Due Date}</strong><br />
|
|
||||||
Amount : <strong>{Invoice Amount}</strong></br />
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
Here's invoice # {Invoice Number} for {Invoice Amount}
|
||||||
<i>Regards</i><br />
|
|
||||||
<i>{Company Name}</i>
|
The amount outstanding of {Invoice Due Amount} is due on {Invoice Due Date}.
|
||||||
</p>
|
|
||||||
|
From your online payment page you can print a PDF or view your outstanding bills.
|
||||||
|
|
||||||
|
If you have any questions, please let us know.
|
||||||
|
|
||||||
|
Thanks,
|
||||||
|
{Company Name}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const DEFAULT_INVOICE_REMINDER_MAIL_SUBJECT =
|
export const DEFAULT_INVOICE_REMINDER_MAIL_SUBJECT =
|
||||||
|
|||||||
@@ -37,8 +37,12 @@ export class PaymentReceivedBrandingTemplate {
|
|||||||
...defaultPaymentReceivedPdfTemplateAttributes,
|
...defaultPaymentReceivedPdfTemplateAttributes,
|
||||||
...commonOrgBrandingAttrs,
|
...commonOrgBrandingAttrs,
|
||||||
};
|
};
|
||||||
|
const brandingTemplateAttrs = {
|
||||||
|
...template.attributes,
|
||||||
|
companyLogoUri: template.companyLogoUri,
|
||||||
|
};
|
||||||
const attributes = mergePdfTemplateWithDefaultAttributes(
|
const attributes = mergePdfTemplateWithDefaultAttributes(
|
||||||
template.attributes,
|
brandingTemplateAttrs,
|
||||||
organizationBrandingAttrs
|
organizationBrandingAttrs
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -37,8 +37,12 @@ export class SaleReceiptBrandingTemplate {
|
|||||||
...defaultSaleReceiptBrandingAttributes,
|
...defaultSaleReceiptBrandingAttributes,
|
||||||
...commonOrgBrandingAttrs,
|
...commonOrgBrandingAttrs,
|
||||||
};
|
};
|
||||||
|
const brandingTemplateAttrs = {
|
||||||
|
...template.attributes,
|
||||||
|
companyLogoUri: template.companyLogoUri,
|
||||||
|
};
|
||||||
const attributes = mergePdfTemplateWithDefaultAttributes(
|
const attributes = mergePdfTemplateWithDefaultAttributes(
|
||||||
template.attributes,
|
brandingTemplateAttrs,
|
||||||
organizationBrandingAttrs
|
organizationBrandingAttrs
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bigcapital/utils": "*",
|
"@bigcapital/utils": "*",
|
||||||
"@bigcapital/pdf-templates": "*",
|
"@bigcapital/pdf-templates": "*",
|
||||||
"@blueprintjs-formik/core": "^0.3.6",
|
"@blueprintjs-formik/core": "^0.3.7",
|
||||||
"@blueprintjs-formik/datetime": "^0.3.7",
|
"@blueprintjs-formik/datetime": "^0.3.7",
|
||||||
"@blueprintjs-formik/select": "^0.3.5",
|
"@blueprintjs-formik/select": "^0.3.5",
|
||||||
"@blueprintjs/colors": "4.1.19",
|
"@blueprintjs/colors": "4.1.19",
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export function InvoiceMailReceipt({
|
|||||||
h="90px"
|
h="90px"
|
||||||
w="90px"
|
w="90px"
|
||||||
mx="auto"
|
mx="auto"
|
||||||
|
borderRadius="3px"
|
||||||
backgroundRepeat="no-repeat"
|
backgroundRepeat="no-repeat"
|
||||||
backgroundPosition="center center"
|
backgroundPosition="center center"
|
||||||
backgroundSize="contain"
|
backgroundSize="contain"
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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);
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
import { Spinner } from '@blueprintjs/core';
|
import { Spinner } from '@blueprintjs/core';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { Drawer, DrawerSuspense } from '@/components';
|
import { Drawer, DrawerSuspense } from '@/components';
|
||||||
import withDrawers from '@/containers/Drawer/withDrawers';
|
import withDrawers from '@/containers/Drawer/withDrawers';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const InvoiceSendMailContent = React.lazy(() =>
|
const InvoiceSendMailContent = React.lazy(() =>
|
||||||
import('./InvoiceSendMailContent').then((module) => ({
|
import('./InvoiceSendMailContent').then((module) => ({
|
||||||
|
|||||||
@@ -18,9 +18,14 @@ import {
|
|||||||
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||||
import { useDrawerActions } from '@/hooks/state';
|
import { useDrawerActions } from '@/hooks/state';
|
||||||
import { useInvoiceMailItems, useSendInvoiceFormatArgsOptions } from './_hooks';
|
import { useInvoiceMailItems, useSendInvoiceFormatArgsOptions } from './_hooks';
|
||||||
|
import { InvoiceSendMailFormValues } from './_types';
|
||||||
|
|
||||||
// Create new account renderer.
|
// Create new account renderer.
|
||||||
const createNewItemRenderer = (query, active, handleClick) => {
|
const createNewItemRenderer = (
|
||||||
|
query: string,
|
||||||
|
active: boolean,
|
||||||
|
handleClick: React.MouseEventHandler<HTMLElement>,
|
||||||
|
) => {
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon="add"
|
icon="add"
|
||||||
@@ -32,7 +37,7 @@ const createNewItemRenderer = (query, active, handleClick) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create new item from the given query string.
|
// Create new item from the given query string.
|
||||||
const createNewItemFromQuery = (name) => ({ name });
|
const createNewItemFromQuery = (text: string): SelectOptionProps => ({ text });
|
||||||
|
|
||||||
const styleEmailButton = css`
|
const styleEmailButton = css`
|
||||||
&.bp4-button.bp4-small {
|
&.bp4-button.bp4-small {
|
||||||
@@ -62,19 +67,19 @@ export function InvoiceSendMailFields() {
|
|||||||
const [showCCField, setShowCCField] = useState<boolean>(false);
|
const [showCCField, setShowCCField] = useState<boolean>(false);
|
||||||
const [showBccField, setShowBccField] = useState<boolean>(false);
|
const [showBccField, setShowBccField] = useState<boolean>(false);
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
const { values, setFieldValue } =
|
||||||
const { values, setFieldValue } = useFormikContext();
|
useFormikContext<InvoiceSendMailFormValues>();
|
||||||
const items = useInvoiceMailItems();
|
const items = useInvoiceMailItems();
|
||||||
const argsOptions = useSendInvoiceFormatArgsOptions();
|
const argsOptions = useSendInvoiceFormatArgsOptions();
|
||||||
|
|
||||||
const handleClickCcBtn = (event) => {
|
const handleClickCcBtn = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
setShowCCField(true);
|
setShowCCField(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClickBccBtn = (event) => {
|
const handleClickBccBtn = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
@@ -82,64 +87,71 @@ export function InvoiceSendMailFields() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateToItemSelect = (value: SelectOptionProps) => {
|
const handleCreateToItemSelect = (value: SelectOptionProps) => {
|
||||||
setFieldValue('to', [...values?.to, value?.name]);
|
setFieldValue('to', [...values?.to, value?.text]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateCcItemSelect = (value: SelectOptionProps) => {
|
const handleCreateCcItemSelect = (value: SelectOptionProps) => {
|
||||||
setFieldValue('cc', [...values?.cc, value?.name]);
|
setFieldValue('cc', [...values?.cc, value?.text]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateBccItemSelect = (value: SelectOptionProps) => {
|
const handleCreateBccItemSelect = (value: SelectOptionProps) => {
|
||||||
setFieldValue('bcc', [...values?.bcc, value?.name]);
|
setFieldValue('bcc', [...values?.bcc, value?.text]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const rightElementsToField = useMemo(() => (
|
const rightElementsToField = useMemo(
|
||||||
<Group
|
() => (
|
||||||
spacing={0}
|
<Group
|
||||||
paddingRight={'7px'}
|
spacing={0}
|
||||||
paddingTop={'7px'}
|
paddingRight={'7px'}
|
||||||
fontWeight={500}
|
paddingTop={'7px'}
|
||||||
color={'#000'}
|
fontWeight={500}
|
||||||
>
|
color={'#000'}
|
||||||
<Button
|
|
||||||
onClick={handleClickCcBtn}
|
|
||||||
minimal
|
|
||||||
small
|
|
||||||
className={styleEmailButton}
|
|
||||||
>
|
>
|
||||||
CC
|
<Button
|
||||||
</Button>
|
onClick={handleClickCcBtn}
|
||||||
|
minimal
|
||||||
|
small
|
||||||
|
className={styleEmailButton}
|
||||||
|
>
|
||||||
|
CC
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={handleClickBccBtn}
|
onClick={handleClickBccBtn}
|
||||||
minimal
|
minimal
|
||||||
small
|
small
|
||||||
className={styleEmailButton}
|
className={styleEmailButton}
|
||||||
>
|
>
|
||||||
BCC
|
BCC
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
), []);
|
),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const handleTextareaChange = useCallback((item: SelectOptionProps) => {
|
const handleTextareaChange = useCallback(
|
||||||
const textarea = textareaRef.current;
|
(item: SelectOptionProps) => {
|
||||||
if (!textarea) return;
|
const textarea = textareaRef.current;
|
||||||
|
if (!textarea) return;
|
||||||
|
|
||||||
const { selectionStart, selectionEnd, value: text } = textarea;
|
const { selectionStart, selectionEnd, value: text } = textarea;
|
||||||
const insertText = `{${item.value}}`;
|
const insertText = `{${item.value}}`;
|
||||||
const message =
|
const message =
|
||||||
text.substring(0, selectionStart) +
|
text.substring(0, selectionStart) +
|
||||||
insertText +
|
insertText +
|
||||||
text.substring(selectionEnd);
|
text.substring(selectionEnd);
|
||||||
|
|
||||||
setFieldValue('message', message);
|
setFieldValue('message', message);
|
||||||
|
|
||||||
// Move the cursor to the end of the inserted text
|
// Move the cursor to the end of the inserted text
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
textarea.selectionStart = textarea.selectionEnd =
|
textarea.selectionStart = textarea.selectionEnd =
|
||||||
selectionStart + insertText.length;
|
selectionStart + insertText.length;
|
||||||
textarea.focus();
|
textarea.focus();
|
||||||
}, 0);
|
}, 0);
|
||||||
}, [setFieldValue]);
|
},
|
||||||
|
[setFieldValue],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
@@ -233,7 +245,7 @@ export function InvoiceSendMailFields() {
|
|||||||
position: Position.BOTTOM_LEFT,
|
position: Position.BOTTOM_LEFT,
|
||||||
minimal: true,
|
minimal: true,
|
||||||
}}
|
}}
|
||||||
input={({ activeItem, text, label, value }) => (
|
input={() => (
|
||||||
<Button
|
<Button
|
||||||
minimal
|
minimal
|
||||||
rightIcon={
|
rightIcon={
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { css } from '@emotion/css';
|
|||||||
import { Tab, Tabs } from '@blueprintjs/core';
|
import { Tab, Tabs } from '@blueprintjs/core';
|
||||||
import { Stack } from '@/components';
|
import { Stack } from '@/components';
|
||||||
|
|
||||||
const InvoiceMailReceiptPreviewConneceted = lazy(() =>
|
const InvoiceMailReceiptPreviewConnected = lazy(() =>
|
||||||
import('./InvoiceMailReceiptPreviewConnected.').then((module) => ({
|
import('./InvoiceMailReceiptPreviewConnected').then((module) => ({
|
||||||
default: module.InvoiceMailReceiptPreviewConneceted,
|
default: module.InvoiceMailReceiptPreviewConnected,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
const InvoiceSendPdfPreviewConnected = lazy(() =>
|
const InvoiceSendPdfPreviewConnected = lazy(() =>
|
||||||
@@ -51,7 +51,7 @@ export function InvoiceSendMailPreview() {
|
|||||||
title={'Payment page'}
|
title={'Payment page'}
|
||||||
panel={
|
panel={
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<InvoiceMailReceiptPreviewConneceted />
|
<InvoiceMailReceiptPreviewConnected />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -372,6 +372,7 @@ export function useSendSaleInvoiceMail(
|
|||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
export interface GetSaleInvoiceDefaultOptionsResponse {
|
export interface GetSaleInvoiceDefaultOptionsResponse {
|
||||||
companyName: string;
|
companyName: string;
|
||||||
|
companyLogoUri: string;
|
||||||
|
|
||||||
dueDate: string;
|
dueDate: string;
|
||||||
dueDateFormatted: string;
|
dueDateFormatted: string;
|
||||||
|
|||||||
26
pnpm-lock.yaml
generated
26
pnpm-lock.yaml
generated
@@ -491,11 +491,11 @@ importers:
|
|||||||
specifier: '*'
|
specifier: '*'
|
||||||
version: link:../../shared/bigcapital-utils
|
version: link:../../shared/bigcapital-utils
|
||||||
'@blueprintjs-formik/core':
|
'@blueprintjs-formik/core':
|
||||||
specifier: ^0.3.6
|
specifier: ^0.3.7
|
||||||
version: 0.3.6(@babel/core@7.26.0)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
|
version: 0.3.7(@babel/core@7.26.0)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
|
||||||
'@blueprintjs-formik/datetime':
|
'@blueprintjs-formik/datetime':
|
||||||
specifier: ^0.3.7
|
specifier: ^0.3.7
|
||||||
version: 0.3.7(@babel/core@7.26.0)(@blueprintjs-formik/core@0.3.6)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
|
version: 0.3.7(@babel/core@7.26.0)(@blueprintjs-formik/core@0.3.7)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
|
||||||
'@blueprintjs-formik/select':
|
'@blueprintjs-formik/select':
|
||||||
specifier: ^0.3.5
|
specifier: ^0.3.5
|
||||||
version: 0.3.5(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react@18.3.1)
|
version: 0.3.5(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react@18.3.1)
|
||||||
@@ -2501,7 +2501,7 @@ packages:
|
|||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.26.0
|
'@babel/core': 7.26.0
|
||||||
'@babel/helper-plugin-utils': 7.24.5
|
'@babel/helper-plugin-utils': 7.25.9
|
||||||
'@babel/helper-skip-transparent-expression-wrappers': 7.22.5
|
'@babel/helper-skip-transparent-expression-wrappers': 7.22.5
|
||||||
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0)
|
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0)
|
||||||
dev: true
|
dev: true
|
||||||
@@ -3006,7 +3006,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.24.5
|
'@babel/core': 7.24.5
|
||||||
'@babel/helper-module-imports': 7.25.9(supports-color@5.5.0)
|
'@babel/helper-module-imports': 7.25.9(supports-color@5.5.0)
|
||||||
'@babel/helper-plugin-utils': 7.24.5
|
'@babel/helper-plugin-utils': 7.25.9
|
||||||
'@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.5)
|
'@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.5)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -3020,7 +3020,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.26.0
|
'@babel/core': 7.26.0
|
||||||
'@babel/helper-module-imports': 7.25.9(supports-color@5.5.0)
|
'@babel/helper-module-imports': 7.25.9(supports-color@5.5.0)
|
||||||
'@babel/helper-plugin-utils': 7.24.5
|
'@babel/helper-plugin-utils': 7.25.9
|
||||||
'@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.26.0)
|
'@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.26.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -3893,7 +3893,7 @@ packages:
|
|||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.24.5
|
'@babel/core': 7.24.5
|
||||||
'@babel/helper-plugin-utils': 7.24.5
|
'@babel/helper-plugin-utils': 7.25.9
|
||||||
regenerator-transform: 0.15.2
|
regenerator-transform: 0.15.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@@ -3904,7 +3904,7 @@ packages:
|
|||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.26.0
|
'@babel/core': 7.26.0
|
||||||
'@babel/helper-plugin-utils': 7.24.5
|
'@babel/helper-plugin-utils': 7.25.9
|
||||||
regenerator-transform: 0.15.2
|
regenerator-transform: 0.15.2
|
||||||
|
|
||||||
/@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.5):
|
/@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.5):
|
||||||
@@ -4513,8 +4513,8 @@ packages:
|
|||||||
/@bcoe/v8-coverage@0.2.3:
|
/@bcoe/v8-coverage@0.2.3:
|
||||||
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
|
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
|
||||||
|
|
||||||
/@blueprintjs-formik/core@0.3.6(@babel/core@7.26.0)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1):
|
/@blueprintjs-formik/core@0.3.7(@babel/core@7.26.0)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1):
|
||||||
resolution: {integrity: sha512-02suh+bFr65i3BmWPGUbC8roGDtrYmm86MXKJ87ENoQZc+pN8P/fKW99ilIXfg5ZCcsIbUJQU5vb34ONoM71oQ==}
|
resolution: {integrity: sha512-VVotc5x3Yjtm6gHHcYyHN705a9OtyfEtuJn+sdbrnB/LI6TbeibAg43EdXyKRfJThVPdQF9W5bP4WNigOuZxgA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@blueprintjs/core': ^3.52.0 || 4 || 5
|
'@blueprintjs/core': ^3.52.0 || 4 || 5
|
||||||
'@blueprintjs/select': ^3.18.12 || 4 || 5
|
'@blueprintjs/select': ^3.18.12 || 4 || 5
|
||||||
@@ -4536,7 +4536,7 @@ packages:
|
|||||||
- react-is
|
- react-is
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@blueprintjs-formik/datetime@0.3.7(@babel/core@7.26.0)(@blueprintjs-formik/core@0.3.6)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1):
|
/@blueprintjs-formik/datetime@0.3.7(@babel/core@7.26.0)(@blueprintjs-formik/core@0.3.7)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1):
|
||||||
resolution: {integrity: sha512-AZCxM0at6n0kuQaufp5oMYID9tHwz5UlsSGW58j6gNdbJSwQBkeOt5DWPMj6oD7kJGaMXeKxW5/7rLahDX3BPQ==}
|
resolution: {integrity: sha512-AZCxM0at6n0kuQaufp5oMYID9tHwz5UlsSGW58j6gNdbJSwQBkeOt5DWPMj6oD7kJGaMXeKxW5/7rLahDX3BPQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@blueprintjs-formik/core': ^0.3.2 || 4 || 5
|
'@blueprintjs-formik/core': ^0.3.2 || 4 || 5
|
||||||
@@ -4546,7 +4546,7 @@ packages:
|
|||||||
react: 16 || ^17.0.2 || 18
|
react: 16 || ^17.0.2 || 18
|
||||||
react-dom: 16 || ^17.0.2 || 18
|
react-dom: 16 || ^17.0.2 || 18
|
||||||
dependencies:
|
dependencies:
|
||||||
'@blueprintjs-formik/core': 0.3.6(@babel/core@7.26.0)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
|
'@blueprintjs-formik/core': 0.3.7(@babel/core@7.26.0)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
|
||||||
'@blueprintjs/core': 4.20.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
|
'@blueprintjs/core': 4.20.2(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
|
||||||
'@blueprintjs/select': 4.9.24(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
|
'@blueprintjs/select': 4.9.24(@types/react@18.3.4)(react-dom@18.3.1)(react@18.3.1)
|
||||||
formik: 2.4.6(react@18.3.1)
|
formik: 2.4.6(react@18.3.1)
|
||||||
@@ -11863,7 +11863,7 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/regexpp': 4.10.0
|
'@eslint-community/regexpp': 4.11.2
|
||||||
'@typescript-eslint/parser': 8.11.0(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/parser': 8.11.0(eslint@9.13.0)(typescript@5.6.3)
|
||||||
'@typescript-eslint/scope-manager': 8.11.0
|
'@typescript-eslint/scope-manager': 8.11.0
|
||||||
'@typescript-eslint/type-utils': 8.11.0(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/type-utils': 8.11.0(eslint@9.13.0)(typescript@5.6.3)
|
||||||
|
|||||||
@@ -95,109 +95,109 @@ export const InvoicePaymentEmail: React.FC<
|
|||||||
|
|
||||||
items,
|
items,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Html lang="en">
|
<Html lang="en">
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{preview}</Preview>
|
<Preview>{preview}</Preview>
|
||||||
|
|
||||||
<Tailwind>
|
<Tailwind>
|
||||||
<Body style={bodyStyle}>
|
<Body style={bodyStyle}>
|
||||||
<Container style={containerStyle}>
|
<Container style={containerStyle}>
|
||||||
<Section style={mainSectionStyle}>
|
<Section style={mainSectionStyle}>
|
||||||
{companyLogoUri && (
|
{companyLogoUri && (
|
||||||
<Section style={logoSectionStyle}>
|
<Section style={logoSectionStyle}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
...companyLogoStyle,
|
...companyLogoStyle,
|
||||||
backgroundImage: `url("${companyLogoUri}")`,
|
backgroundImage: `url("${companyLogoUri}")`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Image
|
Image
|
||||||
</div>
|
</div>
|
||||||
|
</Section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Section style={headerInfoStyle}>
|
||||||
|
<Row>
|
||||||
|
<Heading style={invoiceCompanyNameStyle}>
|
||||||
|
{companyName}
|
||||||
|
</Heading>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Text style={invoiceAmountStyle}>{invoiceAmount}</Text>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Text style={invoiceNumberStyle}>
|
||||||
|
{invoiceNumberLabel?.replace(
|
||||||
|
'{invoiceNumber}',
|
||||||
|
invoiceNumber
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Text style={invoiceDateStyle}>
|
||||||
|
{dueDateLabel.replace('{dueDate}', dueDate)}
|
||||||
|
</Text>
|
||||||
|
</Row>
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
|
||||||
|
|
||||||
<Section style={headerInfoStyle}>
|
<Text style={invoiceMessageStyle}>{invoiceMessage}</Text>
|
||||||
<Row>
|
<Button
|
||||||
<Heading style={invoiceCompanyNameStyle}>
|
href={viewInvoiceButtonUrl}
|
||||||
{companyName}
|
style={{
|
||||||
</Heading>
|
...viewInvoiceButtonStyle,
|
||||||
</Row>
|
backgroundColor: primaryColor,
|
||||||
<Row>
|
}}
|
||||||
<Text style={invoiceAmountStyle}>{invoiceAmount}</Text>
|
>
|
||||||
</Row>
|
{viewInvoiceButtonLabel}
|
||||||
<Row>
|
</Button>
|
||||||
<Text style={invoiceNumberStyle}>
|
|
||||||
{invoiceNumberLabel?.replace(
|
|
||||||
'{invoiceNumber}',
|
|
||||||
invoiceNumber
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<Text style={invoiceDateStyle}>
|
|
||||||
{dueDateLabel.replace('{dueDate}', dueDate)}
|
|
||||||
</Text>
|
|
||||||
</Row>
|
|
||||||
</Section>
|
|
||||||
|
|
||||||
<Text style={invoiceMessageStyle}>{invoiceMessage}</Text>
|
<Section style={totalsSectionStyle}>
|
||||||
<Button
|
{items.map((item, index) => (
|
||||||
href={viewInvoiceButtonUrl}
|
<Row key={index} style={itemLineRowStyle}>
|
||||||
style={{
|
<Column width={'50%'}>
|
||||||
...viewInvoiceButtonStyle,
|
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||||
backgroundColor: primaryColor,
|
</Column>
|
||||||
}}
|
|
||||||
>
|
|
||||||
{viewInvoiceButtonLabel}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Section style={totalsSectionStyle}>
|
<Column width={'50%'}>
|
||||||
{items.map((item, index) => (
|
<Text style={listItemAmountStyle}>
|
||||||
<Row key={index} style={itemLineRowStyle}>
|
{item.quantity} x {item.rate}
|
||||||
|
</Text>
|
||||||
|
</Column>
|
||||||
|
</Row>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<Row style={dueAmounLineRowStyle}>
|
||||||
<Column width={'50%'}>
|
<Column width={'50%'}>
|
||||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
<Text style={dueAmountLineItemLabelStyle}>
|
||||||
|
{dueAmountLabel}
|
||||||
|
</Text>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
||||||
<Column width={'50%'}>
|
<Column width={'50%'}>
|
||||||
<Text style={listItemAmountStyle}>
|
<Text style={dueAmountLineItemAmountStyle}>
|
||||||
{item.quantity} x {item.rate}
|
{dueAmount}
|
||||||
</Text>
|
</Text>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
|
||||||
|
|
||||||
<Row style={dueAmounLineRowStyle}>
|
<Row style={totalLineRowStyle}>
|
||||||
<Column width={'50%'}>
|
<Column width={'50%'}>
|
||||||
<Text style={dueAmountLineItemLabelStyle}>
|
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
||||||
{dueAmountLabel}
|
</Column>
|
||||||
</Text>
|
|
||||||
</Column>
|
|
||||||
|
|
||||||
<Column width={'50%'}>
|
<Column width={'50%'}>
|
||||||
<Text style={dueAmountLineItemAmountStyle}>
|
<Text style={totalLineItemAmountStyle}>{total}</Text>
|
||||||
{dueAmount}
|
</Column>
|
||||||
</Text>
|
</Row>
|
||||||
</Column>
|
</Section>
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Row style={totalLineRowStyle}>
|
|
||||||
<Column width={'50%'}>
|
|
||||||
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
|
||||||
</Column>
|
|
||||||
|
|
||||||
<Column width={'50%'}>
|
|
||||||
<Text style={totalLineItemAmountStyle}>{total}</Text>
|
|
||||||
</Column>
|
|
||||||
</Row>
|
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Container>
|
||||||
</Container>
|
</Body>
|
||||||
</Body>
|
</Tailwind>
|
||||||
</Tailwind>
|
</Html>
|
||||||
</Html>
|
);
|
||||||
);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
export const renderInvoicePaymentEmail = (props: InvoicePaymentEmailProps) => {
|
export const renderInvoicePaymentEmail = (props: InvoicePaymentEmailProps) => {
|
||||||
return render(<InvoicePaymentEmail {...props} />);
|
return render(<InvoicePaymentEmail {...props} />);
|
||||||
@@ -274,6 +274,7 @@ const invoiceMessageStyle: CSSProperties = {
|
|||||||
whiteSpace: 'pre-line',
|
whiteSpace: 'pre-line',
|
||||||
color: '#252A31',
|
color: '#252A31',
|
||||||
margin: '0 0 20px 0',
|
margin: '0 0 20px 0',
|
||||||
|
lineHeight: '20px',
|
||||||
};
|
};
|
||||||
|
|
||||||
const dueAmounLineRowStyle: CSSProperties = {
|
const dueAmounLineRowStyle: CSSProperties = {
|
||||||
|
|||||||
Reference in New Issue
Block a user