diff --git a/packages/webapp/src/containers/PaymentPortal/InvoicePaymentPagePreview.tsx b/packages/webapp/src/containers/PaymentPortal/InvoicePaymentPagePreview.tsx index 87532d998..1802db82c 100644 --- a/packages/webapp/src/containers/PaymentPortal/InvoicePaymentPagePreview.tsx +++ b/packages/webapp/src/containers/PaymentPortal/InvoicePaymentPagePreview.tsx @@ -1,6 +1,7 @@ import { InvoicePaymentPage, PaymentPageProps } from './PaymentPage'; -interface InvoicePaymentPagePreviewProps extends Partial { } +export interface InvoicePaymentPagePreviewProps + extends Partial { } export function InvoicePaymentPagePreview( props: InvoicePaymentPagePreviewProps, diff --git a/packages/webapp/src/containers/PaymentPortal/PaymentPage.tsx b/packages/webapp/src/containers/PaymentPortal/PaymentPage.tsx index b642898af..a756d4127 100644 --- a/packages/webapp/src/containers/PaymentPortal/PaymentPage.tsx +++ b/packages/webapp/src/containers/PaymentPortal/PaymentPage.tsx @@ -2,58 +2,117 @@ import { Text, Classes, Button, Intent, ButtonProps } from '@blueprintjs/core'; import clsx from 'classnames'; import { Box, Group, Stack } from '@/components'; import styles from './PaymentPortal.module.scss'; +import { css } from '@emotion/css'; export interface PaymentPageProps { + // # Company name companyLogoUri: string; organizationName: string; + organizationAddress: string; + + // # Colors + primaryColor?: string; + + // # Customer name customerName: string; - subtotal: string; - total: string; - dueDate: string; - viewInvoiceLabel?: string; - invoiceNumber: string; - totalLabel?: string; - subtotalLabel?: string; customerAddress?: string; - downloadInvoiceBtnLabel?: string; - showPayButton?: boolean; + + // # Subtotal + subtotal: string; + subtotalLabel?: string; + + // # Total + total: string; + totalLabel?: string; + + // # Due date + dueDate: string; + + // # Paid amount paidAmount: string; paidAmountLabel?: string; - organizationAddress: string; + + // # Due amount dueAmount: string; dueAmountLabel?: string; + + // # Download invoice button + downloadInvoiceBtnLabel?: string; downloadInvoiceButtonProps?: Partial; - payInvoiceButtonProps?: Partial; + + // # View invoice button + viewInvoiceLabel?: string; viewInvoiceButtonProps?: Partial; + + // # Invoice number + invoiceNumber: string; invoiceNumberLabel?: string; + + // # Pay button + showPayButton?: boolean; + payButtonLabel?: string; + payInvoiceButtonProps?: Partial; + + // # Buy note buyNote?: string; + + // # Copyright copyrightText?: string; } export function InvoicePaymentPage({ + // # Company companyLogoUri, organizationName, + organizationAddress, + + // # Colors + primaryColor, + + // # Customer customerName, + customerAddress, + + // # Subtotal subtotal, + subtotalLabel = 'Subtotal', + + // # Total total, + totalLabel = 'Total', + + // # Due date dueDate, + + // # Paid amount paidAmount, paidAmountLabel = 'Paid Amount (-)', + + // # Invoice number invoiceNumber, - customerAddress, - totalLabel = 'Total', - subtotalLabel = 'Subtotal', - viewInvoiceLabel = 'View Invoice', + invoiceNumberLabel = 'Invoice #', + + // # Download invoice button downloadInvoiceBtnLabel = 'Download Invoice', - showPayButton = true, - organizationAddress, + downloadInvoiceButtonProps, + + // # View invoice button + viewInvoiceLabel = 'View Invoice', + viewInvoiceButtonProps, + + // # Due amount dueAmount, dueAmountLabel = 'Due Amount', - downloadInvoiceButtonProps, + + // # Pay button + showPayButton = true, + payButtonLabel = 'Pay {total}', payInvoiceButtonProps, - viewInvoiceButtonProps, - invoiceNumberLabel = 'Invoice #', + + // # Buy note buyNote = 'By confirming your payment, you allow Bigcapital Technology, Inc. to charge you for this payment and save your payment information in accordance with their terms.', + + // # Copyright copyrightText = `© 2024 Bigcapital Technology, Inc.
All rights reserved.`, }: PaymentPageProps) { return ( @@ -91,7 +150,9 @@ export function InvoicePaymentPage({ )} -

Invoice {invoiceNumber}

+

+ {invoiceNumberLabel} {invoiceNumber} +

- Due Amount + {dueAmountLabel} {dueAmount} @@ -150,10 +211,18 @@ export function InvoicePaymentPage({ {showPayButton && ( )} diff --git a/packages/webapp/src/containers/PaymentPortal/PaymentPortal.module.scss b/packages/webapp/src/containers/PaymentPortal/PaymentPortal.module.scss index a431cfcfe..b33db22db 100644 --- a/packages/webapp/src/containers/PaymentPortal/PaymentPortal.module.scss +++ b/packages/webapp/src/containers/PaymentPortal/PaymentPortal.module.scss @@ -28,6 +28,7 @@ font-weight: 500; color: #222; font-size: 26px; + line-height: 1.35; } .invoiceDueDate{ diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeContent.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeContent.tsx index 270d8025f..479f5ed49 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeContent.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeContent.tsx @@ -1,11 +1,5 @@ -import React, { lazy, Suspense } from 'react'; -import * as R from 'ramda'; -import { useFormikContext } from 'formik'; +import { lazy, Suspense } from 'react'; import { Spinner, Tab } from '@blueprintjs/core'; -import { - InvoicePaperTemplate, - InvoicePaperTemplateProps, -} from './InvoicePaperTemplate'; import { ElementCustomize, ElementCustomizeContent, @@ -17,21 +11,26 @@ import { InvoiceCustomizeSchema } from './InvoiceCustomizeForm.schema'; import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; import { useDrawerActions } from '@/hooks/state'; import { BrandingTemplateForm } from '@/containers/BrandingTemplates/BrandingTemplateForm'; -import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider'; import { initialValues } from './constants'; import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils'; import { InvoiceCustomizeTabs } from './InvoiceCustomizeTabs'; -const InvoicePaymentPagePreview = lazy(() => - import('@/containers/PaymentPortal/InvoicePaymentPagePreview').then( - (module) => ({ default: module.InvoicePaymentPagePreview }), - ), +const InvoiceCustomizePaymentPreview = lazy(() => + import('./InvoiceCustomizePaymentPreview').then((module) => ({ + default: module.InvoiceCustomizePaymentPreview, + })), ); -const InvoiceMailReceiptPreview = lazy(() => - import( - '@/containers/Sales/Invoices/InvoiceCustomize/InvoiceMailReceiptPreview' - ).then((module) => ({ default: module.InvoiceMailReceiptPreview })), +const InvoiceCustomizeMailReceiptPreview = lazy(() => + import('./InvoiceCustomizeMailReceiptPreview').then((module) => ({ + default: module.InvoiceCustomizeMailReceiptPreview, + })), +); + +const InvoiceCustomizePdfPreview = lazy(() => + import('./InvoiceCustomizePdfPreview').then((module) => ({ + default: module.InvoiceCustomizePdfPreview, + })), ); /** @@ -80,7 +79,7 @@ function InvoiceCustomizeFormContent() { title={'PDF document'} panel={ }> - + } /> @@ -89,7 +88,7 @@ function InvoiceCustomizeFormContent() { title={'Payment page'} panel={ }> - + } /> @@ -98,7 +97,7 @@ function InvoiceCustomizeFormContent() { title={'Email receipt'} panel={ }> - + } /> @@ -119,27 +118,3 @@ function InvoiceCustomizeFormContent() { ); } - -/** - * Injects the `InvoicePaperTemplate` component props from the form and branding states. - * @param Component - * @returns {JSX.Element} - */ -const withInvoicePreviewTemplateProps =

( - Component: React.ComponentType

, -) => { - return (props: Omit) => { - const { values } = useFormikContext(); - const { brandingState } = useElementCustomizeContext(); - - const mergedProps: InvoicePaperTemplateProps = { - ...brandingState, - ...values, - }; - return ; - }; -}; - -export const InvoicePaperTemplateFormConnected = R.compose( - withInvoicePreviewTemplateProps, -)(InvoicePaperTemplate); diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx index a6a8d46f2..ea53835ec 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx @@ -1,5 +1,6 @@ // @ts-nocheck import { Classes, Text } from '@blueprintjs/core'; +import { Link } from 'react-router-dom'; import { FFormGroup, FieldRequiredHint, @@ -13,7 +14,6 @@ import { CreditCardIcon } from '@/icons/CreditCardIcon'; import { Overlay } from './Overlay'; import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils'; import { BrandingCompanyLogoUploadField } from '@/containers/ElementCustomize/components/BrandingCompanyLogoUploadField'; -import { Link } from 'react-router-dom'; import { MANAGE_LINK_URL } from './constants'; import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; import { useDrawerActions } from '@/hooks/state'; diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeMailReceiptPreview.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeMailReceiptPreview.tsx new file mode 100644 index 000000000..0e405a6ec --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeMailReceiptPreview.tsx @@ -0,0 +1,30 @@ +import * as R from 'ramda'; +import { InvoicePaymentPagePreviewProps } from '@/containers/PaymentPortal/InvoicePaymentPagePreview'; +import { InvoiceCustomizeFormValues } from './types'; +import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider'; +import { useFormikContext } from 'formik'; +import { InvoiceMailReceiptPreview } from './InvoiceMailReceiptPreview'; + +const withInvoiceMailReceiptPreviewConnected =

( + Component: React.ComponentType

, +) => { + return (props: Omit) => { + const { values } = useFormikContext(); + const { brandingState } = useElementCustomizeContext(); + + const mergedBrandingState = { + ...brandingState, + ...values, + }; + const mergedProps: InvoicePaymentPagePreviewProps = { + companyLogoUri: mergedBrandingState?.companyLogoUri, + primaryColor: mergedBrandingState?.primaryColor, + // organizationAddress: mergedBrandingState, + }; + return ; + }; +}; + +export const InvoiceCustomizeMailReceiptPreview = R.compose( + withInvoiceMailReceiptPreviewConnected, +)(InvoiceMailReceiptPreview); diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizePaymentPreview.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizePaymentPreview.tsx new file mode 100644 index 000000000..df28c18ba --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizePaymentPreview.tsx @@ -0,0 +1,31 @@ +import * as R from 'ramda'; +import { useFormikContext } from 'formik'; +import { + InvoicePaymentPagePreview, + InvoicePaymentPagePreviewProps, +} from '@/containers/PaymentPortal/InvoicePaymentPagePreview'; +import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider'; +import { InvoiceCustomizeFormValues } from './types'; + +const withInvoicePaymentPreviewPageProps =

( + Component: React.ComponentType

, +) => { + return (props: Omit) => { + const { values } = useFormikContext(); + const { brandingState } = useElementCustomizeContext(); + + const mergedBrandingState = { + ...brandingState, + ...values, + }; + const mergedProps: InvoicePaymentPagePreviewProps = { + companyLogoUri: mergedBrandingState?.companyLogoUri, + primaryColor: mergedBrandingState?.primaryColor, + }; + return ; + }; +}; + +export const InvoiceCustomizePaymentPreview = R.compose( + withInvoicePaymentPreviewPageProps, +)(InvoicePaymentPagePreview); diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizePdfPreview.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizePdfPreview.tsx new file mode 100644 index 000000000..38e8b6c1b --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizePdfPreview.tsx @@ -0,0 +1,32 @@ +import * as R from 'ramda'; +import { useFormikContext } from 'formik'; +import { + InvoicePaperTemplate, + InvoicePaperTemplateProps, +} from './InvoicePaperTemplate'; +import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider'; +import { InvoiceCustomizeFormValues } from './types'; + +/** + * Injects the `InvoicePaperTemplate` component props from the form and branding states. + * @param Component + * @returns {JSX.Element} + */ +const withInvoicePreviewTemplateProps =

( + Component: React.ComponentType

, +) => { + return (props: Omit) => { + const { values } = useFormikContext(); + const { brandingState } = useElementCustomizeContext(); + + const mergedProps: InvoicePaperTemplateProps = { + ...brandingState, + ...values, + }; + return ; + }; +}; + +export const InvoiceCustomizePdfPreview = R.compose( + withInvoicePreviewTemplateProps, +)(InvoicePaperTemplate); diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceMailReceipt.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceMailReceipt.tsx index 2c1c91a51..943bc493a 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceMailReceipt.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceMailReceipt.tsx @@ -4,35 +4,75 @@ import { x } from '@xstyled/emotion'; import { Group, Stack, StackProps } from '@/components'; export interface InvoiceMailReceiptProps extends StackProps { - companyLogoUri?: string; - message: string; + // # Company companyName: string; - invoiceNumber: string; + companyLogoUri?: string; + + // # Colors + primaryColor?: string, + + // # Due date dueDate: string; - items?: Array<{ label: string; total: string; quantity: string | number }>; - total: string; - dueAmount: string; - totalLabel?: string; + dueDateLabel?: string; + + // # Due amount dueAmountLabel?: string; + dueAmount: string; + + // # Total + total: string; + totalLabel?: string; + + // # Invoice number + invoiceNumber: string; + invoiceNumberLabel?: string; + + // # Mail message + message: string; + + // # Invoice items + items?: Array<{ label: string; total: string; quantity: string | number }>; + + // # View invoice button + showViewInvoiceButton?: boolean; viewInvoiceButtonLabel?: string; viewInvoiceButtonOnClick?: () => void; - invoiceNumberLabel?: string; } export function InvoiceMailReceipt({ - companyLogoUri, - message, + // Company companyName, - total, - invoiceNumber, + companyLogoUri, + + // # Colors + primaryColor, + + // Due date dueDate, + dueDateLabel = 'Due', + + // Due amount + dueAmountLabel = 'Due Amount', dueAmount, + + // Total + total, + totalLabel = 'Total', + + // Invoice number + invoiceNumber, + invoiceNumberLabel = 'Invoice #', + + // Invoice message + message, + + // Invoice items items, + + // View invoice button + showViewInvoiceButton = true, viewInvoiceButtonLabel = 'View Invoice', viewInvoiceButtonOnClick, - totalLabel = 'Total', - dueAmountLabel = 'Due Amount', - invoiceNumberLabel = 'Invoice #', ...restProps }: InvoiceMailReceiptProps) { return ( @@ -48,7 +88,15 @@ export function InvoiceMailReceipt({ > {companyLogoUri && ( - + )} @@ -64,7 +112,7 @@ export function InvoiceMailReceipt({ - Due {dueDate} + {dueDateLabel} {dueDate} @@ -73,18 +121,23 @@ export function InvoiceMailReceipt({ {message} - + {showViewInvoiceButton && ( + + )} {items?.map((item, key) => (