feat: add discount and adjustment fields to email templates.
This commit is contained in:
@@ -26,6 +26,9 @@ export interface ISaleEstimate {
|
||||
branchId?: number;
|
||||
warehouseId?: number;
|
||||
|
||||
total?: number;
|
||||
totalLocal?: number;
|
||||
|
||||
discountAmount?: number;
|
||||
discountPercentage?: number | null;
|
||||
|
||||
|
||||
@@ -25,6 +25,12 @@ export class GetEstimateMailTemplateAttributesTransformer extends Transformer {
|
||||
'subtotal',
|
||||
'subtotalLabel',
|
||||
|
||||
'discount',
|
||||
'discountLabel',
|
||||
|
||||
'adjustment',
|
||||
'adjustmentLabel',
|
||||
|
||||
'dueAmount',
|
||||
'dueAmountLabel',
|
||||
|
||||
@@ -103,7 +109,7 @@ export class GetEstimateMailTemplateAttributesTransformer extends Transformer {
|
||||
* Estimate total.
|
||||
*/
|
||||
public total(): string {
|
||||
return this.options.estimate.formattedAmount;
|
||||
return this.options.estimate.totalFormatted;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,11 +120,43 @@ export class GetEstimateMailTemplateAttributesTransformer extends Transformer {
|
||||
return 'Total';
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate discount.
|
||||
* @returns {string}
|
||||
*/
|
||||
public discount(): string {
|
||||
return this.options.estimate?.discountAmountFormatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate discount label.
|
||||
* @returns {string}
|
||||
*/
|
||||
public discountLabel(): string {
|
||||
return 'Discount';
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate adjustment.
|
||||
* @returns {string}
|
||||
*/
|
||||
public adjustment(): string {
|
||||
return this.options.estimate?.adjustmentFormatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate adjustment label.
|
||||
* @returns {string}
|
||||
*/
|
||||
public adjustmentLabel(): string {
|
||||
return 'Adjustment';
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate subtotal.
|
||||
*/
|
||||
public subtotal(): string {
|
||||
return this.options.estimate.formattedAmount;
|
||||
return this.options.estimate.formattedSubtotal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,8 @@ export class SaleEstimateTransfromer extends Transformer {
|
||||
'discountAmountFormatted',
|
||||
'discountPercentageFormatted',
|
||||
'adjustmentFormatted',
|
||||
'totalFormatted',
|
||||
'totalLocalFormatted',
|
||||
'formattedCreatedAt',
|
||||
'entries',
|
||||
'attachments',
|
||||
@@ -134,6 +136,27 @@ export class SaleEstimateTransfromer extends Transformer {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted estimate total.
|
||||
* @returns {string}
|
||||
*/
|
||||
protected totalFormatted = (estimate: ISaleEstimate): string => {
|
||||
return formatNumber(estimate.total, {
|
||||
currencyCode: estimate.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted estimate total in local currency.
|
||||
* @param estimate
|
||||
* @returns {string}
|
||||
*/
|
||||
protected totalLocalFormatted = (estimate: ISaleEstimate): string => {
|
||||
return formatNumber(estimate.totalLocal, {
|
||||
currencyCode: estimate.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the entries of the sale estimate.
|
||||
* @param {ISaleEstimate} estimate
|
||||
|
||||
@@ -18,9 +18,6 @@ export class SaleEstimatesPdf {
|
||||
@Inject()
|
||||
private chromiumlyTenancy: ChromiumlyTenancy;
|
||||
|
||||
@Inject()
|
||||
private templateInjectable: TemplateInjectable;
|
||||
|
||||
@Inject()
|
||||
private getSaleEstimate: GetSaleEstimate;
|
||||
|
||||
@@ -62,6 +59,7 @@ export class SaleEstimatesPdf {
|
||||
// Retireves the sale estimate html.
|
||||
const htmlContent = await this.saleEstimateHtml(tenantId, saleEstimateId);
|
||||
|
||||
// Converts the html content to pdf.
|
||||
const content = await this.chromiumlyTenancy.convertHtmlContent(
|
||||
tenantId,
|
||||
htmlContent
|
||||
|
||||
@@ -23,6 +23,15 @@ export class GetInvoiceMailTemplateAttributesTransformer extends Transformer {
|
||||
'invoiceNumber',
|
||||
'invoiceNumberLabel',
|
||||
|
||||
'subtotal',
|
||||
'subtotalLabel',
|
||||
|
||||
'discount',
|
||||
'discountLabel',
|
||||
|
||||
'adjustment',
|
||||
'adjustmentLabel',
|
||||
|
||||
'total',
|
||||
'totalLabel',
|
||||
|
||||
@@ -76,6 +85,30 @@ export class GetInvoiceMailTemplateAttributesTransformer extends Transformer {
|
||||
return 'Invoice # {invoiceNumber}';
|
||||
}
|
||||
|
||||
public subtotal(): string {
|
||||
return this.options.invoice?.subtotalFormatted;
|
||||
}
|
||||
|
||||
public subtotalLabel(): string {
|
||||
return 'Subtotal';
|
||||
}
|
||||
|
||||
public discount(): string {
|
||||
return this.options.invoice?.discountAmountFormatted;
|
||||
}
|
||||
|
||||
public discountLabel(): string {
|
||||
return 'Discount';
|
||||
}
|
||||
|
||||
public adjustment(): string {
|
||||
return this.options.invoice?.adjustmentFormatted;
|
||||
}
|
||||
|
||||
public adjustmentLabel(): string {
|
||||
return 'Adjustment';
|
||||
}
|
||||
|
||||
public total(): string {
|
||||
return this.options.invoice?.totalFormatted;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,12 @@ export class GetSaleReceiptMailTemplateAttributesTransformer extends Transformer
|
||||
'total',
|
||||
'totalLabel',
|
||||
|
||||
'discount',
|
||||
'discountLabel',
|
||||
|
||||
'adjustment',
|
||||
'adjustmentLabel',
|
||||
|
||||
'subtotal',
|
||||
'subtotalLabel',
|
||||
|
||||
@@ -98,7 +104,7 @@ export class GetSaleReceiptMailTemplateAttributesTransformer extends Transformer
|
||||
* Receipt total.
|
||||
*/
|
||||
public total(): string {
|
||||
return this.options.receipt.formattedAmount;
|
||||
return this.options.receipt.totalFormatted;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,12 +115,44 @@ export class GetSaleReceiptMailTemplateAttributesTransformer extends Transformer
|
||||
return 'Total';
|
||||
}
|
||||
|
||||
/**
|
||||
* Receipt discount.
|
||||
* @returns {string}
|
||||
*/
|
||||
public discount(): string {
|
||||
return this.options.receipt?.discountAmountFormatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receipt discount label.
|
||||
* @returns {string}
|
||||
*/
|
||||
public discountLabel(): string {
|
||||
return 'Discount';
|
||||
}
|
||||
|
||||
/**
|
||||
* Receipt adjustment.
|
||||
* @returns {string}
|
||||
*/
|
||||
public adjustment(): string {
|
||||
return this.options.receipt?.adjustmentFormatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receipt adjustment label.
|
||||
* @returns {string}
|
||||
*/
|
||||
public adjustmentLabel(): string {
|
||||
return 'Adjustment';
|
||||
}
|
||||
|
||||
/**
|
||||
* Receipt subtotal.
|
||||
* @returns {string}
|
||||
*/
|
||||
public subtotal(): string {
|
||||
return this.options.receipt.formattedSubtotal;
|
||||
return this.options.receipt.subtotalFormatted;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
19
pnpm-lock.yaml
generated
19
pnpm-lock.yaml
generated
@@ -882,6 +882,12 @@ importers:
|
||||
'@react-email/components':
|
||||
specifier: 0.0.25
|
||||
version: 0.0.25(react-dom@18.3.1)(react@18.3.1)
|
||||
'@types/lodash.isempty':
|
||||
specifier: ^4.4.9
|
||||
version: 4.4.9
|
||||
lodash.isempty:
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0
|
||||
react:
|
||||
specifier: 18.3.1
|
||||
version: 18.3.1
|
||||
@@ -2504,7 +2510,7 @@ packages:
|
||||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.26.0
|
||||
'@babel/helper-plugin-utils': 7.25.9
|
||||
'@babel/helper-plugin-utils': 7.24.5
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.22.5
|
||||
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0)
|
||||
dev: true
|
||||
@@ -11420,6 +11426,12 @@ packages:
|
||||
- tedious
|
||||
dev: false
|
||||
|
||||
/@types/lodash.isempty@4.4.9:
|
||||
resolution: {integrity: sha512-DPSFfnT2JmZiAWNWOU8IRZws/Ha6zyGF5m06TydfsY+0dVoQqby2J61Na2QU4YtwiZ+moC6cJS6zWYBJq4wBVw==}
|
||||
dependencies:
|
||||
'@types/lodash': 4.17.13
|
||||
dev: false
|
||||
|
||||
/@types/lodash@4.17.13:
|
||||
resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==}
|
||||
dev: false
|
||||
@@ -15958,7 +15970,7 @@ packages:
|
||||
postcss-modules-values: 4.0.0(postcss@8.4.47)
|
||||
postcss-value-parser: 4.2.0
|
||||
semver: 7.6.2
|
||||
webpack: 5.91.0(esbuild@0.23.1)
|
||||
webpack: 5.91.0(esbuild@0.18.20)(webpack-cli@5.1.4)
|
||||
|
||||
/css-minimizer-webpack-plugin@3.4.1(esbuild@0.23.1)(webpack@5.91.0):
|
||||
resolution: {integrity: sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==}
|
||||
@@ -31178,7 +31190,7 @@ packages:
|
||||
peerDependencies:
|
||||
webpack: ^5.0.0
|
||||
dependencies:
|
||||
webpack: 5.91.0(esbuild@0.23.1)
|
||||
webpack: 5.91.0(esbuild@0.18.20)(webpack-cli@5.1.4)
|
||||
|
||||
/styled-components@5.3.11(@babel/core@7.26.0)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1):
|
||||
resolution: {integrity: sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==}
|
||||
@@ -33492,6 +33504,7 @@ packages:
|
||||
- '@swc/core'
|
||||
- esbuild
|
||||
- uglify-js
|
||||
dev: false
|
||||
|
||||
/webpack@5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0):
|
||||
resolution: {integrity: sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==}
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-email/components": "0.0.25",
|
||||
"@types/lodash.isempty": "^4.4.9",
|
||||
"lodash.isempty": "^4.4.0",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"tailwindcss": "^3.4.14",
|
||||
"vite-plugin-dts": "^4.3.0",
|
||||
"vitest": "^2.1.3",
|
||||
"react-dom": "18.3.1",
|
||||
"react": "18.3.1"
|
||||
"vitest": "^2.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.13.0",
|
||||
|
||||
@@ -30,4 +30,7 @@ If you have any questions, please let us know.
|
||||
|
||||
Thanks,
|
||||
Bigcapital`,
|
||||
subtotal: '$1,000.00',
|
||||
discount: '$1,000.00',
|
||||
adjustment: '$1,000.00'
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Section,
|
||||
Text,
|
||||
} from '@react-email/components';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { EmailTemplateLayout } from './EmailTemplateLayout';
|
||||
import { CSSProperties } from 'react';
|
||||
import { EmailTemplate } from './EmailTemplate';
|
||||
@@ -25,6 +26,18 @@ export interface CreditNoteEmailProps {
|
||||
total: string;
|
||||
totalLabel?: string;
|
||||
|
||||
// # Subtotal
|
||||
subtotal: string;
|
||||
subtotalLabel?: string;
|
||||
|
||||
// # Adjustment
|
||||
adjustment?: string;
|
||||
adjustmentLabel?: string;
|
||||
|
||||
// # Discount
|
||||
discount?: string;
|
||||
discountLabel?: string;
|
||||
|
||||
// # Items
|
||||
items: Array<{ label: string; quantity: string; rate: string }>;
|
||||
|
||||
@@ -56,6 +69,18 @@ export const CreditNoteEmailTemplate: React.FC<
|
||||
total,
|
||||
totalLabel = 'Total',
|
||||
|
||||
// # Subtotal
|
||||
subtotal,
|
||||
subtotalLabel = 'Subtotal',
|
||||
|
||||
// # Discount
|
||||
discount,
|
||||
discountLabel = 'Discount',
|
||||
|
||||
// # Adjustment
|
||||
adjustment,
|
||||
adjustmentLabel = 'Adjustment',
|
||||
|
||||
// # Credit Note #
|
||||
creditNoteNumberLabel = 'Credit Note # {creditNoteNumber}',
|
||||
creditNoteNumber = 'CN-00001',
|
||||
@@ -70,70 +95,104 @@ export const CreditNoteEmailTemplate: React.FC<
|
||||
// # Items
|
||||
items = [],
|
||||
}) => {
|
||||
return (
|
||||
<EmailTemplateLayout preview={preview}>
|
||||
<EmailTemplate>
|
||||
<Section style={mainSectionStyle}>
|
||||
{companyLogoUri && <EmailTemplate.CompanyLogo src={companyLogoUri} />}
|
||||
return (
|
||||
<EmailTemplateLayout preview={preview}>
|
||||
<EmailTemplate>
|
||||
<Section style={mainSectionStyle}>
|
||||
{companyLogoUri && <EmailTemplate.CompanyLogo src={companyLogoUri} />}
|
||||
|
||||
<Section style={headerInfoStyle}>
|
||||
<Row>
|
||||
<Heading style={companyNameStyle}>{companyName}</Heading>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={invoiceAmountStyle}>{total}</Text>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={creditNumberStyle}>
|
||||
{creditNoteNumberLabel?.replace(
|
||||
'{creditNoteNumber}',
|
||||
creditNoteNumber
|
||||
)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Section>
|
||||
|
||||
<Text style={messageStyle}>{message}</Text>
|
||||
<Button
|
||||
href={viewButtonUrl}
|
||||
style={{
|
||||
...viewInvoiceButtonStyle,
|
||||
backgroundColor: primaryColor,
|
||||
}}
|
||||
>
|
||||
{viewButtonLabel}
|
||||
</Button>
|
||||
|
||||
<Section style={totalsSectionStyle}>
|
||||
{items.map((item, index) => (
|
||||
<Row key={index} style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>
|
||||
{item.quantity} x {item.rate}
|
||||
</Text>
|
||||
</Column>
|
||||
</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 style={headerInfoStyle}>
|
||||
<Row>
|
||||
<Heading style={companyNameStyle}>{companyName}</Heading>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={invoiceAmountStyle}>{total}</Text>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={creditNumberStyle}>
|
||||
{creditNoteNumberLabel?.replace(
|
||||
'{creditNoteNumber}',
|
||||
creditNoteNumber
|
||||
)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Section>
|
||||
</EmailTemplate>
|
||||
</EmailTemplateLayout>
|
||||
);
|
||||
};
|
||||
|
||||
<Text style={messageStyle}>{message}</Text>
|
||||
<Button
|
||||
href={viewButtonUrl}
|
||||
style={{
|
||||
...viewInvoiceButtonStyle,
|
||||
backgroundColor: primaryColor,
|
||||
}}
|
||||
>
|
||||
{viewButtonLabel}
|
||||
</Button>
|
||||
|
||||
<Section style={totalsSectionStyle}>
|
||||
{items.map((item, index) => (
|
||||
<Row key={index} style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>
|
||||
{item.quantity} x {item.rate}
|
||||
</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
))}
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{subtotalLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{subtotal}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
{!isEmpty(discount) && (
|
||||
<Row style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{discountLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>{discount}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
{!isEmpty(adjustment) && (
|
||||
<Row style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{adjustmentLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>{adjustment}</Text>
|
||||
</Column>
|
||||
</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>
|
||||
</EmailTemplate>
|
||||
</EmailTemplateLayout>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the estimate mail template to string
|
||||
|
||||
@@ -30,4 +30,7 @@ If you have any questions, please let us know.
|
||||
|
||||
Thanks,
|
||||
Bigcapital`,
|
||||
adjustment: '$100.00',
|
||||
discount: '$100.00',
|
||||
subtotal: '$100.00',
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { CSSProperties } from 'react';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import {
|
||||
Button,
|
||||
Column,
|
||||
Container,
|
||||
Heading,
|
||||
render,
|
||||
Row,
|
||||
@@ -30,7 +30,15 @@ export interface EstimatePaymentEmailProps {
|
||||
subtotal: string;
|
||||
subtotalLabel?: string;
|
||||
|
||||
// # Estimate No#
|
||||
// # Adjustment
|
||||
adjustment?: string;
|
||||
adjustmentLabel?: string;
|
||||
|
||||
// # Discount
|
||||
discount?: string;
|
||||
discountLabel?: string;
|
||||
|
||||
// # Estimate No.
|
||||
estimateNumber?: string;
|
||||
estimateNumberLabel?: string;
|
||||
|
||||
@@ -65,6 +73,14 @@ export const EstimatePaymentEmail: React.FC<
|
||||
total,
|
||||
totalLabel = 'Total',
|
||||
|
||||
// # Adjustment
|
||||
adjustment,
|
||||
adjustmentLabel = 'Adjustment',
|
||||
|
||||
// # Discount
|
||||
discount,
|
||||
discountLabel = 'Discount',
|
||||
|
||||
// # Subtotal
|
||||
subtotal,
|
||||
subtotalLabel = 'Subtotal',
|
||||
@@ -87,84 +103,108 @@ export const EstimatePaymentEmail: React.FC<
|
||||
// # Items
|
||||
items = [],
|
||||
}) => {
|
||||
return (
|
||||
<EmailTemplateLayout preview={preview}>
|
||||
<EmailTemplate>
|
||||
{companyLogoUri && <EmailTemplate.CompanyLogo src={companyLogoUri} />}
|
||||
return (
|
||||
<EmailTemplateLayout preview={preview}>
|
||||
<EmailTemplate>
|
||||
{companyLogoUri && <EmailTemplate.CompanyLogo src={companyLogoUri} />}
|
||||
|
||||
<Section style={headerInfoStyle}>
|
||||
<Row>
|
||||
<Heading style={invoiceCompanyNameStyle}>{companyName}</Heading>
|
||||
<Section style={headerInfoStyle}>
|
||||
<Row>
|
||||
<Heading style={invoiceCompanyNameStyle}>{companyName}</Heading>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={estimateAmountStyle}>{total}</Text>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={estimateNumberStyle}>
|
||||
{estimateNumberLabel?.replace('{estimateNumber}', estimateNumber)}
|
||||
</Text>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={estimateExpirationStyle}>
|
||||
{expirationDateLabel.replace('{expirationDate}', expirationDate)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Section>
|
||||
|
||||
<Text style={estimateMessageStyle}>{message}</Text>
|
||||
<Button
|
||||
href={viewEstimateButtonUrl}
|
||||
style={{
|
||||
...viewEstimateButtonStyle,
|
||||
backgroundColor: primaryColor,
|
||||
}}
|
||||
>
|
||||
{viewEstimateButtonLabel}
|
||||
</Button>
|
||||
|
||||
<Section style={totalsSectionStyle}>
|
||||
{items.map((item, index) => (
|
||||
<Row key={index} style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>
|
||||
{item.quantity} x {item.rate}
|
||||
</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={estimateAmountStyle}>{total}</Text>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={estimateNumberStyle}>
|
||||
{estimateNumberLabel?.replace('{estimateNumber}', estimateNumber)}
|
||||
</Text>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={estimateExpirationStyle}>
|
||||
{expirationDateLabel.replace('{expirationDate}', expirationDate)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Section>
|
||||
))}
|
||||
|
||||
<Text style={estimateMessageStyle}>{message}</Text>
|
||||
<Button
|
||||
href={viewEstimateButtonUrl}
|
||||
style={{
|
||||
...viewEstimateButtonStyle,
|
||||
backgroundColor: primaryColor,
|
||||
}}
|
||||
>
|
||||
{viewEstimateButtonLabel}
|
||||
</Button>
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{subtotalLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Section style={totalsSectionStyle}>
|
||||
{items.map((item, index) => (
|
||||
<Row key={index} style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>
|
||||
{item.quantity} x {item.rate}
|
||||
</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
))}
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{subtotal}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
{!isEmpty(discount) && (
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{subtotalLabel}</Text>
|
||||
<Text style={listItemLabelStyle}>{discountLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{subtotal}</Text>
|
||||
<Text style={listItemAmountStyle}>{discount}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
{!isEmpty(adjustment) && (
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
||||
<Text style={listItemLabelStyle}>{adjustmentLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{total}</Text>
|
||||
<Text style={listItemAmountStyle}>{adjustment}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
</Section>
|
||||
</EmailTemplate>
|
||||
</EmailTemplateLayout>
|
||||
);
|
||||
};
|
||||
)}
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{total}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
</Section>
|
||||
</EmailTemplate>
|
||||
</EmailTemplateLayout>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the estimate mail template to string
|
||||
* @param {EstimatePaymentEmailProps} props
|
||||
* @param {EstimatePaymentEmailProps} props
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export const renderEstimateEmailTemplate = (
|
||||
|
||||
@@ -33,6 +33,9 @@ Thanks,
|
||||
Bigcapital`,
|
||||
dueDate: ' 10 Oct 2024',
|
||||
total: '$1,000.00',
|
||||
subtotal: '$1,000.00',
|
||||
dueAmount: '$1,000.00',
|
||||
items: [{ label: 'Swaniawski Muller', quantity: '1', rate: '$1,000.00' }],
|
||||
adjustment: '$100.00',
|
||||
discount: '$100.00',
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CSSProperties } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Container,
|
||||
Section,
|
||||
Heading,
|
||||
Text,
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
Column,
|
||||
render,
|
||||
} from '@react-email/components';
|
||||
import { CSSProperties } from 'react';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { EmailTemplateLayout } from './EmailTemplateLayout';
|
||||
import { EmailTemplate } from './EmailTemplate';
|
||||
|
||||
@@ -36,6 +36,18 @@ export interface InvoicePaymentEmailProps {
|
||||
dueAmount: string;
|
||||
dueAmountLabel?: string;
|
||||
|
||||
// # Adjustment
|
||||
adjustment?: string;
|
||||
adjustmentLabel?: string;
|
||||
|
||||
// # Discount
|
||||
discount?: string;
|
||||
discountLabel?: string;
|
||||
|
||||
// # Subtotal
|
||||
subtotal: string;
|
||||
subtotalLabel?: string;
|
||||
|
||||
// # Due date
|
||||
dueDate: string;
|
||||
dueDateLabel?: string;
|
||||
@@ -82,6 +94,18 @@ export const InvoicePaymentEmail: React.FC<
|
||||
total,
|
||||
totalLabel = 'Total',
|
||||
|
||||
// # Subtotal
|
||||
subtotal,
|
||||
subtotalLabel = 'Subtotal',
|
||||
|
||||
// # Discount
|
||||
discount,
|
||||
discountLabel = 'Discount',
|
||||
|
||||
// # Adjustment
|
||||
adjustment,
|
||||
adjustmentLabel = 'Adjustment',
|
||||
|
||||
// # Invoice due amount
|
||||
dueAmountLabel = 'Due Amount',
|
||||
dueAmount,
|
||||
@@ -92,84 +116,118 @@ export const InvoicePaymentEmail: React.FC<
|
||||
|
||||
items,
|
||||
}) => {
|
||||
return (
|
||||
<EmailTemplateLayout preview={preview}>
|
||||
<EmailTemplate>
|
||||
<Section style={mainSectionStyle}>
|
||||
{companyLogoUri && <EmailTemplate.CompanyLogo src={companyLogoUri} />}
|
||||
return (
|
||||
<EmailTemplateLayout preview={preview}>
|
||||
<EmailTemplate>
|
||||
<Section style={mainSectionStyle}>
|
||||
{companyLogoUri && <EmailTemplate.CompanyLogo src={companyLogoUri} />}
|
||||
|
||||
<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 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>
|
||||
|
||||
<Text style={invoiceMessageStyle}>{invoiceMessage}</Text>
|
||||
<Button
|
||||
href={viewInvoiceButtonUrl}
|
||||
style={{
|
||||
...viewInvoiceButtonStyle,
|
||||
backgroundColor: primaryColor,
|
||||
}}
|
||||
>
|
||||
{viewInvoiceButtonLabel}
|
||||
</Button>
|
||||
<Text style={invoiceMessageStyle}>{invoiceMessage}</Text>
|
||||
<Button
|
||||
href={viewInvoiceButtonUrl}
|
||||
style={{
|
||||
...viewInvoiceButtonStyle,
|
||||
backgroundColor: primaryColor,
|
||||
}}
|
||||
>
|
||||
{viewInvoiceButtonLabel}
|
||||
</Button>
|
||||
|
||||
<Section style={totalsSectionStyle}>
|
||||
{items.map((item, index) => (
|
||||
<Row key={index} style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>
|
||||
{item.quantity} x {item.rate}
|
||||
</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
))}
|
||||
|
||||
<Row style={dueAmounLineRowStyle}>
|
||||
<Section style={totalsSectionStyle}>
|
||||
{items.map((item, index) => (
|
||||
<Row key={index} style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={dueAmountLineItemLabelStyle}>
|
||||
{dueAmountLabel}
|
||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>
|
||||
{item.quantity} x {item.rate}
|
||||
</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
))}
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{subtotalLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{subtotal}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
{!isEmpty(discount) && (
|
||||
<Row style={lineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{discountLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={dueAmountLineItemAmountStyle}>{dueAmount}</Text>
|
||||
<Text style={listItemAmountStyle}>{discount}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
{!isEmpty(adjustment) && (
|
||||
<Row style={lineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
||||
<Text style={listItemLabelStyle}>{adjustmentLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{total}</Text>
|
||||
<Text style={listItemAmountStyle}>{adjustment}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{total}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
<Row style={dueAmounLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={dueAmountLineItemLabelStyle}>
|
||||
{dueAmountLabel}
|
||||
</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={dueAmountLineItemAmountStyle}>{dueAmount}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
</Section>
|
||||
</EmailTemplate>
|
||||
</EmailTemplateLayout>
|
||||
);
|
||||
};
|
||||
</Section>
|
||||
</EmailTemplate>
|
||||
</EmailTemplateLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderInvoicePaymentEmail = (props: InvoicePaymentEmailProps) => {
|
||||
return render(<InvoicePaymentEmail {...props} />);
|
||||
@@ -237,6 +295,11 @@ const dueAmounLineRowStyle: CSSProperties = {
|
||||
height: 40,
|
||||
};
|
||||
|
||||
const lineRowStyle: CSSProperties = {
|
||||
borderBottom: '1px solid #D9D9D9',
|
||||
height: 40,
|
||||
};
|
||||
|
||||
const totalLineRowStyle: CSSProperties = {
|
||||
borderBottom: '1px solid #000',
|
||||
height: 40,
|
||||
|
||||
@@ -28,4 +28,6 @@ If you have any questions, please let us know.
|
||||
|
||||
Thanks,
|
||||
Bigcapital`,
|
||||
adjustment: '$100.00',
|
||||
discount: '$100.00',
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CSSProperties } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Column,
|
||||
Heading,
|
||||
render,
|
||||
@@ -7,14 +7,12 @@ import {
|
||||
Section,
|
||||
Text,
|
||||
} from '@react-email/components';
|
||||
import { CSSProperties } from 'react';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { EmailTemplateLayout } from './EmailTemplateLayout';
|
||||
import { EmailTemplate } from './EmailTemplate';
|
||||
|
||||
export interface ReceiptEmailTemplateProps {
|
||||
preview: string;
|
||||
|
||||
|
||||
companyName?: string;
|
||||
companyLogoUri: string;
|
||||
|
||||
@@ -36,6 +34,10 @@ export interface ReceiptEmailTemplateProps {
|
||||
discount?: string;
|
||||
discountLabel?: string;
|
||||
|
||||
// # Adjustment
|
||||
adjustment?: string;
|
||||
adjustmentLabel?: string;
|
||||
|
||||
// # Subtotal
|
||||
subtotal?: string;
|
||||
subtotalLabel?: string;
|
||||
@@ -60,6 +62,14 @@ export const ReceiptEmailTemplate: React.FC<
|
||||
total = '$1,000.00',
|
||||
totalLabel = 'Total',
|
||||
|
||||
// # Diso
|
||||
discountLabel = 'Discount',
|
||||
discount,
|
||||
|
||||
// # ADjustment
|
||||
adjustmentLabel = 'Adjustment',
|
||||
adjustment,
|
||||
|
||||
// # Subtotal
|
||||
subtotal = '$1,000.00',
|
||||
subtotalLabel = 'Subtotal',
|
||||
@@ -74,68 +84,92 @@ export const ReceiptEmailTemplate: React.FC<
|
||||
// # Items
|
||||
items = [{ label: 'Swaniawski Muller', quantity: '1', rate: '$1,000.00' }],
|
||||
}) => {
|
||||
return (
|
||||
<EmailTemplateLayout preview={preview}>
|
||||
<EmailTemplate>
|
||||
{companyLogoUri && <EmailTemplate.CompanyLogo src={companyLogoUri} />}
|
||||
return (
|
||||
<EmailTemplateLayout preview={preview}>
|
||||
<EmailTemplate>
|
||||
{companyLogoUri && <EmailTemplate.CompanyLogo src={companyLogoUri} />}
|
||||
|
||||
<Section style={headerInfoStyle}>
|
||||
<Row>
|
||||
<Heading style={invoiceCompanyNameStyle}>{companyName}</Heading>
|
||||
</Row>
|
||||
<Section style={headerInfoStyle}>
|
||||
<Row>
|
||||
<Heading style={invoiceCompanyNameStyle}>{companyName}</Heading>
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Text style={amountStyle}>{total}</Text>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text style={amountStyle}>{total}</Text>
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Text style={receiptNumberStyle}>
|
||||
{receiptNumberLabel?.replace('{receiptNumber}', receiptNumber)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Section>
|
||||
<Row>
|
||||
<Text style={receiptNumberStyle}>
|
||||
{receiptNumberLabel?.replace('{receiptNumber}', receiptNumber)}
|
||||
</Text>
|
||||
</Row>
|
||||
</Section>
|
||||
|
||||
<Text style={messageStyle}>{message}</Text>
|
||||
<Text style={messageStyle}>{message}</Text>
|
||||
|
||||
<Section style={totalsSectionStyle}>
|
||||
{items.map((item, index) => (
|
||||
<Row key={index} style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>
|
||||
{item.quantity} x {item.rate}
|
||||
</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
))}
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Section style={totalsSectionStyle}>
|
||||
{items.map((item, index) => (
|
||||
<Row key={index} style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={dueAmountLineItemLabelStyle}>{subtotalLabel}</Text>
|
||||
<Text style={listItemLabelStyle}>{item.label}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={dueAmountLineItemAmountStyle}>{subtotal}</Text>
|
||||
<Text style={listItemAmountStyle}>
|
||||
{item.quantity} x {item.rate}
|
||||
</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
))}
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={dueAmountLineItemLabelStyle}>{subtotalLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={dueAmountLineItemAmountStyle}>{subtotal}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
|
||||
{!isEmpty(discount) && (
|
||||
<Row style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
||||
<Text style={listItemLabelStyle}>{discountLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{total}</Text>
|
||||
<Text style={listItemAmountStyle}>{discount}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
</Section>
|
||||
</EmailTemplate>
|
||||
</EmailTemplateLayout>
|
||||
);
|
||||
};
|
||||
)}
|
||||
|
||||
{!isEmpty(adjustment) && (
|
||||
<Row style={itemLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemLabelStyle}>{adjustmentLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={listItemAmountStyle}>{adjustment}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
<Row style={totalLineRowStyle}>
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemLabelStyle}>{totalLabel}</Text>
|
||||
</Column>
|
||||
|
||||
<Column width={'50%'}>
|
||||
<Text style={totalLineItemAmountStyle}>{total}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
</Section>
|
||||
</EmailTemplate>
|
||||
</EmailTemplateLayout>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the sale receipt mail template to string
|
||||
|
||||
Reference in New Issue
Block a user