mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
feat: invoice customize paper preview
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
|||||||
import { HexColorPicker } from 'react-colorful';
|
import { HexColorPicker } from 'react-colorful';
|
||||||
import { useUncontrolled } from '@/hooks/useUncontrolled';
|
import { useUncontrolled } from '@/hooks/useUncontrolled';
|
||||||
import { Box, BoxProps } from '@/components';
|
import { Box, BoxProps } from '@/components';
|
||||||
|
import { sanitizeToHexColor } from '@/utils/sanitize-hex-color';
|
||||||
import styles from './ColorInput.module.scss';
|
import styles from './ColorInput.module.scss';
|
||||||
|
|
||||||
export interface ColorInputProps {
|
export interface ColorInputProps {
|
||||||
@@ -72,6 +73,10 @@ export function ColorInput({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
|
onChange={(e) => {
|
||||||
|
const value = sanitizeToHexColor(e.currentTarget.value);
|
||||||
|
handleChange(value);
|
||||||
|
}}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
className={clsx(styles.field, inputProps?.className)}
|
className={clsx(styles.field, inputProps?.className)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export interface ElementCustomizePaperTemplateProps {
|
|||||||
ElementCustomize.PaperTemplate = ({
|
ElementCustomize.PaperTemplate = ({
|
||||||
children,
|
children,
|
||||||
}: ElementCustomizePaperTemplateProps) => {
|
}: ElementCustomizePaperTemplateProps) => {
|
||||||
return <Box>{children}</Box>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ElementCustomizeContentProps {
|
export interface ElementCustomizeContentProps {
|
||||||
@@ -70,5 +70,5 @@ ElementCustomize.FieldsTab = ({
|
|||||||
label,
|
label,
|
||||||
children,
|
children,
|
||||||
}: ElementCustomizeContentProps) => {
|
}: ElementCustomizeContentProps) => {
|
||||||
return <Box>{children}</Box>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { Button, Intent } from '@blueprintjs/core';
|
import { Button, Intent } from '@blueprintjs/core';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
import { Group, Stack } from '@/components';
|
import { Box, Group, Stack } from '@/components';
|
||||||
import { ElementCustomizeHeader } from './ElementCustomizeHeader';
|
import { ElementCustomizeHeader } from './ElementCustomizeHeader';
|
||||||
import { ElementCustomizeTabs } from './ElementCustomizeTabs';
|
import { ElementCustomizeTabs } from './ElementCustomizeTabs';
|
||||||
import { useElementCustomizeTabsController } from './ElementCustomizeTabsController';
|
import { useElementCustomizeTabsController } from './ElementCustomizeTabsController';
|
||||||
@@ -38,7 +38,7 @@ export function ElementCustomizeFieldsMain() {
|
|||||||
<ElementCustomizeHeader label={'Customize'} />
|
<ElementCustomizeHeader label={'Customize'} />
|
||||||
|
|
||||||
<Stack spacing={0} style={{ flex: '1 1 auto', overflow: 'auto' }}>
|
<Stack spacing={0} style={{ flex: '1 1 auto', overflow: 'auto' }}>
|
||||||
{CustomizeTabPanel}
|
<Box style={{ flex: '1 1' }}>{CustomizeTabPanel}</Box>
|
||||||
<ElementCustomizeFooterActions />
|
<ElementCustomizeFooterActions />
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -5,45 +5,18 @@ import { InvoicePaperTemplate } from './InvoicePaperTemplate';
|
|||||||
import { ElementCustomize } from '../../../ElementCustomize/ElementCustomize';
|
import { ElementCustomize } from '../../../ElementCustomize/ElementCustomize';
|
||||||
import { InvoiceCustomizeGeneralField } from './InvoiceCustomizeGeneralFields';
|
import { InvoiceCustomizeGeneralField } from './InvoiceCustomizeGeneralFields';
|
||||||
import { InvoiceCustomizeContentFields } from './InvoiceCutomizeContentFields';
|
import { InvoiceCustomizeContentFields } from './InvoiceCutomizeContentFields';
|
||||||
|
import { InvoiceCustomizeValues } from './types';
|
||||||
interface InvoiceCustomizeValues {
|
import { initialValues } from './constants';
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function InvoiceCustomizeContent() {
|
export default function InvoiceCustomizeContent() {
|
||||||
|
const handleFormSubmit = (values: InvoiceCustomizeValues) => {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className={Classes.DRAWER_BODY}>
|
<Box className={Classes.DRAWER_BODY}>
|
||||||
<ElementCustomize<InvoiceCustomizeValues>>
|
<ElementCustomize<InvoiceCustomizeValues>
|
||||||
|
initialValues={initialValues}
|
||||||
|
onSubmit={handleFormSubmit}
|
||||||
|
>
|
||||||
<ElementCustomize.PaperTemplate>
|
<ElementCustomize.PaperTemplate>
|
||||||
<InvoicePaperTemplate />
|
<InvoicePaperTemplate />
|
||||||
</ElementCustomize.PaperTemplate>
|
</ElementCustomize.PaperTemplate>
|
||||||
|
|||||||
@@ -20,33 +20,38 @@ export function InvoiceCustomizeGeneralField() {
|
|||||||
<FFormGroup
|
<FFormGroup
|
||||||
name={'primaryColor'}
|
name={'primaryColor'}
|
||||||
label={'Primary Color'}
|
label={'Primary Color'}
|
||||||
inline
|
|
||||||
className={styles.fieldGroup}
|
className={styles.fieldGroup}
|
||||||
|
inline
|
||||||
|
fastField
|
||||||
>
|
>
|
||||||
<FColorInput
|
<FColorInput
|
||||||
name={'primaryColor'}
|
name={'primaryColor'}
|
||||||
inputProps={{ style: { maxWidth: 120 } }}
|
inputProps={{ style: { maxWidth: 120 } }}
|
||||||
|
fastField
|
||||||
/>
|
/>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
<FFormGroup
|
<FFormGroup
|
||||||
name={'secondaryColor'}
|
name={'secondaryColor'}
|
||||||
label={'Secondary Color'}
|
label={'Secondary Color'}
|
||||||
inline
|
|
||||||
className={styles.fieldGroup}
|
className={styles.fieldGroup}
|
||||||
|
inline
|
||||||
|
fastField
|
||||||
>
|
>
|
||||||
<FColorInput
|
<FColorInput
|
||||||
name={'secondaryColor'}
|
name={'secondaryColor'}
|
||||||
inputProps={{ style: { maxWidth: 120 } }}
|
inputProps={{ style: { maxWidth: 120 } }}
|
||||||
|
fastField
|
||||||
/>
|
/>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
<FFormGroup name={'showLogo'} label={'Logo'}>
|
<FFormGroup name={'showCompanyLogo'} label={'Logo'} fastField>
|
||||||
<FSwitch
|
<FSwitch
|
||||||
name={'showLogo'}
|
name={'showCompanyLogo'}
|
||||||
label={'Display company logo in the paper'}
|
label={'Display company logo in the paper'}
|
||||||
className={styles.showCompanyLogoField}
|
className={styles.showCompanyLogoField}
|
||||||
large
|
large
|
||||||
|
fastField
|
||||||
/>
|
/>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,37 +1,46 @@
|
|||||||
import { Classes } from '@blueprintjs/core';
|
// @ts-nocheck
|
||||||
import { FInputGroup, FSwitch, Group, Stack } from '@/components';
|
import { FInputGroup, FSwitch, Group, Stack } from '@/components';
|
||||||
|
import { CLASSES } from '@/constants';
|
||||||
const items = [
|
import { Classes } from '@blueprintjs/core';
|
||||||
{ key: 'dueAmount', label: 'Due Amount' },
|
import { fieldsGroups } from './constants';
|
||||||
{ key: 'billedTo', label: 'Billed To' },
|
|
||||||
{ key: 'balanceDue', label: 'Balance Due' },
|
|
||||||
{ key: 'termsConditions', label: 'Terms & Conditions' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function InvoiceCustomizeContentFields() {
|
export function InvoiceCustomizeContentFields() {
|
||||||
return (
|
return (
|
||||||
<Stack style={{ padding: 20, flex: '1 1 auto' }}>
|
<Stack
|
||||||
<Stack>
|
spacing={10}
|
||||||
<h2>General Branding</h2>
|
style={{ padding: 20, paddingBottom: 40, flex: '1 1 auto' }}
|
||||||
|
>
|
||||||
|
<Stack spacing={10}>
|
||||||
|
<h3>General Branding</h3>
|
||||||
<p className={Classes.TEXT_MUTED}>
|
<p className={Classes.TEXT_MUTED}>
|
||||||
Set your invoice details to be automatically applied every time
you
|
Set your invoice details to be automatically applied every time
you
|
||||||
create a new invoice.
|
create a new invoice.
|
||||||
</p>
|
</p>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<h1>Header</h1>
|
|
||||||
|
|
||||||
<Stack>
|
<Stack>
|
||||||
{items.map((item, index) => (
|
{fieldsGroups.map((group) => (
|
||||||
<Group position={'apart'} key={index}>
|
<>
|
||||||
<FSwitch name={`item.${item.key}.enabled`} label={item.label} />
|
<h4 className={CLASSES.TEXT_MUTED} style={{ fontWeight: 600 }}>
|
||||||
|
{group.label}
|
||||||
|
</h4>
|
||||||
|
<Stack spacing={14}>
|
||||||
|
{group.fields.map((item, index) => (
|
||||||
|
<Group spacing={14} position={'apart'} key={index}>
|
||||||
|
<FSwitch name={item.enableKey} label={item.label} fastField />
|
||||||
|
{item.labelKey && (
|
||||||
<FInputGroup
|
<FInputGroup
|
||||||
name={'item.dueAmount.text'}
|
name={item.labelKey}
|
||||||
placeholder={item.label}
|
style={{ maxWidth: 150 }}
|
||||||
|
fastField
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
color: #111;
|
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;
|
padding: 24px 30px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -1,60 +1,127 @@
|
|||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
import styles from './InvoicePaperTemplate.module.scss';
|
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 {
|
interface PaperTemplateProps {
|
||||||
|
primaryColor?: string;
|
||||||
|
secondaryColor?: string;
|
||||||
|
|
||||||
|
showCompanyLogo?: boolean;
|
||||||
|
companyLogo?: string;
|
||||||
|
|
||||||
|
showInvoiceNumber?: boolean;
|
||||||
invoiceNumber?: string;
|
invoiceNumber?: string;
|
||||||
invoiceNumberLabel?: string;
|
invoiceNumberLabel?: string;
|
||||||
|
|
||||||
|
showDateIssue?: boolean;
|
||||||
dateIssue?: string;
|
dateIssue?: string;
|
||||||
dateIssueLabel?: string;
|
dateIssueLabel?: string;
|
||||||
|
|
||||||
|
showDueDate?: boolean;
|
||||||
dueDate?: string;
|
dueDate?: string;
|
||||||
dueDateLabel?: string;
|
dueDateLabel?: string;
|
||||||
|
|
||||||
companyName?: string;
|
companyName?: string;
|
||||||
|
|
||||||
bigtitle?: string;
|
bigtitle?: string;
|
||||||
|
|
||||||
itemRateLabel?: string;
|
// Address
|
||||||
itemQuantityLabel?: string;
|
showBillingToAddress?: boolean;
|
||||||
itemTotalLabel?: string;
|
showBilledFromAddress?: boolean;
|
||||||
|
billedToLabel?: string;
|
||||||
|
|
||||||
|
// Entries
|
||||||
|
lineItemLabel?: string;
|
||||||
|
lineDescriptionLabel?: string;
|
||||||
|
lineRateLabel?: string;
|
||||||
|
lineTotalLabel?: string;
|
||||||
|
|
||||||
// Totals
|
// Totals
|
||||||
showDueAmount?: boolean;
|
|
||||||
showDiscount?: boolean;
|
|
||||||
showPaymentMade?: boolean;
|
|
||||||
showTaxes?: boolean;
|
|
||||||
showSubtotal?: boolean;
|
|
||||||
showTotal?: boolean;
|
showTotal?: boolean;
|
||||||
showBalanceDue?: boolean;
|
|
||||||
|
|
||||||
paymentMadeLabel?: string;
|
|
||||||
discountLabel?: string;
|
|
||||||
subtotalLabel?: string;
|
|
||||||
totalLabel?: 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;
|
balanceDueLabel?: string;
|
||||||
|
balanceDue?: string;
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
termsConditionsLabel: string;
|
||||||
|
showTermsConditions: boolean;
|
||||||
|
termsConditions: string;
|
||||||
|
|
||||||
|
statementLabel: string;
|
||||||
|
showStatement: boolean;
|
||||||
|
statement: string;
|
||||||
|
|
||||||
|
lines?: Array<PapaerLine>;
|
||||||
|
taxes?: Array<PaperTax>;
|
||||||
|
|
||||||
|
billedFromAddres?: Array<string>;
|
||||||
|
billedToAddress?: Array<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InvoicePaperTemplate({
|
function InvoicePaperTemplateRoot({
|
||||||
bigtitle = 'Invoice',
|
primaryColor,
|
||||||
|
secondaryColor,
|
||||||
|
|
||||||
|
bigtitle = 'Invoice',
|
||||||
companyName = 'Bigcapital Technology, Inc.',
|
companyName = 'Bigcapital Technology, Inc.',
|
||||||
// dueDateLabel,
|
|
||||||
|
showCompanyLogo = true,
|
||||||
|
companyLogo,
|
||||||
|
|
||||||
dueDate = 'September 3, 2024',
|
dueDate = 'September 3, 2024',
|
||||||
dueDateLabel = 'Date due',
|
dueDateLabel = 'Date due',
|
||||||
|
showDueDate,
|
||||||
|
|
||||||
dateIssue = 'September 3, 2024',
|
dateIssue = 'September 3, 2024',
|
||||||
dateIssueLabel = 'Date of issue',
|
dateIssueLabel = 'Date of issue',
|
||||||
|
showDateIssue,
|
||||||
|
|
||||||
// dateIssue,
|
// dateIssue,
|
||||||
invoiceNumberLabel = 'Invoice number',
|
invoiceNumberLabel = 'Invoice number',
|
||||||
invoiceNumber = '346D3D40-0001',
|
invoiceNumber = '346D3D40-0001',
|
||||||
|
showInvoiceNumber,
|
||||||
|
|
||||||
|
// Address
|
||||||
|
showBillingToAddress = true,
|
||||||
|
showBilledFromAddress = true,
|
||||||
|
billedToLabel = 'Billed To',
|
||||||
|
|
||||||
// Entries
|
// Entries
|
||||||
itemQuantityLabel = 'Quantity',
|
lineItemLabel = 'Item',
|
||||||
itemRateLabel = 'Rate',
|
lineDescriptionLabel = 'Description',
|
||||||
itemTotalLabel = 'Total',
|
lineRateLabel = 'Rate',
|
||||||
|
lineTotalLabel = 'Total',
|
||||||
|
|
||||||
totalLabel = 'Total',
|
totalLabel = 'Total',
|
||||||
subtotalLabel = 'Subtotal',
|
subtotalLabel = 'Subtotal',
|
||||||
@@ -70,82 +137,127 @@ export function InvoicePaperTemplate({
|
|||||||
showPaymentMade = true,
|
showPaymentMade = true,
|
||||||
showDueAmount = true,
|
showDueAmount = true,
|
||||||
showBalanceDue = 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) {
|
}: PaperTemplateProps) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.root}>
|
<div className={styles.root}>
|
||||||
|
<style>{`:root { --invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor}; }`}</style>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h1 className={styles.bigTitle}>{bigtitle}</h1>
|
<h1 className={styles.bigTitle}>{bigtitle}</h1>
|
||||||
|
|
||||||
|
{showCompanyLogo && (
|
||||||
<div className={styles.logoWrap}>
|
<div className={styles.logoWrap}>
|
||||||
<img
|
<img alt="" src={companyLogo} />
|
||||||
alt=""
|
|
||||||
src="https://cdn-development.mercury.com/demo-assets/avatars/mercury-demo-dark.png"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.details}>
|
<div className={styles.details}>
|
||||||
|
{showInvoiceNumber && (
|
||||||
<div className={styles.detail}>
|
<div className={styles.detail}>
|
||||||
<div className={styles.detailLabel}>{invoiceNumberLabel}</div>
|
<div className={styles.detailLabel}>{invoiceNumberLabel}</div>
|
||||||
<div>{invoiceNumber}</div>
|
<div>{invoiceNumber}</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{showDateIssue && (
|
||||||
<div className={styles.detail}>
|
<div className={styles.detail}>
|
||||||
<div className={styles.detailLabel}>{dateIssueLabel}</div>
|
<div className={styles.detailLabel}>{dateIssueLabel}</div>
|
||||||
<div>{dateIssue}</div>
|
<div>{dateIssue}</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{showDueDate && (
|
||||||
<div className={styles.detail}>
|
<div className={styles.detail}>
|
||||||
<div className={styles.detailLabel}>{dueDateLabel}</div>
|
<div className={styles.detailLabel}>{dueDateLabel}</div>
|
||||||
<div>{dueDate}</div>
|
<div>{dueDate}</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.addressRoot}>
|
<div className={styles.addressRoot}>
|
||||||
|
{showBilledFromAddress && (
|
||||||
<div className={styles.addressBillTo}>
|
<div className={styles.addressBillTo}>
|
||||||
<strong>{companyName}</strong> <br />
|
<strong>{companyName}</strong> <br />
|
||||||
131 Continental Dr Suite 305 Newark,
|
{billedFromAddres.map((text, index) => (
|
||||||
<br />
|
<div key={index}>{text}</div>
|
||||||
Delaware 19713
|
))}
|
||||||
<br />
|
|
||||||
United States
|
|
||||||
<br />
|
|
||||||
+1 762-339-5634
|
|
||||||
<br />
|
|
||||||
ahmed@bigcapital.app
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showBillingToAddress && (
|
||||||
<div className={styles.addressFrom}>
|
<div className={styles.addressFrom}>
|
||||||
<strong>Billed To</strong> <br />
|
<strong>{billedToLabel}</strong> <br />
|
||||||
Bigcapital Technology, Inc. <br />
|
{billedToAddress.map((text, index) => (
|
||||||
131 Continental Dr Suite 305 Newark,
|
<div key={index}>{text}</div>
|
||||||
<br />
|
))}
|
||||||
Delaware 19713
|
|
||||||
<br />
|
|
||||||
United States
|
|
||||||
<br />
|
|
||||||
+1 762-339-5634
|
|
||||||
<br />
|
|
||||||
ahmed@bigcapital.app
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table className={styles.table}>
|
<table className={styles.table}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Item</th>
|
<th>{lineItemLabel}</th>
|
||||||
<th>Description</th>
|
<th>{lineDescriptionLabel}</th>
|
||||||
<th className={styles.rate}>{itemRateLabel}</th>
|
<th className={styles.rate}>{lineRateLabel}</th>
|
||||||
<th className={styles.total}>{itemTotalLabel}</th>
|
<th className={styles.total}>{lineTotalLabel}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody className={styles.tableBody}>
|
<tbody className={styles.tableBody}>
|
||||||
<tr>
|
{lines.map((line, index) => (
|
||||||
<td>Simply dummy text</td>
|
<tr key={index}>
|
||||||
<td>Simply dummy text of the printing and typesetting</td>
|
<td>{line.item}</td>
|
||||||
<td className={styles.rate}>1 X $100,00</td>
|
<td>{line.description}</td>
|
||||||
<td className={styles.total}>$100,00</td>
|
<td className={styles.rate}>
|
||||||
|
{line.quantity} X {line.rate}
|
||||||
|
</td>
|
||||||
|
<td className={styles.total}>{line.total}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@@ -159,32 +271,25 @@ export function InvoicePaperTemplate({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className={styles.totalsItemLabel}>{subtotalLabel}</div>
|
<div className={styles.totalsItemLabel}>{subtotalLabel}</div>
|
||||||
<div className={styles.totalsItemAmount}>630.00</div>
|
<div className={styles.totalsItemAmount}>{subtotal}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showDiscount && (
|
{showDiscount && (
|
||||||
<div className={styles.totalsItem}>
|
<div className={styles.totalsItem}>
|
||||||
<div className={styles.totalsItemLabel}>{discountLabel}</div>
|
<div className={styles.totalsItemLabel}>{discountLabel}</div>
|
||||||
<div className={styles.totalsItemAmount}>0.00</div>
|
<div className={styles.totalsItemAmount}>{discount}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showTaxes && (
|
{showTaxes && (
|
||||||
<>
|
<>
|
||||||
<div className={styles.totalsItem}>
|
{taxes.map((tax, index) => (
|
||||||
<div className={styles.totalsItemLabel}>
|
<div key={index} className={styles.totalsItem}>
|
||||||
Sample Tax1 (4.70%)
|
<div className={styles.totalsItemLabel}>{tax.label}</div>
|
||||||
</div>
|
<div className={styles.totalsItemAmount}>{tax.amount}</div>
|
||||||
<div className={styles.totalsItemAmount}>11.75</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.totalsItem}>
|
|
||||||
<div className={styles.totalsItemLabel}>
|
|
||||||
Sample Tax2 (7.00%)
|
|
||||||
</div>
|
|
||||||
<div className={styles.totalsItemAmount}>21.00</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -193,14 +298,14 @@ export function InvoicePaperTemplate({
|
|||||||
className={clsx(styles.totalsItem, styles.totalBottomBordered)}
|
className={clsx(styles.totalsItem, styles.totalBottomBordered)}
|
||||||
>
|
>
|
||||||
<div className={styles.totalsItemLabel}>{totalLabel}</div>
|
<div className={styles.totalsItemLabel}>{totalLabel}</div>
|
||||||
<div className={styles.totalsItemAmount}>$662.75</div>
|
<div className={styles.totalsItemAmount}>{total}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showPaymentMade && (
|
{showPaymentMade && (
|
||||||
<div className={styles.totalsItem}>
|
<div className={styles.totalsItem}>
|
||||||
<div className={styles.totalsItemLabel}>{paymentMadeLabel}</div>
|
<div className={styles.totalsItemLabel}>{paymentMadeLabel}</div>
|
||||||
<div className={styles.totalsItemAmount}>100.00</div>
|
<div className={styles.totalsItemAmount}>{paymentMade}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -209,27 +314,38 @@ export function InvoicePaperTemplate({
|
|||||||
className={clsx(styles.totalsItem, styles.totalBottomBordered)}
|
className={clsx(styles.totalsItem, styles.totalBottomBordered)}
|
||||||
>
|
>
|
||||||
<div className={styles.totalsItemLabel}>{balanceDueLabel}</div>
|
<div className={styles.totalsItemLabel}>{balanceDueLabel}</div>
|
||||||
<div className={styles.totalsItemAmount}>$562.75</div>
|
<div className={styles.totalsItemAmount}>{balanceDue}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{showTermsConditions && (
|
||||||
<div className={styles.paragraph}>
|
<div className={styles.paragraph}>
|
||||||
<div className={styles.paragraphLabel}>Terms & Conditions</div>
|
<div className={styles.paragraphLabel}>{termsConditionsLabel}</div>
|
||||||
<div>
|
<div>{termsConditions}</div>
|
||||||
It is a long established fact that a reader will be distracted by the
|
|
||||||
readable content of a page when looking at its layout.
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
{showStatement && (
|
||||||
<div className={styles.paragraph}>
|
<div className={styles.paragraph}>
|
||||||
<div className={styles.paragraphLabel}>Statement</div>
|
<div className={styles.paragraphLabel}>{statementLabel}</div>
|
||||||
<div>
|
<div>{statement}</div>
|
||||||
It is a long established fact that a reader will be distracted by the
|
|
||||||
readable content of a page when looking at its layout.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const withFormikProps = <P extends object>(
|
||||||
|
Component: React.ComponentType<P>,
|
||||||
|
) => {
|
||||||
|
return (props: Omit<P, keyof PaperTemplateProps>) => {
|
||||||
|
const { values } = useFormikContext<PaperTemplateProps>();
|
||||||
|
|
||||||
|
return <Component {...(props as P)} {...values} />;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InvoicePaperTemplate = R.compose(withFormikProps)(
|
||||||
|
InvoicePaperTemplateRoot,
|
||||||
|
);
|
||||||
|
|||||||
@@ -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',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
3
packages/webapp/src/utils/sanitize-hex-color.ts
Normal file
3
packages/webapp/src/utils/sanitize-hex-color.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function sanitizeToHexColor(input: string) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user