mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 15:20:34 +00:00
feat: estimate mail receipt
This commit is contained in:
12
packages/server/newrelic_agent.log
Normal file
12
packages/server/newrelic_agent.log
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":5186,"time":"2024-11-18T22:14:20.534Z","msg":"Unable to find configuration file. If a configuration file is desired (common for non-containerized environments), a base configuration file can be copied from /Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/newrelic.js and renamed to \"newrelic.js\" in the directory from which you will start your application. Attempting to start agent using environment variables."}
|
||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":5186,"time":"2024-11-18T22:14:20.542Z","msg":"Using New Relic for Node.js. Agent version: 11.17.0; Node version: v18.18.2."}
|
||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":5186,"time":"2024-11-18T22:14:20.878Z","msg":"Using AsyncLocalContextManager"}
|
||||||
|
{"v":0,"level":50,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":5186,"time":"2024-11-18T22:14:20.881Z","msg":"New Relic for Node.js was unable to bootstrap itself due to an error:","stack":"Error: New Relic requires that you name this application!\nSet app_name in your newrelic.js or newrelic.cjs file or set environment variable\nNEW_RELIC_APP_NAME. Not starting!\n at createAgent (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:160:11)\n at initialize (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:105:15)\n at Object.<anonymous> (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:39:3)\n at Module._compile (node:internal/modules/cjs/loader:1256:14)\n at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)\n at Module.load (node:internal/modules/cjs/loader:1119:32)\n at Module._load (node:internal/modules/cjs/loader:960:12)\n at Module.require (node:internal/modules/cjs/loader:1143:19)\n at require (node:internal/modules/cjs/helpers:119:18)\n at Object.newrelic (/Users/ahmedbouhuolia/repos/bigcapital/packages/server/build/index.js:49240:18)","message":"New Relic requires that you name this application!\nSet app_name in your newrelic.js or newrelic.cjs file or set environment variable\nNEW_RELIC_APP_NAME. Not starting!"}
|
||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":36447,"time":"2024-11-19T14:46:43.059Z","msg":"Unable to find configuration file. If a configuration file is desired (common for non-containerized environments), a base configuration file can be copied from /Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/newrelic.js and renamed to \"newrelic.js\" in the directory from which you will start your application. Attempting to start agent using environment variables."}
|
||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":36447,"time":"2024-11-19T14:46:43.068Z","msg":"Using New Relic for Node.js. Agent version: 11.17.0; Node version: v18.18.2."}
|
||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":36447,"time":"2024-11-19T14:46:43.304Z","msg":"Using AsyncLocalContextManager"}
|
||||||
|
{"v":0,"level":50,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":36447,"time":"2024-11-19T14:46:43.306Z","msg":"New Relic for Node.js was unable to bootstrap itself due to an error:","stack":"Error: New Relic requires that you name this application!\nSet app_name in your newrelic.js or newrelic.cjs file or set environment variable\nNEW_RELIC_APP_NAME. Not starting!\n at createAgent (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:160:11)\n at initialize (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:105:15)\n at Object.<anonymous> (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:39:3)\n at Module._compile (node:internal/modules/cjs/loader:1256:14)\n at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)\n at Module.load (node:internal/modules/cjs/loader:1119:32)\n at Module._load (node:internal/modules/cjs/loader:960:12)\n at Module.require (node:internal/modules/cjs/loader:1143:19)\n at require (node:internal/modules/cjs/helpers:119:18)\n at Object.newrelic (/Users/ahmedbouhuolia/repos/bigcapital/packages/server/build/index.js:49240:18)","message":"New Relic requires that you name this application!\nSet app_name in your newrelic.js or newrelic.cjs file or set environment variable\nNEW_RELIC_APP_NAME. Not starting!"}
|
||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":60390,"time":"2024-11-19T19:55:31.373Z","msg":"Unable to find configuration file. If a configuration file is desired (common for non-containerized environments), a base configuration file can be copied from /Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/newrelic.js and renamed to \"newrelic.js\" in the directory from which you will start your application. Attempting to start agent using environment variables."}
|
||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":60390,"time":"2024-11-19T19:55:31.382Z","msg":"Using New Relic for Node.js. Agent version: 11.17.0; Node version: v18.18.2."}
|
||||||
|
{"v":0,"level":30,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":60390,"time":"2024-11-19T19:55:31.682Z","msg":"Using AsyncLocalContextManager"}
|
||||||
|
{"v":0,"level":50,"name":"newrelic","hostname":"Ahmeds-MacBook-Air.local","pid":60390,"time":"2024-11-19T19:55:31.683Z","msg":"New Relic for Node.js was unable to bootstrap itself due to an error:","stack":"Error: New Relic requires that you name this application!\nSet app_name in your newrelic.js or newrelic.cjs file or set environment variable\nNEW_RELIC_APP_NAME. Not starting!\n at createAgent (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:160:11)\n at initialize (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:105:15)\n at Object.<anonymous> (/Users/ahmedbouhuolia/repos/bigcapital/node_modules/.pnpm/newrelic@11.17.0/node_modules/newrelic/index.js:39:3)\n at Module._compile (node:internal/modules/cjs/loader:1256:14)\n at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)\n at Module.load (node:internal/modules/cjs/loader:1119:32)\n at Module._load (node:internal/modules/cjs/loader:960:12)\n at Module.require (node:internal/modules/cjs/loader:1143:19)\n at require (node:internal/modules/cjs/helpers:119:18)\n at Object.newrelic (/Users/ahmedbouhuolia/repos/bigcapital/packages/server/build/index.js:49240:18)","message":"New Relic requires that you name this application!\nSet app_name in your newrelic.js or newrelic.cjs file or set environment variable\nNEW_RELIC_APP_NAME. Not starting!"}
|
||||||
@@ -2,6 +2,7 @@ import { Suspense } from 'react';
|
|||||||
import { SendMailViewPreviewTabs } from '../SendMailViewDrawer/SendMailViewPreviewTabs';
|
import { SendMailViewPreviewTabs } from '../SendMailViewDrawer/SendMailViewPreviewTabs';
|
||||||
import { Tab } from '@blueprintjs/core';
|
import { Tab } from '@blueprintjs/core';
|
||||||
import { EstimateSendPdfPreviewConnected } from './EstimateSendPdfPreviewConnected';
|
import { EstimateSendPdfPreviewConnected } from './EstimateSendPdfPreviewConnected';
|
||||||
|
import { EstimateSendMailReceiptPreview } from './EstimateSendMailReceiptPreview';
|
||||||
|
|
||||||
export function EstimateSendMailPreviewTabs() {
|
export function EstimateSendMailPreviewTabs() {
|
||||||
return (
|
return (
|
||||||
@@ -10,7 +11,9 @@ export function EstimateSendMailPreviewTabs() {
|
|||||||
id={'payment-page'}
|
id={'payment-page'}
|
||||||
title={'Payment page'}
|
title={'Payment page'}
|
||||||
panel={
|
panel={
|
||||||
<Suspense>{/* <InvoiceMailReceiptPreviewConnected /> */}</Suspense>
|
<Suspense>
|
||||||
|
<EstimateSendMailReceiptPreview />
|
||||||
|
</Suspense>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import { x } from '@xstyled/emotion';
|
||||||
|
import { Group, Stack } from '@/components';
|
||||||
|
import { SendMailReceipt, SendMailReceiptProps } from '../SendMailViewDrawer/SendMailViewReceiptPreview';
|
||||||
|
|
||||||
|
interface EstimateSendMailReceiptProps extends SendMailReceiptProps {
|
||||||
|
// # Company name.
|
||||||
|
companyLogoUri?: string;
|
||||||
|
companyName: string;
|
||||||
|
|
||||||
|
// # Estimate number.
|
||||||
|
estimateNumberLabel?: string;
|
||||||
|
estimateNumber: string;
|
||||||
|
|
||||||
|
// # Total.
|
||||||
|
total: string;
|
||||||
|
totalLabel?: string;
|
||||||
|
|
||||||
|
// # Expiration date.
|
||||||
|
expirationDateLabel?: string;
|
||||||
|
expirationDate: string;
|
||||||
|
|
||||||
|
// # Message.
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
// # Estimate items.
|
||||||
|
items?: Array<{ label: string; total: string; quantity: string | number }>;
|
||||||
|
|
||||||
|
// # Subtotal
|
||||||
|
subtotalLabel?: string;
|
||||||
|
subtotal: string;
|
||||||
|
|
||||||
|
// # View estimate button
|
||||||
|
showViewEstimateButton?: boolean;
|
||||||
|
viewEstimateButtonLabel?: string;
|
||||||
|
viewEstimateButtonOnClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EstimateSendMailReceipt({
|
||||||
|
// # Company name.
|
||||||
|
companyLogoUri,
|
||||||
|
companyName,
|
||||||
|
|
||||||
|
// # Estimate number.
|
||||||
|
estimateNumberLabel = 'Estimate #',
|
||||||
|
estimateNumber,
|
||||||
|
|
||||||
|
// # Total.
|
||||||
|
total,
|
||||||
|
totalLabel = 'Total',
|
||||||
|
|
||||||
|
// # Expiration date.
|
||||||
|
expirationDateLabel = 'Expiration Date',
|
||||||
|
expirationDate,
|
||||||
|
|
||||||
|
// # Message
|
||||||
|
message,
|
||||||
|
|
||||||
|
// # Items
|
||||||
|
items,
|
||||||
|
|
||||||
|
// # Subtotal
|
||||||
|
subtotal,
|
||||||
|
subtotalLabel = 'Subtotal',
|
||||||
|
|
||||||
|
// # View estimate button
|
||||||
|
showViewEstimateButton = true,
|
||||||
|
viewEstimateButtonLabel = 'View Estimate',
|
||||||
|
viewEstimateButtonOnClick,
|
||||||
|
|
||||||
|
...props
|
||||||
|
}: EstimateSendMailReceiptProps) {
|
||||||
|
return (
|
||||||
|
<SendMailReceipt {...props}>
|
||||||
|
<Stack spacing={16} textAlign={'center'}>
|
||||||
|
{companyLogoUri && <SendMailReceipt.CompanyLogo src={companyLogoUri} />}
|
||||||
|
|
||||||
|
<Stack spacing={8}>
|
||||||
|
<x.h1 m={0} fontSize={'18px'} fontWeight={500} color="#404854">
|
||||||
|
{companyName}
|
||||||
|
</x.h1>
|
||||||
|
|
||||||
|
<x.h3 color="#383E47" fontWeight={500}>
|
||||||
|
{total}
|
||||||
|
</x.h3>
|
||||||
|
|
||||||
|
<x.span fontSize={'13px'} color="#404854">
|
||||||
|
{estimateNumberLabel} {estimateNumber}
|
||||||
|
</x.span>
|
||||||
|
|
||||||
|
<x.span fontSize={'13px'} color="#404854">
|
||||||
|
{expirationDateLabel} {expirationDate}
|
||||||
|
</x.span>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<x.p m={0} whiteSpace={'pre-line'} color="#252A31">
|
||||||
|
{message}
|
||||||
|
</x.p>
|
||||||
|
|
||||||
|
{showViewEstimateButton && (
|
||||||
|
<SendMailReceipt.PrimaryButton
|
||||||
|
primaryColor={'#000'}
|
||||||
|
onClick={viewEstimateButtonOnClick}
|
||||||
|
>
|
||||||
|
{viewEstimateButtonLabel}
|
||||||
|
</SendMailReceipt.PrimaryButton>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Stack spacing={0}>
|
||||||
|
{items?.map((item, key) => (
|
||||||
|
<Group
|
||||||
|
key={key}
|
||||||
|
h={'40px'}
|
||||||
|
position={'apart'}
|
||||||
|
borderBottomStyle="solid"
|
||||||
|
borderBottomWidth={'1px'}
|
||||||
|
borderBottomColor={'#D9D9D9'}
|
||||||
|
borderTopStyle="solid"
|
||||||
|
borderTopColor={'#D9D9D9'}
|
||||||
|
borderTopWidth={'1px'}
|
||||||
|
>
|
||||||
|
<x.span>{item.label}</x.span>
|
||||||
|
<x.span>
|
||||||
|
{item.quantity} x {item.total}
|
||||||
|
</x.span>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<Group
|
||||||
|
h={'40px'}
|
||||||
|
position={'apart'}
|
||||||
|
borderBottomStyle="solid"
|
||||||
|
borderBottomWidth={'1px'}
|
||||||
|
borderBottomColor={'#000'}
|
||||||
|
>
|
||||||
|
<x.span fontWeight={500}>{subtotalLabel}</x.span>
|
||||||
|
<x.span fontWeight={600} fontSize={15}>
|
||||||
|
{subtotal}
|
||||||
|
</x.span>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Group
|
||||||
|
h={'40px'}
|
||||||
|
position={'apart'}
|
||||||
|
borderBottomStyle="solid"
|
||||||
|
borderBottomWidth={'1px'}
|
||||||
|
borderColor={'#000'}
|
||||||
|
>
|
||||||
|
<x.span fontWeight={500}>{totalLabel}</x.span>
|
||||||
|
<x.span fontWeight={600} fontSize={15}>
|
||||||
|
{total}
|
||||||
|
</x.span>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</SendMailReceipt>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { EstimateSendMailReceipt } from './EstimateSendMailReceipt';
|
||||||
|
import { EstimateSendMailPreviewHeader } from './EstimateSendMailPreviewHeader';
|
||||||
|
import { Stack } from '@/components';
|
||||||
|
|
||||||
|
export const EstimateSendMailReceiptPreview = () => {
|
||||||
|
const props = {
|
||||||
|
companyName: 'Bigcapital Technology, Inc.',
|
||||||
|
companyLogoUri: ' ',
|
||||||
|
|
||||||
|
message: '',
|
||||||
|
total: '$1,000.00',
|
||||||
|
subtotal: '$1,000.00',
|
||||||
|
estimateNumber: 'INV-0001',
|
||||||
|
expirationDate: '2 Oct 2024',
|
||||||
|
dueAmount: '$1,000.00',
|
||||||
|
items: [{ label: 'Web development', total: '$1000.00', quantity: 1 }],
|
||||||
|
message: `Hi Ahmed Bouhuolia,
|
||||||
|
|
||||||
|
Here's invoice # INV-00002 for $738.30
|
||||||
|
|
||||||
|
The amount outstanding of $737.30 is due on 01 Feb 2023.
|
||||||
|
|
||||||
|
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,
|
||||||
|
Bigcapital`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack>
|
||||||
|
<EstimateSendMailPreviewHeader />
|
||||||
|
|
||||||
|
<Stack px={4} py={6}>
|
||||||
|
<EstimateSendMailReceipt
|
||||||
|
{...props}
|
||||||
|
className={css`
|
||||||
|
margin: 0 auto;
|
||||||
|
border-radius: 5px !important;
|
||||||
|
transform: scale(0.9);
|
||||||
|
transform-origin: top;
|
||||||
|
boxshadow: 0 10px 15px rgba(0, 0, 0, 0.05) !important;
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -24,7 +24,6 @@ function EstimateSendPdfPreviewIframe() {
|
|||||||
if (isLoading && data) {
|
if (isLoading && data) {
|
||||||
return <Spinner size={20} />;
|
return <Spinner size={20} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const iframeSrcDoc = data?.htmlContent;
|
const iframeSrcDoc = data?.htmlContent;
|
||||||
|
|
||||||
return <SendMailViewPreviewPdfIframe srcDoc={iframeSrcDoc} />;
|
return <SendMailViewPreviewPdfIframe srcDoc={iframeSrcDoc} />;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
import { Button, ButtonProps, Intent } from '@blueprintjs/core';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { lighten } from 'polished';
|
||||||
import { x } from '@xstyled/emotion';
|
import { x } from '@xstyled/emotion';
|
||||||
import { Stack, StackProps } from '@/components';
|
import { Stack, StackProps } from '@/components';
|
||||||
|
|
||||||
interface SendMailReceiptProps extends StackProps {
|
export type SendMailReceiptProps = StackProps;
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SendMailReceipt({
|
export function SendMailReceipt({
|
||||||
children,
|
|
||||||
...restProps
|
...restProps
|
||||||
}: SendMailReceiptProps) {
|
}: SendMailReceiptProps) {
|
||||||
return (
|
return (
|
||||||
@@ -19,7 +19,7 @@ export function SendMailReceipt({
|
|||||||
boxShadow={'0 10px 15px rgba(0, 0, 0, 0.05)'}
|
boxShadow={'0 10px 15px rgba(0, 0, 0, 0.05)'}
|
||||||
color={'black'}
|
color={'black'}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
></Stack>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,4 +46,36 @@ function SendMailReceiptCompanyLogo({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SendMailReceiptTitleProps extends ButtonProps {
|
||||||
|
primaryColor?: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SendMailReceiptPrimaryButton({
|
||||||
|
primaryColor,
|
||||||
|
...props
|
||||||
|
}: SendMailReceiptTitleProps) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
large
|
||||||
|
intent={Intent.PRIMARY}
|
||||||
|
className={css`
|
||||||
|
&.bp4-intent-primary {
|
||||||
|
background-color: ${primaryColor};
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background-color: ${lighten(0.1, primaryColor || '#000')};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.bp4-large {
|
||||||
|
min-height: 38px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SendMailReceipt.PrimaryButton = SendMailReceiptPrimaryButton;
|
||||||
SendMailReceipt.CompanyLogo = SendMailReceiptCompanyLogo;
|
SendMailReceipt.CompanyLogo = SendMailReceiptCompanyLogo;
|
||||||
|
|||||||
@@ -41,36 +41,36 @@ export interface InvoiceMailReceiptProps extends StackProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function InvoiceMailReceipt({
|
export function InvoiceMailReceipt({
|
||||||
// Company
|
// # Company
|
||||||
companyName,
|
companyName,
|
||||||
companyLogoUri,
|
companyLogoUri,
|
||||||
|
|
||||||
// # Colors
|
// # Colors
|
||||||
primaryColor = 'rgb(0, 82, 204)',
|
primaryColor = 'rgb(0, 82, 204)',
|
||||||
|
|
||||||
// Due date
|
// # Due date
|
||||||
dueDate,
|
dueDate,
|
||||||
dueDateLabel = 'Due',
|
dueDateLabel = 'Due',
|
||||||
|
|
||||||
// Due amount
|
// # Due amount
|
||||||
dueAmountLabel = 'Due Amount',
|
dueAmountLabel = 'Due Amount',
|
||||||
dueAmount,
|
dueAmount,
|
||||||
|
|
||||||
// Total
|
// # Total
|
||||||
total,
|
total,
|
||||||
totalLabel = 'Total',
|
totalLabel = 'Total',
|
||||||
|
|
||||||
// Invoice number
|
// # Invoice number
|
||||||
invoiceNumber,
|
invoiceNumber,
|
||||||
invoiceNumberLabel = 'Invoice #',
|
invoiceNumberLabel = 'Invoice #',
|
||||||
|
|
||||||
// Invoice message
|
// # Invoice message
|
||||||
message,
|
message,
|
||||||
|
|
||||||
// Invoice items
|
// # Invoice items
|
||||||
items,
|
items,
|
||||||
|
|
||||||
// View invoice button
|
// # View invoice button
|
||||||
showViewInvoiceButton = true,
|
showViewInvoiceButton = true,
|
||||||
viewInvoiceButtonLabel = 'View Invoice',
|
viewInvoiceButtonLabel = 'View Invoice',
|
||||||
viewInvoiceButtonOnClick,
|
viewInvoiceButtonOnClick,
|
||||||
|
|||||||
Reference in New Issue
Block a user