feat: Hook up company address to payment page

This commit is contained in:
Ahmed Bouhuolia
2024-09-28 20:19:05 +02:00
parent e506a7ba35
commit 9b63c176cd
6 changed files with 123 additions and 23 deletions

View File

@@ -45,6 +45,7 @@ export class GetInvoicePaymentLinkMetadata {
.withGraphFetched('entries.item')
.withGraphFetched('customer')
.withGraphFetched('taxes.taxRate')
.withGraphFetched('paymentMethods.paymentIntegration')
.throwIfNotFound();
return this.transformer.transform(

View File

@@ -41,6 +41,8 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
'entries',
'taxes',
'organization',
'isReceivable',
'hasStripePaymentMethod',
];
};
@@ -50,7 +52,7 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
/**
* Retrieves the organization metadata for the payment link.
* @returns
* @returns
*/
public organization(invoice) {
return this.item(
@@ -89,6 +91,16 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
}
);
};
protected isReceivable(invoice) {
return invoice.dueAmount > 0;
}
protected hasStripePaymentMethod(invoice) {
return invoice.paymentMethods.some(
(paymentMethod) => paymentMethod.paymentIntegration.service === 'Stripe'
);
}
}
class GetPaymentLinkOrganizationMetaTransformer extends Transformer {
@@ -97,12 +109,26 @@ class GetPaymentLinkOrganizationMetaTransformer extends Transformer {
* @returns {Array}
*/
public includeAttributes = (): string[] => {
return ['primaryColor', 'name', 'address', 'logoUri'];
return [
'primaryColor',
'name',
'address',
'logoUri',
'addressTextFormatted',
];
};
public excludeAttributes = (): string[] => {
return ['*'];
};
/**
* Retrieves the formatted text of organization address.
* @returns {string}
*/
public addressTextFormatted() {
return this.context.organization.addressTextFormatted;
}
}
class GetInvoicePaymentLinkEntryMetaTransformer extends ItemEntryTransformer {

View File

@@ -1,3 +1,4 @@
import { addressTextFormat } from '@/utils/address-text-format';
import BaseModel from 'models/Model';
export default class TenantMetadata extends BaseModel {
@@ -12,8 +13,11 @@ export default class TenantMetadata extends BaseModel {
fiscalYear!: string;
primaryColor!: string;
logoKey!: string;
address!: object;
address!: Record<string, any>;
/**
* Json schema.
*/
static get jsonSchema() {
return {
type: 'object',
@@ -50,9 +54,35 @@ export default class TenantMetadata extends BaseModel {
}
/**
*
* Organization logo url.
* @returns {string | null}
*/
public get logoUri() {
return this.logoKey ? `https://bigcapital.sfo3.digitaloceanspaces.com/${this.logoKey}` : null;
return this.logoKey
? `https://bigcapital.sfo3.digitaloceanspaces.com/${this.logoKey}`
: null;
}
/**
* Retrieves the organization address formatted text.
* @returns {string}
*/
public get addressTextFormatted() {
const defaultMessage = `<strong>{ORGANIZATION_NAME}</strong>
{ADDRESS_1},
{ADDRESS_2},
{CITY} {STATE},
{POSTAL_CODE},
{COUNTRY}
`;
return addressTextFormat(defaultMessage, {
organizationName: this.name,
address1: this.address?.address1,
address2: this.address?.address2,
state: this.address?.stateProvince,
city: this.address?.city,
postalCode: this.address?.postalCode,
country: 'United State',
});
}
}

View File

@@ -0,0 +1,42 @@
interface OrganizationAddressFormatArgs {
organizationName?: string;
address1?: string;
address2?: string;
state?: string;
city?: string;
country?: string;
postalCode?: string;
}
const defaultMessage = `
<strong>{ORGANIZATION_NAME}</strong>
{ADDRESS_1},
{ADDRESS_2},
{CITY} {STATE},
{POSTAL_CODE},
{COUNTRY}
`;
export const addressTextFormat = (
message: string,
args: OrganizationAddressFormatArgs
) => {
const replacements: Record<string, string> = {
ORGANIZATION_NAME: args.organizationName || '',
ADDRESS_1: args.address1 || '',
ADDRESS_2: args.address2 || '',
CITY: args.city || '',
STATE: args.state || '',
POSTAL_CODE: args.postalCode || '',
COUNTRY: args.country || '',
};
let formattedMessage = Object.entries(replacements).reduce(
(msg, [key, value]) => {
return value ? msg.split(`{${key}}`).join(value) : msg;
},
message
);
formattedMessage = formattedMessage.replace(/\n/g, '<br />');
return formattedMessage.trim();
};

View File

@@ -96,7 +96,6 @@ export function PaymentPortal() {
<Text>{tax?.taxRateAmountFormatted}</Text>
</Group>
))}
<Group
position={'apart'}
className={clsx(styles.totalItem, styles.borderBottomGray)}
@@ -132,14 +131,17 @@ export function PaymentPortal() {
View Invoice
</Button>
<Button
intent={Intent.PRIMARY}
className={clsx(styles.footerButton, styles.buyButton)}
loading={isStripeCheckoutLoading}
onClick={handlePayButtonClick}
>
Pay {sharableLinkMeta?.totalFormatted}
</Button>
{sharableLinkMeta?.isReceivable &&
sharableLinkMeta?.hasStripePaymentMethod && (
<Button
intent={Intent.PRIMARY}
className={clsx(styles.footerButton, styles.buyButton)}
loading={isStripeCheckoutLoading}
onClick={handlePayButtonClick}
>
Pay {sharableLinkMeta?.totalFormatted}
</Button>
)}
</Stack>
<Text className={clsx(Classes.TEXT_MUTED, styles.buyNote)}>
@@ -150,15 +152,11 @@ export function PaymentPortal() {
</Stack>
<Stack spacing={18} className={styles.footer}>
<Stack spacing={0}>
<Box>
<strong>Bigcapital Technology, Inc.</strong>
</Box>
<Box>131 Continental Dr Suite 305 Newark,</Box>
<Box>Delaware 19713</Box>
<Box>United States</Box>
<Box>ahmed@bigcapital.app</Box>
</Stack>
<Box
dangerouslySetInnerHTML={{
__html: sharableLinkMeta?.organization?.addressTextFormatted || '',
}}
></Box>
<Stack spacing={0} className={styles.footerText}>
© 2024 Bigcapital Technology, Inc.

View File

@@ -104,8 +104,11 @@ export interface GetInvoicePaymentLinkResponse {
name: string;
primaryColor: string;
logoUri: string;
addressTextFormatted: string;
}
>;
hasStripePaymentMethod: boolean;
isReceivable: boolean;
}
/**