mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 06:40:31 +00:00
feat: Hook up customer/company address to invoice preview of payment page
This commit is contained in:
@@ -3,6 +3,7 @@ import { ItemEntryTransformer } from './ItemEntryTransformer';
|
|||||||
import { SaleInvoiceTaxEntryTransformer } from './SaleInvoiceTaxEntryTransformer';
|
import { SaleInvoiceTaxEntryTransformer } from './SaleInvoiceTaxEntryTransformer';
|
||||||
import { SaleInvoiceTransformer } from './SaleInvoiceTransformer';
|
import { SaleInvoiceTransformer } from './SaleInvoiceTransformer';
|
||||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||||
|
import { contactAddressTextFormat } from '@/utils/address-text-format';
|
||||||
|
|
||||||
export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer {
|
export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer {
|
||||||
/**
|
/**
|
||||||
@@ -43,6 +44,7 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
|
|||||||
'organization',
|
'organization',
|
||||||
'isReceivable',
|
'isReceivable',
|
||||||
'hasStripePaymentMethod',
|
'hasStripePaymentMethod',
|
||||||
|
'formattedCustomerAddress',
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -101,6 +103,14 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
|
|||||||
(paymentMethod) => paymentMethod.paymentIntegration.service === 'Stripe'
|
(paymentMethod) => paymentMethod.paymentIntegration.service === 'Stripe'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected formattedCustomerAddress(invoice) {
|
||||||
|
return contactAddressTextFormat(invoice.customer, `{ADDRESS_1}
|
||||||
|
{ADDRESS_2}
|
||||||
|
{CITY}, {STATE} {POSTAL_CODE}
|
||||||
|
{COUNTRY}
|
||||||
|
{PHONE}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetPaymentLinkOrganizationMetaTransformer extends Transformer {
|
class GetPaymentLinkOrganizationMetaTransformer extends Transformer {
|
||||||
|
|||||||
@@ -68,11 +68,11 @@ export default class TenantMetadata extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
public get addressTextFormatted() {
|
public get addressTextFormatted() {
|
||||||
const defaultMessage = `<strong>{ORGANIZATION_NAME}</strong>
|
const defaultMessage = `<strong>{ORGANIZATION_NAME}</strong>
|
||||||
{ADDRESS_1},
|
{ADDRESS_1}
|
||||||
{ADDRESS_2},
|
{ADDRESS_2}
|
||||||
{CITY} {STATE},
|
{CITY}, {STATE} {POSTAL_CODE}
|
||||||
{POSTAL_CODE},
|
|
||||||
{COUNTRY}
|
{COUNTRY}
|
||||||
|
{PHONE}
|
||||||
`;
|
`;
|
||||||
return organizationAddressTextFormat(defaultMessage, {
|
return organizationAddressTextFormat(defaultMessage, {
|
||||||
organizationName: this.name,
|
organizationName: this.name,
|
||||||
@@ -81,6 +81,7 @@ export default class TenantMetadata extends BaseModel {
|
|||||||
state: this.address?.stateProvince,
|
state: this.address?.stateProvince,
|
||||||
city: this.address?.city,
|
city: this.address?.city,
|
||||||
postalCode: this.address?.postalCode,
|
postalCode: this.address?.postalCode,
|
||||||
|
phone: this.address?.phone,
|
||||||
country: 'United State',
|
country: 'United State',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,17 +8,27 @@ interface OrganizationAddressFormatArgs {
|
|||||||
city?: string;
|
city?: string;
|
||||||
country?: string;
|
country?: string;
|
||||||
postalCode?: string;
|
postalCode?: string;
|
||||||
|
phone?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultMessage = `
|
const defaultMessage = `
|
||||||
<strong>{ORGANIZATION_NAME}</strong>
|
<strong>{ORGANIZATION_NAME}</strong>
|
||||||
{ADDRESS_1},
|
{ADDRESS_1}
|
||||||
{ADDRESS_2},
|
{ADDRESS_2}
|
||||||
{CITY} {STATE},
|
{CITY}, {STATE} {POSTAL_CODE}
|
||||||
{POSTAL_CODE},
|
|
||||||
{COUNTRY}
|
{COUNTRY}
|
||||||
|
{PHONE}
|
||||||
`;
|
`;
|
||||||
|
/**
|
||||||
|
* Formats the address text based on the provided message and arguments.
|
||||||
|
* This function replaces placeholders in the message with actual values
|
||||||
|
* from the OrganizationAddressFormatArgs. It ensures that the final
|
||||||
|
* formatted message is clean and free of excessive newlines.
|
||||||
|
*
|
||||||
|
* @param {string} message - The message template containing placeholders.
|
||||||
|
* @param {Record<string, string>} args - The arguments containing the values to replace in the message.
|
||||||
|
* @returns {string} - The formatted address text.
|
||||||
|
*/
|
||||||
const formatText = (message: string, replacements: Record<string, string>) => {
|
const formatText = (message: string, replacements: Record<string, string>) => {
|
||||||
let formattedMessage = Object.entries(replacements).reduce(
|
let formattedMessage = Object.entries(replacements).reduce(
|
||||||
(msg, [key, value]) => {
|
(msg, [key, value]) => {
|
||||||
@@ -26,9 +36,11 @@ const formatText = (message: string, replacements: Record<string, string>) => {
|
|||||||
},
|
},
|
||||||
message
|
message
|
||||||
);
|
);
|
||||||
|
formattedMessage = formattedMessage.replace(/\n{2,}/g, '\n').trim();
|
||||||
formattedMessage = formattedMessage.replace(/\n/g, '<br />');
|
formattedMessage = formattedMessage.replace(/\n/g, '<br />');
|
||||||
|
formattedMessage = formattedMessage.trim();
|
||||||
|
|
||||||
return formattedMessage.trim();
|
return formattedMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const organizationAddressTextFormat = (
|
export const organizationAddressTextFormat = (
|
||||||
@@ -43,6 +55,7 @@ export const organizationAddressTextFormat = (
|
|||||||
STATE: args.state || '',
|
STATE: args.state || '',
|
||||||
POSTAL_CODE: args.postalCode || '',
|
POSTAL_CODE: args.postalCode || '',
|
||||||
COUNTRY: args.country || '',
|
COUNTRY: args.country || '',
|
||||||
|
PHONE: args.phone || '',
|
||||||
};
|
};
|
||||||
return formatText(message, replacements);
|
return formatText(message, replacements);
|
||||||
};
|
};
|
||||||
@@ -56,15 +69,15 @@ interface ContactAddressTextFormatArgs {
|
|||||||
city?: string;
|
city?: string;
|
||||||
address2?: string;
|
address2?: string;
|
||||||
address1?: string;
|
address1?: string;
|
||||||
|
phone?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const contactFormatMessage = `{CONTACT_NAME}
|
const contactFormatMessage = `{CONTACT_NAME}
|
||||||
{ADDRESS_1}
|
{ADDRESS_1}
|
||||||
{ADDRESS_2}
|
{ADDRESS_2}
|
||||||
{CITY} {STATE}
|
{CITY}, {STATE} {POSTAL_CODE}
|
||||||
{POSTAL_CODE}
|
|
||||||
{COUNTRY}
|
{COUNTRY}
|
||||||
{EMAIL}
|
{PHONE}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const contactAddressTextFormat = (
|
export const contactAddressTextFormat = (
|
||||||
@@ -80,6 +93,7 @@ export const contactAddressTextFormat = (
|
|||||||
postalCode: contact?.billingAddressPostcode,
|
postalCode: contact?.billingAddressPostcode,
|
||||||
city: contact?.billingAddressCity,
|
city: contact?.billingAddressCity,
|
||||||
email: contact?.email,
|
email: contact?.email,
|
||||||
|
phone: contact?.billingAddressPhone,
|
||||||
} as ContactAddressTextFormatArgs;
|
} as ContactAddressTextFormatArgs;
|
||||||
|
|
||||||
const replacements: Record<string, string> = {
|
const replacements: Record<string, string> = {
|
||||||
@@ -91,6 +105,7 @@ export const contactAddressTextFormat = (
|
|||||||
POSTAL_CODE: args.postalCode || '',
|
POSTAL_CODE: args.postalCode || '',
|
||||||
COUNTRY: args.country || '',
|
COUNTRY: args.country || '',
|
||||||
EMAIL: args?.email || '',
|
EMAIL: args?.email || '',
|
||||||
|
PHONE: args?.phone || '',
|
||||||
};
|
};
|
||||||
return formatText(message, replacements);
|
return formatText(message, replacements);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ export const DefaultPdfTemplateItemDescription =
|
|||||||
'Website development with content and SEO optimization';
|
'Website development with content and SEO optimization';
|
||||||
|
|
||||||
export const DefaultPdfTemplateAddressBilledTo = `Bigcapital Technology, Inc.<br />
|
export const DefaultPdfTemplateAddressBilledTo = `Bigcapital Technology, Inc.<br />
|
||||||
131 Continental Dr Suite 305 Newark, <br />
|
131 Continental Dr, <br />
|
||||||
Delaware 19713, <br />
|
Suite 305, <br />
|
||||||
United States, <br />
|
Newark, Delaware 19713, <br />
|
||||||
+1 762-339-5634, <br />
|
United States,<br />
|
||||||
ahmed@bigcapital.app
|
+1 762-339-5634
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const DefaultPdfTemplateAddressBilledFrom = `131 Continental Dr Suite 305 Newark, <br />
|
export const DefaultPdfTemplateAddressBilledFrom = `131 Continental Dr Suite 305 Newark, <br />
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Text, Classes, Button, Intent } from '@blueprintjs/core';
|
import { Text, Classes, Button, Intent, Tag } from '@blueprintjs/core';
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
import { AppToaster, Box, Group, Stack } from '@/components';
|
import { AppToaster, Box, Group, Stack } from '@/components';
|
||||||
import { usePaymentPortalBoot } from './PaymentPortalBoot';
|
import { usePaymentPortalBoot } from './PaymentPortalBoot';
|
||||||
@@ -54,20 +54,25 @@ export function PaymentPortal() {
|
|||||||
{sharableLinkMeta?.organization?.name} Sent an Invoice for{' '}
|
{sharableLinkMeta?.organization?.name} Sent an Invoice for{' '}
|
||||||
{sharableLinkMeta?.totalFormatted}
|
{sharableLinkMeta?.totalFormatted}
|
||||||
</h1>
|
</h1>
|
||||||
<Text className={clsx(Classes.TEXT_MUTED, styles.invoiceDueDate)}>
|
<Group spacing={10}>
|
||||||
Invoice due {sharableLinkMeta?.dueDateFormatted}
|
<Text className={clsx(Classes.TEXT_MUTED, styles.invoiceDueDate)}>
|
||||||
</Text>
|
Invoice due {sharableLinkMeta?.dueDateFormatted}{' '}
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack className={styles.address} spacing={2}>
|
<Stack className={styles.address} spacing={2}>
|
||||||
<Box className={styles.customerName}>
|
<Box className={styles.customerName}>
|
||||||
{sharableLinkMeta?.customerName}
|
{sharableLinkMeta?.customerName}
|
||||||
</Box>
|
</Box>
|
||||||
<Box>Bigcapital Technology, Inc.</Box>
|
|
||||||
<Box>131 Continental Dr Suite 305 Newark,</Box>
|
{sharableLinkMeta?.formattedCustomerAddress && (
|
||||||
<Box>Delaware 19713</Box>
|
<Box
|
||||||
<Box>United States</Box>
|
dangerouslySetInnerHTML={{
|
||||||
<Box>ahmed@bigcapital.app</Box>
|
__html: sharableLinkMeta?.formattedCustomerAddress,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<h2 className={styles.invoiceNumber}>
|
<h2 className={styles.invoiceNumber}>
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ export function PaymentInvoicePreviewContent() {
|
|||||||
label: tax.name,
|
label: tax.name,
|
||||||
amount: tax.taxRateAmountFormatted,
|
amount: tax.taxRateAmountFormatted,
|
||||||
}))}
|
}))}
|
||||||
|
companyAddress={
|
||||||
|
sharableLinkMeta?.organization?.addressTextFormatted
|
||||||
|
}
|
||||||
|
customerAddress={sharableLinkMeta?.formattedCustomerAddress}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</DrawerBody>
|
</DrawerBody>
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ export interface GetInvoicePaymentLinkResponse {
|
|||||||
organization: GetInvoicePaymentLinkOrganizationRes;
|
organization: GetInvoicePaymentLinkOrganizationRes;
|
||||||
hasStripePaymentMethod: boolean;
|
hasStripePaymentMethod: boolean;
|
||||||
isReceivable: boolean;
|
isReceivable: boolean;
|
||||||
|
formattedCustomerAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user