diff --git a/packages/webapp/src/components/Forms/ColorInput.tsx b/packages/webapp/src/components/Forms/ColorInput.tsx index e986e0892..d06f2fdc8 100644 --- a/packages/webapp/src/components/Forms/ColorInput.tsx +++ b/packages/webapp/src/components/Forms/ColorInput.tsx @@ -11,6 +11,7 @@ import { import { HexColorPicker } from 'react-colorful'; import { useUncontrolled } from '@/hooks/useUncontrolled'; import { Box, BoxProps } from '@/components'; +import { sanitizeToHexColor } from '@/utils/sanitize-hex-color'; import styles from './ColorInput.module.scss'; export interface ColorInputProps { @@ -72,6 +73,10 @@ export function ColorInput({ /> } + onChange={(e) => { + const value = sanitizeToHexColor(e.currentTarget.value); + handleChange(value); + }} {...inputProps} className={clsx(styles.field, inputProps?.className)} /> diff --git a/packages/webapp/src/containers/ElementCustomize/ElementCustomize.tsx b/packages/webapp/src/containers/ElementCustomize/ElementCustomize.tsx index 2ba5e0998..8c55d16bc 100644 --- a/packages/webapp/src/containers/ElementCustomize/ElementCustomize.tsx +++ b/packages/webapp/src/containers/ElementCustomize/ElementCustomize.tsx @@ -56,7 +56,7 @@ export interface ElementCustomizePaperTemplateProps { ElementCustomize.PaperTemplate = ({ children, }: ElementCustomizePaperTemplateProps) => { - return {children}; + return <>{children}; }; export interface ElementCustomizeContentProps { @@ -70,5 +70,5 @@ ElementCustomize.FieldsTab = ({ label, children, }: ElementCustomizeContentProps) => { - return {children}; + return <>{children}; }; diff --git a/packages/webapp/src/containers/ElementCustomize/ElementCustomizeFields.tsx b/packages/webapp/src/containers/ElementCustomize/ElementCustomizeFields.tsx index b55132c74..25294d3b1 100644 --- a/packages/webapp/src/containers/ElementCustomize/ElementCustomizeFields.tsx +++ b/packages/webapp/src/containers/ElementCustomize/ElementCustomizeFields.tsx @@ -3,7 +3,7 @@ import React from 'react'; import * as R from 'ramda'; import { Button, Intent } from '@blueprintjs/core'; import { useFormikContext } from 'formik'; -import { Group, Stack } from '@/components'; +import { Box, Group, Stack } from '@/components'; import { ElementCustomizeHeader } from './ElementCustomizeHeader'; import { ElementCustomizeTabs } from './ElementCustomizeTabs'; import { useElementCustomizeTabsController } from './ElementCustomizeTabsController'; @@ -14,7 +14,7 @@ import styles from './ElementCustomize.module.scss'; export function ElementCustomizeFields() { return ( - + @@ -38,7 +38,7 @@ export function ElementCustomizeFieldsMain() { - {CustomizeTabPanel} + {CustomizeTabPanel} diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomize.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomize.tsx index d84fb170b..3eefb60f6 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomize.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomize.tsx @@ -5,45 +5,18 @@ import { InvoicePaperTemplate } from './InvoicePaperTemplate'; import { ElementCustomize } from '../../../ElementCustomize/ElementCustomize'; import { InvoiceCustomizeGeneralField } from './InvoiceCustomizeGeneralFields'; import { InvoiceCustomizeContentFields } from './InvoiceCutomizeContentFields'; - -interface InvoiceCustomizeValues { - invoiceNumber?: string; - invoiceNumberLabel?: string; - - dateIssue?: string; - dateIssueLabel?: string; - - dueDate?: string; - dueDateLabel?: string; - - companyName?: string; - - bigtitle?: string; - - itemRateLabel?: string; - itemQuantityLabel?: string; - itemTotalLabel?: string; - - // Totals - showDueAmount?: boolean; - showDiscount?: boolean; - showPaymentMade?: boolean; - showTaxes?: boolean; - showSubtotal?: boolean; - showTotal?: boolean; - showBalanceDue?: boolean; - - paymentMadeLabel?: string; - discountLabel?: string; - subtotalLabel?: string; - totalLabel?: string; - balanceDueLabel?: string; -} +import { InvoiceCustomizeValues } from './types'; +import { initialValues } from './constants'; export default function InvoiceCustomizeContent() { + const handleFormSubmit = (values: InvoiceCustomizeValues) => {}; + return ( - > + + initialValues={initialValues} + onSubmit={handleFormSubmit} + > diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx index 2636deb1e..43397bd64 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx @@ -20,33 +20,38 @@ export function InvoiceCustomizeGeneralField() { - + diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCutomizeContentFields.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCutomizeContentFields.tsx index 29ca74c3e..fd1188d20 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCutomizeContentFields.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCutomizeContentFields.tsx @@ -1,35 +1,44 @@ -import { Classes } from '@blueprintjs/core'; +// @ts-nocheck import { FInputGroup, FSwitch, Group, Stack } from '@/components'; - -const items = [ - { key: 'dueAmount', label: 'Due Amount' }, - { key: 'billedTo', label: 'Billed To' }, - { key: 'balanceDue', label: 'Balance Due' }, - { key: 'termsConditions', label: 'Terms & Conditions' }, -]; +import { CLASSES } from '@/constants'; +import { Classes } from '@blueprintjs/core'; +import { fieldsGroups } from './constants'; export function InvoiceCustomizeContentFields() { return ( - - -

General Branding

+ + +

General Branding

Set your invoice details to be automatically applied every time
you create a new invoice.

-

Header

- - {items.map((item, index) => ( - - - - + {fieldsGroups.map((group) => ( + <> +

+ {group.label} +

+ + {group.fields.map((item, index) => ( + + + {item.labelKey && ( + + )} + + ))} + + ))}
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoicePaperTemplate.module.scss b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoicePaperTemplate.module.scss index b042dd270..9cc71dcb1 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoicePaperTemplate.module.scss +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoicePaperTemplate.module.scss @@ -3,7 +3,7 @@ border-radius: 5px; background-color: #fff; color: #111; - box-shadow: inset 0 4px 0px 0 #002762, 0 10px 15px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color), 0 10px 15px rgba(0, 0, 0, 0.05); padding: 24px 30px; font-size: 12px; position: relative; diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoicePaperTemplate.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoicePaperTemplate.tsx index 84c213627..7fb69d58b 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoicePaperTemplate.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoicePaperTemplate.tsx @@ -1,60 +1,127 @@ import clsx from 'classnames'; +import * as R from 'ramda'; +import { useFormikContext } from 'formik'; import styles from './InvoicePaperTemplate.module.scss'; +interface PapaerLine { + item?: string; + description?: string; + quantity?: string; + rate?: string; + total?: string; +} + +interface PaperTax { + label: string; + amount: string; +} + interface PaperTemplateProps { + primaryColor?: string; + secondaryColor?: string; + + showCompanyLogo?: boolean; + companyLogo?: string; + + showInvoiceNumber?: boolean; invoiceNumber?: string; invoiceNumberLabel?: string; + showDateIssue?: boolean; dateIssue?: string; dateIssueLabel?: string; + showDueDate?: boolean; dueDate?: string; dueDateLabel?: string; companyName?: string; - bigtitle?: string; - itemRateLabel?: string; - itemQuantityLabel?: string; - itemTotalLabel?: string; + // Address + showBillingToAddress?: boolean; + showBilledFromAddress?: boolean; + billedToLabel?: string; + + // Entries + lineItemLabel?: string; + lineDescriptionLabel?: string; + lineRateLabel?: string; + lineTotalLabel?: string; // Totals - showDueAmount?: boolean; - showDiscount?: boolean; - showPaymentMade?: boolean; - showTaxes?: boolean; - showSubtotal?: boolean; showTotal?: boolean; - showBalanceDue?: boolean; - - paymentMadeLabel?: string; - discountLabel?: string; - subtotalLabel?: string; totalLabel?: string; + total?: string; + + showDiscount?: boolean; + discountLabel?: string; + discount?: string; + + showSubtotal?: boolean; + subtotalLabel?: string; + subtotal?: string; + + showPaymentMade?: boolean; + paymentMadeLabel?: string; + paymentMade?: string; + + showTaxes?: boolean; + + showDueAmount?: boolean; + showBalanceDue?: boolean; balanceDueLabel?: string; + balanceDue?: string; + + // Footer + termsConditionsLabel: string; + showTermsConditions: boolean; + termsConditions: string; + + statementLabel: string; + showStatement: boolean; + statement: string; + + lines?: Array; + taxes?: Array; + + billedFromAddres?: Array; + billedToAddress?: Array; } -export function InvoicePaperTemplate({ - bigtitle = 'Invoice', +function InvoicePaperTemplateRoot({ + primaryColor, + secondaryColor, + bigtitle = 'Invoice', companyName = 'Bigcapital Technology, Inc.', - // dueDateLabel, + + showCompanyLogo = true, + companyLogo, dueDate = 'September 3, 2024', dueDateLabel = 'Date due', + showDueDate, dateIssue = 'September 3, 2024', dateIssueLabel = 'Date of issue', + showDateIssue, // dateIssue, invoiceNumberLabel = 'Invoice number', invoiceNumber = '346D3D40-0001', + showInvoiceNumber, + + // Address + showBillingToAddress = true, + showBilledFromAddress = true, + billedToLabel = 'Billed To', // Entries - itemQuantityLabel = 'Quantity', - itemRateLabel = 'Rate', - itemTotalLabel = 'Total', + lineItemLabel = 'Item', + lineDescriptionLabel = 'Description', + lineRateLabel = 'Rate', + lineTotalLabel = 'Total', totalLabel = 'Total', subtotalLabel = 'Subtotal', @@ -70,82 +137,127 @@ export function InvoicePaperTemplate({ showPaymentMade = true, showDueAmount = true, showBalanceDue = true, + + total = '$662.75', + subtotal = '630.00', + discount = '0.00', + paymentMade = '100.00', + balanceDue = '$562.75', + + // Footer paragraphs. + termsConditionsLabel = 'Terms & Conditions', + showTermsConditions = true, + termsConditions = 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.', + + lines = [ + { + item: 'Simply dummy text', + description: 'Simply dummy text of the printing and typesetting', + rate: '1', + quantity: '1000', + total: '$1000.00', + }, + ], + taxes = [ + { label: 'Sample Tax1 (4.70%)', amount: '11.75' }, + { label: 'Sample Tax2 (7.00%)', amount: '21.74' }, + ], + + statementLabel = 'Statement', + showStatement = true, + statement = 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.', + billedToAddress = [ + 'Bigcapital Technology, Inc.', + '131 Continental Dr Suite 305 Newark,', + 'Delaware 19713', + 'United States', + '+1 762-339-5634', + 'ahmed@bigcapital.app', + ], + billedFromAddres = [ + '131 Continental Dr Suite 305 Newark,', + 'Delaware 19713', + 'United States', + '+1 762-339-5634', + 'ahmed@bigcapital.app', + ], }: PaperTemplateProps) { return (
+ +

{bigtitle}

-
- -
+ + {showCompanyLogo && ( +
+ +
+ )}
-
-
{invoiceNumberLabel}
-
{invoiceNumber}
-
- -
-
{dateIssueLabel}
-
{dateIssue}
-
- -
-
{dueDateLabel}
-
{dueDate}
-
+ {showInvoiceNumber && ( +
+
{invoiceNumberLabel}
+
{invoiceNumber}
+
+ )} + {showDateIssue && ( +
+
{dateIssueLabel}
+
{dateIssue}
+
+ )} + {showDueDate && ( +
+
{dueDateLabel}
+
{dueDate}
+
+ )}
-
- {companyName}
- 131 Continental Dr Suite 305 Newark, -
- Delaware 19713 -
- United States -
- +1 762-339-5634 -
- ahmed@bigcapital.app -
+ {showBilledFromAddress && ( +
+ {companyName}
+ {billedFromAddres.map((text, index) => ( +
{text}
+ ))} +
+ )} -
- Billed To
- Bigcapital Technology, Inc.
- 131 Continental Dr Suite 305 Newark, -
- Delaware 19713 -
- United States -
- +1 762-339-5634 -
- ahmed@bigcapital.app -
+ {showBillingToAddress && ( +
+ {billedToLabel}
+ {billedToAddress.map((text, index) => ( +
{text}
+ ))} +
+ )}
- - - - + + + + - - - - - - + {lines.map((line, index) => ( + + + + + + + ))}
ItemDescription{itemRateLabel}{itemTotalLabel}{lineItemLabel}{lineDescriptionLabel}{lineRateLabel}{lineTotalLabel}
Simply dummy textSimply dummy text of the printing and typesetting1 X $100,00$100,00
{line.item}{line.description} + {line.quantity} X {line.rate} + {line.total}
@@ -159,32 +271,25 @@ export function InvoicePaperTemplate({ )} >
{subtotalLabel}
-
630.00
+
{subtotal}
)} {showDiscount && (
{discountLabel}
-
0.00
+
{discount}
)} {showTaxes && ( <> -
-
- Sample Tax1 (4.70%) + {taxes.map((tax, index) => ( +
+
{tax.label}
+
{tax.amount}
-
11.75
-
- -
-
- Sample Tax2 (7.00%) -
-
21.00
-
+ ))} )} @@ -193,14 +298,14 @@ export function InvoicePaperTemplate({ className={clsx(styles.totalsItem, styles.totalBottomBordered)} >
{totalLabel}
-
$662.75
+
{total}
)} {showPaymentMade && (
{paymentMadeLabel}
-
100.00
+
{paymentMade}
)} @@ -209,27 +314,38 @@ export function InvoicePaperTemplate({ className={clsx(styles.totalsItem, styles.totalBottomBordered)} >
{balanceDueLabel}
-
$562.75
+
{balanceDue}
)} -
-
Terms & Conditions
-
- It is a long established fact that a reader will be distracted by the - readable content of a page when looking at its layout. + {showTermsConditions && ( +
+
{termsConditionsLabel}
+
{termsConditions}
-
- -
-
Statement
-
- It is a long established fact that a reader will be distracted by the - readable content of a page when looking at its layout. + )} + {showStatement && ( +
+
{statementLabel}
+
{statement}
-
+ )}
); } + +const withFormikProps =

( + Component: React.ComponentType

, +) => { + return (props: Omit) => { + const { values } = useFormikContext(); + + return ; + }; +}; + +export const InvoicePaperTemplate = R.compose(withFormikProps)( + InvoicePaperTemplateRoot, +); diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/constants.ts b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/constants.ts new file mode 100644 index 000000000..ac4a03dae --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/constants.ts @@ -0,0 +1,134 @@ +export const initialValues = { + // Colors + primaryColor: '#2c3dd8', + secondaryColor: '#2c3dd8', + + // Company logo. + showCompanyLogo: true, + companyLogo: + 'https://cdn-development.mercury.com/demo-assets/avatars/mercury-demo-dark.png', + + // Top details. + showInvoiceNumber: true, + invoiceNumberLabel: 'Invoice number', + + showDateIssue: true, + dateIssueLabel: 'Date of Issue', + + showDueDate: true, + dueDateLabel: 'Due Date', + + // Company name + companyName: 'Bigcapital Technology, Inc.', + + // Addresses + showBilledFromAddress: true, + showBillingToAddress: true, + billedToLabel: 'Billed To', + + // Entries + itemNameLabel: 'Item', + itemDescriptionLabel: 'Description', + itemRateLabel: 'Rate', + itemTotalLabel: 'Total', + + // Totals + showSubtotal: true, + subtotalLabel: 'Subtotal', + + showDiscount: true, + discountLabel: 'Discount', + + showTaxes: true, + + showTotal: true, + totalLabel: 'Total', + + paymentMadeLabel: 'Payment Made', + showPaymentMade: true, + + dueAmountLabel: 'Due Amount', + showDueAmount: true, + + // Footer paragraphs. + termsConditionsLabel: 'Terms & Conditions', + showTermsConditions: true, + + statementLabel: 'Statement', + showStatement: true, +}; + +export const fieldsGroups = [ + { + label: 'Header', + fields: [ + { + labelKey: 'invoiceNumberLabel', + enableKey: 'showInvoiceNumber', + label: 'Invoice No.', + }, + { + labelKey: 'dateIssueLabel', + enableKey: 'showDateIssue', + label: 'Issue Date', + }, + { + labelKey: 'dueDateLabel', + enableKey: 'showDueDate', + label: 'Due Date', + }, + { + enableKey: 'showBillingToAddress', + labelKey: 'billedToLabel', + label: 'Bill To', + }, + { + enableKey: 'showBilledFromAddress', + label: 'Billed From', + }, + ], + }, + { + label: 'Totals', + fields: [ + { + labelKey: 'subtotalLabel', + enableKey: 'showSubtotal', + label: 'Subtotal', + }, + { + labelKey: 'discountLabel', + enableKey: 'showDiscount', + label: 'Discount', + }, + { enableKey: 'showTaxes', label: 'Taxes' }, + { labelKey: 'totalLabel', enableKey: 'showTotal', label: 'Total' }, + { + labelKey: 'paymentMadeLabel', + enableKey: 'showPaymentMade', + label: 'Payment Made', + }, + { + labelKey: 'dueAmountLabel', + enableKey: 'showDueAmount', + label: 'Due Amount', + }, + ], + }, + { + label: 'Footer', + fields: [ + { + labelKey: 'termsConditionsLabel', + enableKey: 'showTermsConditions', + label: 'Terms & Conditions', + }, + { + labelKey: 'statementLabel', + enableKey: 'showStatement', + label: 'Statement', + labelPlaceholder: 'Statement', + }, + ], + }, +]; diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/types.ts b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/types.ts new file mode 100644 index 000000000..6985bafb4 --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/types.ts @@ -0,0 +1,58 @@ +export interface InvoiceCustomizeValues { + // Colors + primaryColor?: string; + secondaryColor?: string; + + // Company Logo + showCompanyLogo?: boolean; + companyLogo?: string; + + // Top details. + showInvoiceNumber?: boolean; + invoiceNumberLabel?: string; + + showDateIssue?: boolean; + dateIssueLabel?: string; + + showDueDate?: boolean; + dueDateLabel?: string; + + // Company name + companyName?: string; + + // Addresses + showBilledFromAddress?: boolean; + showBillingToAddress?: boolean; + billedToLabel?: string; + + // Entries + itemNameLabel?: string; + itemDescriptionLabel?: string; + itemRateLabel?: string; + itemTotalLabel?: string; + + // Totals + showSubtotal?: boolean; + subtotalLabel?: string; + + showDiscount?: boolean; + discountLabel?: string; + + showTaxes?: boolean; + + showTotal?: boolean; + totalLabel?: string; + + paymentMadeLabel?: string; + showPaymentMade?: boolean; + + dueAmountLabel?: string; + showDueAmount?: boolean; + + // Footer paragraphs. + termsConditionsLabel?: string; + showTermsConditions?: boolean; + + statementLabel?: string; + showStatement?: boolean; +} diff --git a/packages/webapp/src/utils/sanitize-hex-color.ts b/packages/webapp/src/utils/sanitize-hex-color.ts new file mode 100644 index 000000000..e89bb76de --- /dev/null +++ b/packages/webapp/src/utils/sanitize-hex-color.ts @@ -0,0 +1,3 @@ +export function sanitizeToHexColor(input: string) { + return input; +}