mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-22 15:50:32 +00:00
feat: wip invoice customizer
This commit is contained in:
@@ -23,10 +23,11 @@ import WarehouseTransferDetailDrawer from '@/containers/Drawers/WarehouseTransfe
|
|||||||
import TaxRateDetailsDrawer from '@/containers/TaxRates/drawers/TaxRateDetailsDrawer/TaxRateDetailsDrawer';
|
import TaxRateDetailsDrawer from '@/containers/TaxRates/drawers/TaxRateDetailsDrawer/TaxRateDetailsDrawer';
|
||||||
import CategorizeTransactionDrawer from '@/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionDrawer';
|
import CategorizeTransactionDrawer from '@/containers/CashFlow/CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionDrawer';
|
||||||
import ChangeSubscriptionPlanDrawer from '@/containers/Subscriptions/drawers/ChangeSubscriptionPlanDrawer/ChangeSubscriptionPlanDrawer';
|
import ChangeSubscriptionPlanDrawer from '@/containers/Subscriptions/drawers/ChangeSubscriptionPlanDrawer/ChangeSubscriptionPlanDrawer';
|
||||||
|
import { InvoiceCustomizeDrawer } from '@/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeDrawer';
|
||||||
|
import { EstimateCustomizeDrawer } from '@/containers/Sales/Estimates/EstimateCustomize/EstimateCustomizeDrawer';
|
||||||
|
import { ReceiptCustomizeDrawer } from '@/containers/Sales/Receipts/ReceiptCustomize/ReceiptCustomizeDrawer';
|
||||||
|
|
||||||
import { DRAWERS } from '@/constants/drawers';
|
import { DRAWERS } from '@/constants/drawers';
|
||||||
import { InvoiceCustomizeDrawer } from '@/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeDrawer';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drawers container of the dashboard.
|
* Drawers container of the dashboard.
|
||||||
*/
|
*/
|
||||||
@@ -67,6 +68,8 @@ export default function DrawersContainer() {
|
|||||||
<CategorizeTransactionDrawer name={DRAWERS.CATEGORIZE_TRANSACTION} />
|
<CategorizeTransactionDrawer name={DRAWERS.CATEGORIZE_TRANSACTION} />
|
||||||
<ChangeSubscriptionPlanDrawer name={DRAWERS.CHANGE_SUBSCARIPTION_PLAN} />
|
<ChangeSubscriptionPlanDrawer name={DRAWERS.CHANGE_SUBSCARIPTION_PLAN} />
|
||||||
<InvoiceCustomizeDrawer name={DRAWERS.INVOICE_CUSTOMIZE} />
|
<InvoiceCustomizeDrawer name={DRAWERS.INVOICE_CUSTOMIZE} />
|
||||||
|
<EstimateCustomizeDrawer name={DRAWERS.ESTIMATE_CUSTOMIZE} />
|
||||||
|
<ReceiptCustomizeDrawer name={DRAWERS.RECEIPT_CUSTOMIZE} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export default function EstimateCustomizeContent() {
|
||||||
|
return <h1>Hello World</h1>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import { Drawer, DrawerSuspense } from '@/components';
|
||||||
|
import withDrawers from '@/containers/Drawer/withDrawers';
|
||||||
|
|
||||||
|
const EstimateCustomizeContent = React.lazy(
|
||||||
|
() => import('./EstimateCustomizeContent'),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimate customize drawer.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
function EstimateCustomizeDrawerRoot({
|
||||||
|
name,
|
||||||
|
|
||||||
|
// #withDrawer
|
||||||
|
isOpen,
|
||||||
|
payload: {},
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Drawer isOpen={isOpen} name={name} size={'100%'}>
|
||||||
|
<DrawerSuspense>
|
||||||
|
<EstimateCustomizeContent />
|
||||||
|
</DrawerSuspense>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EstimateCustomizeDrawer = R.compose(withDrawers())(
|
||||||
|
EstimateCustomizeDrawerRoot,
|
||||||
|
);
|
||||||
@@ -7,6 +7,11 @@ import {
|
|||||||
NavbarGroup,
|
NavbarGroup,
|
||||||
Intent,
|
Intent,
|
||||||
Alignment,
|
Alignment,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
Popover,
|
||||||
|
PopoverInteractionKind,
|
||||||
|
Position,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -35,6 +40,8 @@ import { useDownloadExportPdf } from '@/hooks/query/FinancialReports/use-export-
|
|||||||
import { SaleEstimateAction, AbilitySubject } from '@/constants/abilityOption';
|
import { SaleEstimateAction, AbilitySubject } from '@/constants/abilityOption';
|
||||||
import { compose } from '@/utils';
|
import { compose } from '@/utils';
|
||||||
import { DialogsName } from '@/constants/dialogs';
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||||
|
import { DRAWERS } from '@/constants/drawers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Estimates list actions bar.
|
* Estimates list actions bar.
|
||||||
@@ -52,6 +59,9 @@ function EstimateActionsBar({
|
|||||||
// #withDialogActions
|
// #withDialogActions
|
||||||
openDialog,
|
openDialog,
|
||||||
|
|
||||||
|
// #withDrawerActions
|
||||||
|
openDrawer,
|
||||||
|
|
||||||
// #withSettingsActions
|
// #withSettingsActions
|
||||||
addSetting,
|
addSetting,
|
||||||
}) {
|
}) {
|
||||||
@@ -96,6 +106,10 @@ function EstimateActionsBar({
|
|||||||
const handlePrintBtnClick = () => {
|
const handlePrintBtnClick = () => {
|
||||||
downloadExportPdf({ resource: 'SaleEstimate' });
|
downloadExportPdf({ resource: 'SaleEstimate' });
|
||||||
};
|
};
|
||||||
|
// Handle customize button clicl.
|
||||||
|
const handleCustomizeBtnClick = () => {
|
||||||
|
openDrawer(DRAWERS.ESTIMATE_CUSTOMIZE);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<DashboardActionsBar>
|
||||||
@@ -167,6 +181,25 @@ function EstimateActionsBar({
|
|||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
|
|
||||||
<NavbarGroup align={Alignment.RIGHT}>
|
<NavbarGroup align={Alignment.RIGHT}>
|
||||||
|
<Popover
|
||||||
|
minimal={true}
|
||||||
|
interactionKind={PopoverInteractionKind.CLICK}
|
||||||
|
position={Position.BOTTOM_RIGHT}
|
||||||
|
modifiers={{
|
||||||
|
offset: { offset: '0, 4' },
|
||||||
|
}}
|
||||||
|
content={
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
onClick={handleCustomizeBtnClick}
|
||||||
|
text={'Customize Estimate'}
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button icon={<Icon icon="cog-16" iconSize={16} />} minimal={true} />
|
||||||
|
</Popover>
|
||||||
|
<NavbarDivider />
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon="refresh-16" iconSize={14} />}
|
icon={<Icon icon="refresh-16" iconSize={14} />}
|
||||||
@@ -187,4 +220,5 @@ export default compose(
|
|||||||
estimatesTableSize: estimatesSettings?.tableSize,
|
estimatesTableSize: estimatesSettings?.tableSize,
|
||||||
})),
|
})),
|
||||||
withDialogActions,
|
withDialogActions,
|
||||||
|
withDrawerActions,
|
||||||
)(EstimateActionsBar);
|
)(EstimateActionsBar);
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Box, Group } from '@/components';
|
||||||
|
import { InvoiceCustomizeProvider } from './InvoiceCustomizeProvider';
|
||||||
|
import {
|
||||||
|
InvoiceCustomizeForm,
|
||||||
|
InvoiceCustomizeFormProps,
|
||||||
|
} from './InvoiceCustomizerForm';
|
||||||
|
import { InvoiceCustomizeTabsControllerProvider } from './InvoiceCustomizeTabsController';
|
||||||
|
import { InvoiceCustomizeFields } from './InvoiceCustomizeFields';
|
||||||
|
import { InvoiceCustomizePreview } from './InvoiceCustomizePreview';
|
||||||
|
import { extractChildren } from '@/utils/extract-children';
|
||||||
|
|
||||||
|
export interface InvoiceCustomizeProps<T> extends InvoiceCustomizeFormProps<T> {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InvoiceCustomize<T>({
|
||||||
|
initialValues,
|
||||||
|
validationSchema,
|
||||||
|
onSubmit,
|
||||||
|
children,
|
||||||
|
}: InvoiceCustomizeProps<T>) {
|
||||||
|
const PaperTemplate = React.useMemo(
|
||||||
|
() => extractChildren(children, InvoiceCustomize.PaperTemplate),
|
||||||
|
[children],
|
||||||
|
);
|
||||||
|
const CustomizeTabs = React.useMemo(
|
||||||
|
() => extractChildren(children, InvoiceCustomize.FieldsTab),
|
||||||
|
[children],
|
||||||
|
);
|
||||||
|
|
||||||
|
const value = { PaperTemplate, CustomizeTabs };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InvoiceCustomizeForm
|
||||||
|
initialValues={initialValues}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
>
|
||||||
|
<InvoiceCustomizeTabsControllerProvider>
|
||||||
|
<InvoiceCustomizeProvider value={value}>
|
||||||
|
<Group spacing={0} align="stretch">
|
||||||
|
<InvoiceCustomizeFields />
|
||||||
|
<InvoiceCustomizePreview />
|
||||||
|
</Group>
|
||||||
|
</InvoiceCustomizeProvider>
|
||||||
|
</InvoiceCustomizeTabsControllerProvider>
|
||||||
|
</InvoiceCustomizeForm>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InvoiceCustomizePaperTemplateProps {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvoiceCustomize.PaperTemplate = ({
|
||||||
|
children,
|
||||||
|
}: InvoiceCustomizePaperTemplateProps) => {
|
||||||
|
return <Box>{children}</Box>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface InvoiceCustomizeContentProps {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvoiceCustomize.FieldsTab = ({
|
||||||
|
id,
|
||||||
|
label,
|
||||||
|
children,
|
||||||
|
}: InvoiceCustomizeContentProps) => {
|
||||||
|
return <Box>{children}</Box>;
|
||||||
|
};
|
||||||
@@ -1,21 +1,65 @@
|
|||||||
import { Box, Group } from '@/components';
|
import React from 'react';
|
||||||
import { InvoiceCustomizePreview } from './InvoiceCustomizePreview';
|
import { Box } from '@/components';
|
||||||
import { InvoiceCustomizeFields } from './InvoiceCustomizeFields';
|
|
||||||
import { InvoiceCustomizeForm } from './InvoiceCustomizerForm';
|
|
||||||
import { Classes } from '@blueprintjs/core';
|
import { Classes } from '@blueprintjs/core';
|
||||||
import { InvoiceCustomizeTabsControllerProvider } from './InvoiceCustomizeTabsController';
|
import { InvoicePaperTemplate } from './InvoicePaperTemplate';
|
||||||
|
import { InvoiceCustomize } from './InvoiceCustomize';
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
export default function InvoiceCustomizeContent() {
|
export default function InvoiceCustomizeContent() {
|
||||||
return (
|
return (
|
||||||
<Box className={Classes.DRAWER_BODY}>
|
<Box className={Classes.DRAWER_BODY}>
|
||||||
<InvoiceCustomizeForm>
|
<InvoiceCustomize<InvoiceCustomizeValues>>
|
||||||
<Group spacing={0} align="stretch">
|
<InvoiceCustomize.PaperTemplate>
|
||||||
<InvoiceCustomizeTabsControllerProvider>
|
<InvoicePaperTemplate />
|
||||||
<InvoiceCustomizeFields />
|
</InvoiceCustomize.PaperTemplate>
|
||||||
<InvoiceCustomizePreview />
|
|
||||||
</InvoiceCustomizeTabsControllerProvider>
|
<InvoiceCustomize.FieldsTab id={'general'} label={'General'}>
|
||||||
</Group>
|
<InvoiceCustomizeGeneralField />
|
||||||
</InvoiceCustomizeForm>
|
</InvoiceCustomize.FieldsTab>
|
||||||
|
|
||||||
|
<InvoiceCustomize.FieldsTab id={'content'} label={'Content'}>
|
||||||
|
<InvoiceCustomizeContentFields />
|
||||||
|
</InvoiceCustomize.FieldsTab>
|
||||||
|
|
||||||
|
<InvoiceCustomize.FieldsTab id={'totals'} label={'Totals'}>
|
||||||
|
asdfasdfdsaf #3
|
||||||
|
</InvoiceCustomize.FieldsTab>
|
||||||
|
</InvoiceCustomize>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ const InvoiceCustomizeContent = React.lazy(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refund credit note detail.
|
* Invoice customize drawer.
|
||||||
* @returns
|
* @returns {React.ReactNode}
|
||||||
*/
|
*/
|
||||||
function InvoiceCustomizeDrawerRoot({
|
function InvoiceCustomizeDrawerRoot({
|
||||||
name,
|
name,
|
||||||
@@ -19,12 +19,7 @@ function InvoiceCustomizeDrawerRoot({
|
|||||||
payload: {},
|
payload: {},
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer isOpen={isOpen} name={name} size={'100%'}>
|
||||||
isOpen={isOpen}
|
|
||||||
name={name}
|
|
||||||
size={'100%'}
|
|
||||||
>
|
|
||||||
|
|
||||||
<DrawerSuspense>
|
<DrawerSuspense>
|
||||||
<InvoiceCustomizeContent />
|
<InvoiceCustomizeContent />
|
||||||
</DrawerSuspense>
|
</DrawerSuspense>
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { Box, Group, Stack } from '@/components';
|
import { Button, Intent } from '@blueprintjs/core';
|
||||||
|
import { Group, Stack } from '@/components';
|
||||||
import { InvoiceCustomizeHeader } from './InvoiceCustomizeHeader';
|
import { InvoiceCustomizeHeader } from './InvoiceCustomizeHeader';
|
||||||
import { InvoiceCustomizeTabs } from './InvoiceCustomizeTabs';
|
import { InvoiceCustomizeTabs } from './InvoiceCustomizeTabs';
|
||||||
import { InvoiceCustomizeGeneralField } from './InvoiceCustomizeGeneralFields';
|
|
||||||
import { useInvoiceCustomizeTabsController } from './InvoiceCustomizeTabsController';
|
import { useInvoiceCustomizeTabsController } from './InvoiceCustomizeTabsController';
|
||||||
import { Button, Intent } from '@blueprintjs/core';
|
|
||||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
|
||||||
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
import { InvoiceCustomizeContentFields } from './InvoiceCutomizeContentFields';
|
import { useInvoiceCustomizeContext } from './InvoiceCustomizeProvider';
|
||||||
import styles from './InvoiceCustomizeFields.module.scss';
|
import styles from './InvoiceCustomizeFields.module.scss';
|
||||||
|
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
export function InvoiceCustomizeFields() {
|
export function InvoiceCustomizeFields() {
|
||||||
return (
|
return (
|
||||||
@@ -23,14 +23,22 @@ export function InvoiceCustomizeFields() {
|
|||||||
|
|
||||||
export function InvoiceCustomizeFieldsMain() {
|
export function InvoiceCustomizeFieldsMain() {
|
||||||
const { currentTabId } = useInvoiceCustomizeTabsController();
|
const { currentTabId } = useInvoiceCustomizeTabsController();
|
||||||
|
const { CustomizeTabs } = useInvoiceCustomizeContext();
|
||||||
|
|
||||||
|
const CustomizeTabPanel = React.useMemo(
|
||||||
|
() =>
|
||||||
|
React.Children.map(CustomizeTabs, (tab) => {
|
||||||
|
return tab.props.id === currentTabId ? tab : null;
|
||||||
|
}).filter(Boolean),
|
||||||
|
[CustomizeTabs, currentTabId],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack spacing={0} className={styles.mainFields}>
|
<Stack spacing={0} className={styles.mainFields}>
|
||||||
<InvoiceCustomizeHeader label={'Customize'} />
|
<InvoiceCustomizeHeader label={'Customize'} />
|
||||||
|
|
||||||
<Stack spacing={0} style={{ flex: '1 1 auto', overflow: 'auto' }}>
|
<Stack spacing={0} style={{ flex: '1 1 auto', overflow: 'auto' }}>
|
||||||
{currentTabId === 'general' && <InvoiceCustomizeGeneralField />}
|
{CustomizeTabPanel}
|
||||||
{currentTabId === 'content' && <InvoiceCustomizeContentFields />}
|
|
||||||
|
|
||||||
<InvoiceCustomizeFooterActions />
|
<InvoiceCustomizeFooterActions />
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import { Box } from '@/components';
|
import { Box } from '@/components';
|
||||||
import { PaperTemplate } from './PaperTemplate';
|
import { useInvoiceCustomizeContext } from './InvoiceCustomizeProvider';
|
||||||
|
|
||||||
export function InvoiceCustomizePreviewContent() {
|
export function InvoiceCustomizePreviewContent() {
|
||||||
|
const { PaperTemplate } = useInvoiceCustomizeContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
padding: '28px 24px 40px',
|
padding: '28px 24px 40px',
|
||||||
backgroundColor: '#F5F5F5',
|
backgroundColor: '#F5F5F5',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
flex: '1'
|
flex: '1',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PaperTemplate />
|
{PaperTemplate}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import React, { createContext, useContext } from 'react';
|
||||||
|
|
||||||
|
interface InvoiceCustomizeValue {
|
||||||
|
PaperTemplate?: React.ReactNode;
|
||||||
|
CustomizeTabs: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InvoiceCustomizeContext = createContext<InvoiceCustomizeValue>(
|
||||||
|
{} as InvoiceCustomizeValue,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const InvoiceCustomizeProvider: React.FC<{
|
||||||
|
value: InvoiceCustomizeValue;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}> = ({ value, children }) => {
|
||||||
|
return (
|
||||||
|
<InvoiceCustomizeContext.Provider value={{ ...value }}>
|
||||||
|
{children}
|
||||||
|
</InvoiceCustomizeContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useInvoiceCustomizeContext = (): InvoiceCustomizeValue => {
|
||||||
|
const context = useContext<InvoiceCustomizeValue>(InvoiceCustomizeContext);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
'useInvoiceCustomize must be used within an InvoiceCustomizeProvider',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@@ -6,10 +6,17 @@ import {
|
|||||||
useInvoiceCustomizeTabsController,
|
useInvoiceCustomizeTabsController,
|
||||||
} from './InvoiceCustomizeTabsController';
|
} from './InvoiceCustomizeTabsController';
|
||||||
import styles from './InvoiceCustomizeTabs.module.scss';
|
import styles from './InvoiceCustomizeTabs.module.scss';
|
||||||
|
import { useInvoiceCustomizeContext } from './InvoiceCustomizeProvider';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
export function InvoiceCustomizeTabs() {
|
export function InvoiceCustomizeTabs() {
|
||||||
const { setCurrentTabId } = useInvoiceCustomizeTabsController();
|
const { setCurrentTabId } = useInvoiceCustomizeTabsController();
|
||||||
|
|
||||||
|
const { CustomizeTabs } = useInvoiceCustomizeContext();
|
||||||
|
|
||||||
|
const tabItems = React.Children.map(CustomizeTabs, (node) => ({
|
||||||
|
...(React.isValidElement(node) ? node.props : {}),
|
||||||
|
}));
|
||||||
const handleChange = (value: InvoiceCustomizeTabsEnum) => {
|
const handleChange = (value: InvoiceCustomizeTabsEnum) => {
|
||||||
setCurrentTabId(value);
|
setCurrentTabId(value);
|
||||||
};
|
};
|
||||||
@@ -25,9 +32,9 @@ export function InvoiceCustomizeTabs() {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className={styles.tabsList}
|
className={styles.tabsList}
|
||||||
>
|
>
|
||||||
<Tab id="general" title="General" />
|
{tabItems?.map(({ id, label }: { id: string; label: string }) => (
|
||||||
<Tab id="content" title="Content" />
|
<Tab id={id} key={id} title={label} />
|
||||||
<Tab id="total" title="Total" />
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import { Formik, Form } from 'formik';
|
// @ts-nocheck
|
||||||
import * as Yup from 'yup';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Formik, Form, FormikHelpers } from 'formik';
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
export interface InvoiceCustomizeFormProps<T> {
|
||||||
invoiceNumber: Yup.string().required('Invoice number is required'),
|
initialValues?: T;
|
||||||
customerName: Yup.string().required('Customer name is required'),
|
validationSchema?: any;
|
||||||
amount: Yup.number()
|
onSubmit?: (values: T, formikHelpers: FormikHelpers<T>) => void;
|
||||||
.required('Amount is required')
|
children?: React.ReactNode;
|
||||||
.positive('Amount must be positive'),
|
|
||||||
});
|
|
||||||
|
|
||||||
interface InvoiceCustomizeFormProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InvoiceCustomizeForm({ children }: InvoiceCustomizeFormProps) {
|
export function InvoiceCustomizeForm<T>({
|
||||||
|
initialValues,
|
||||||
|
validationSchema,
|
||||||
|
onSubmit,
|
||||||
|
children,
|
||||||
|
}: InvoiceCustomizeFormProps<T>) {
|
||||||
return (
|
return (
|
||||||
<Formik
|
<Formik<T>
|
||||||
initialValues={{ invoiceNumber: '', customerName: '', amount: '' }}
|
initialValues={{ ...initialValues }}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
onSubmit={(values) => {}}
|
onSubmit={(value, helpers) => onSubmit && onSubmit(value, helpers)}
|
||||||
>
|
>
|
||||||
<Form>{children}</Form>
|
<Form>{children}</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
import clsx from 'classnames';
|
||||||
|
import styles from './PaperTemplate.module.scss';
|
||||||
|
|
||||||
|
interface PaperTemplateProps {
|
||||||
|
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 function InvoicePaperTemplate({
|
||||||
|
bigtitle = 'Invoice',
|
||||||
|
|
||||||
|
companyName = 'Bigcapital Technology, Inc.',
|
||||||
|
// dueDateLabel,
|
||||||
|
|
||||||
|
dueDate = 'September 3, 2024',
|
||||||
|
dueDateLabel = 'Date due',
|
||||||
|
|
||||||
|
dateIssue = 'September 3, 2024',
|
||||||
|
dateIssueLabel = 'Date of issue',
|
||||||
|
|
||||||
|
// dateIssue,
|
||||||
|
invoiceNumberLabel = 'Invoice number',
|
||||||
|
invoiceNumber = '346D3D40-0001',
|
||||||
|
|
||||||
|
// Entries
|
||||||
|
itemQuantityLabel = 'Quantity',
|
||||||
|
itemRateLabel = 'Rate',
|
||||||
|
itemTotalLabel = 'Total',
|
||||||
|
|
||||||
|
totalLabel = 'Total',
|
||||||
|
subtotalLabel = 'Subtotal',
|
||||||
|
discountLabel = 'Discount',
|
||||||
|
paymentMadeLabel = 'Payment Made',
|
||||||
|
balanceDueLabel = 'Balance Due',
|
||||||
|
|
||||||
|
// Totals
|
||||||
|
showTotal = true,
|
||||||
|
showSubtotal = true,
|
||||||
|
showDiscount = true,
|
||||||
|
showTaxes = true,
|
||||||
|
showPaymentMade = true,
|
||||||
|
showDueAmount = true,
|
||||||
|
showBalanceDue = true,
|
||||||
|
}: PaperTemplateProps) {
|
||||||
|
return (
|
||||||
|
<div className={styles.root}>
|
||||||
|
<div>
|
||||||
|
<h1 className={styles.bigTitle}>{bigtitle}</h1>
|
||||||
|
<div className={styles.logoWrap}>
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
src="https://cdn-development.mercury.com/demo-assets/avatars/mercury-demo-dark.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.details}>
|
||||||
|
<div className={styles.detail}>
|
||||||
|
<div className={styles.detailLabel}>{invoiceNumberLabel}</div>
|
||||||
|
<div>{invoiceNumber}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.detail}>
|
||||||
|
<div className={styles.detailLabel}>{dateIssueLabel}</div>
|
||||||
|
<div>{dateIssue}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.detail}>
|
||||||
|
<div className={styles.detailLabel}>{dueDateLabel}</div>
|
||||||
|
<div>{dueDate}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.addressRoot}>
|
||||||
|
<div className={styles.addressBillTo}>
|
||||||
|
<strong>{companyName}</strong> <br />
|
||||||
|
131 Continental Dr Suite 305 Newark,
|
||||||
|
<br />
|
||||||
|
Delaware 19713
|
||||||
|
<br />
|
||||||
|
United States
|
||||||
|
<br />
|
||||||
|
+1 762-339-5634
|
||||||
|
<br />
|
||||||
|
ahmed@bigcapital.app
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.addressFrom}>
|
||||||
|
<strong>Billed To</strong> <br />
|
||||||
|
Bigcapital Technology, Inc. <br />
|
||||||
|
131 Continental Dr Suite 305 Newark,
|
||||||
|
<br />
|
||||||
|
Delaware 19713
|
||||||
|
<br />
|
||||||
|
United States
|
||||||
|
<br />
|
||||||
|
+1 762-339-5634
|
||||||
|
<br />
|
||||||
|
ahmed@bigcapital.app
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table className={styles.table}>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Item</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th className={styles.rate}>{itemRateLabel}</th>
|
||||||
|
<th className={styles.total}>{itemTotalLabel}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody className={styles.tableBody}>
|
||||||
|
<tr>
|
||||||
|
<td>Simply dummy text</td>
|
||||||
|
<td>Simply dummy text of the printing and typesetting</td>
|
||||||
|
<td className={styles.rate}>1 X $100,00</td>
|
||||||
|
<td className={styles.total}>$100,00</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<div className={styles.totals}>
|
||||||
|
{showSubtotal && (
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
styles.totalsItem,
|
||||||
|
styles.totalBottomGrayBordered,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={styles.totalsItemLabel}>{subtotalLabel}</div>
|
||||||
|
<div className={styles.totalsItemAmount}>630.00</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showDiscount && (
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>{discountLabel}</div>
|
||||||
|
<div className={styles.totalsItemAmount}>0.00</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showTaxes && (
|
||||||
|
<>
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>
|
||||||
|
Sample Tax1 (4.70%)
|
||||||
|
</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>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showTotal && (
|
||||||
|
<div
|
||||||
|
className={clsx(styles.totalsItem, styles.totalBottomBordered)}
|
||||||
|
>
|
||||||
|
<div className={styles.totalsItemLabel}>{totalLabel}</div>
|
||||||
|
<div className={styles.totalsItemAmount}>$662.75</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showPaymentMade && (
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>{paymentMadeLabel}</div>
|
||||||
|
<div className={styles.totalsItemAmount}>100.00</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showBalanceDue && (
|
||||||
|
<div
|
||||||
|
className={clsx(styles.totalsItem, styles.totalBottomBordered)}
|
||||||
|
>
|
||||||
|
<div className={styles.totalsItemLabel}>{balanceDueLabel}</div>
|
||||||
|
<div className={styles.totalsItemAmount}>$562.75</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.paragraph}>
|
||||||
|
<div className={styles.paragraphLabel}>Terms & Conditions</div>
|
||||||
|
<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 className={styles.paragraph}>
|
||||||
|
<div className={styles.paragraphLabel}>Statement</div>
|
||||||
|
<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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
import clsx from 'classnames';
|
|
||||||
import styles from './PaperTemplate.module.scss';
|
|
||||||
|
|
||||||
export function PaperTemplate() {
|
|
||||||
return (
|
|
||||||
<div className={styles.root}>
|
|
||||||
<div>
|
|
||||||
<h1 className={styles.bigTitle}>Invoice</h1>
|
|
||||||
|
|
||||||
<div className={styles.logoWrap}>
|
|
||||||
<img
|
|
||||||
alt=""
|
|
||||||
src="https://cdn-development.mercury.com/demo-assets/avatars/mercury-demo-dark.png"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.details}>
|
|
||||||
<div className={styles.detail}>
|
|
||||||
<div className={styles.detailLabel}>Invoice number</div>
|
|
||||||
<div>346D3D40-0001</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.detail}>
|
|
||||||
<div className={styles.detailLabel}>Date of issue</div>
|
|
||||||
<div>September 3, 2024</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.detail}>
|
|
||||||
<div className={styles.detailLabel}>Date due</div>
|
|
||||||
<div>October 3, 2024</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.addressRoot}>
|
|
||||||
<div className={styles.addressBillTo}>
|
|
||||||
<strong>Bigcapital Technology, Inc.</strong> <br />
|
|
||||||
131 Continental Dr Suite 305 Newark,
|
|
||||||
<br />
|
|
||||||
Delaware 19713
|
|
||||||
<br />
|
|
||||||
United States
|
|
||||||
<br />
|
|
||||||
+1 762-339-5634
|
|
||||||
<br />
|
|
||||||
ahmed@bigcapital.app
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.addressFrom}>
|
|
||||||
<strong>Billed To</strong> <br />
|
|
||||||
Bigcapital Technology, Inc. <br />
|
|
||||||
131 Continental Dr Suite 305 Newark,
|
|
||||||
<br />
|
|
||||||
Delaware 19713
|
|
||||||
<br />
|
|
||||||
United States
|
|
||||||
<br />
|
|
||||||
+1 762-339-5634
|
|
||||||
<br />
|
|
||||||
ahmed@bigcapital.app
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table className={styles.table}>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Item</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th className={styles.rate}>Rate</th>
|
|
||||||
<th className={styles.total}>Total</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody className={styles.tableBody}>
|
|
||||||
<tr>
|
|
||||||
<td>Simply dummy text</td>
|
|
||||||
<td>Simply dummy text of the printing and typesetting</td>
|
|
||||||
<td className={styles.rate}>1 X $100,00</td>
|
|
||||||
<td className={styles.total}>$100,00</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div style={{ display: 'flex' }}>
|
|
||||||
<div className={styles.totals}>
|
|
||||||
<div
|
|
||||||
className={clsx(styles.totalsItem, styles.totalBottomGrayBordered)}
|
|
||||||
>
|
|
||||||
<div className={styles.totalsItemLabel}>Sub Total</div>
|
|
||||||
<div className={styles.totalsItemAmount}>630.00</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.totalsItem}>
|
|
||||||
<div className={styles.totalsItemLabel}>Discount</div>
|
|
||||||
<div className={styles.totalsItemAmount}>0.00</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.totalsItem}>
|
|
||||||
<div className={styles.totalsItemLabel}>Sample Tax1 (4.70%)</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 className={clsx(styles.totalsItem, styles.totalBottomBordered)}>
|
|
||||||
<div className={styles.totalsItemLabel}>Total</div>
|
|
||||||
<div className={styles.totalsItemAmount}>$662.75</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.totalsItem}>
|
|
||||||
<div className={styles.totalsItemLabel}>Payment Made</div>
|
|
||||||
<div className={styles.totalsItemAmount}>100.00</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={clsx(styles.totalsItem, styles.totalBottomBordered)}>
|
|
||||||
<div className={styles.totalsItemLabel}>Balance Due</div>
|
|
||||||
<div className={styles.totalsItemAmount}>$562.75</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={styles.paragraph}>
|
|
||||||
<div className={styles.paragraphLabel}>Terms & Conditions</div>
|
|
||||||
<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 className={styles.paragraph}>
|
|
||||||
<div className={styles.paragraphLabel}>Statement</div>
|
|
||||||
<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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export default function ReceiptCustomizeContent() {
|
||||||
|
return <h1>asdasdasd</h1>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import { Drawer, DrawerSuspense } from '@/components';
|
||||||
|
import withDrawers from '@/containers/Drawer/withDrawers';
|
||||||
|
|
||||||
|
const ReceiptCustomizeContent = React.lazy(
|
||||||
|
() => import('./ReceiptCustomizeContent'),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receipt customize drawer.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
function ReceiptCustomizeDrawerRoot({
|
||||||
|
name,
|
||||||
|
// #withDrawer
|
||||||
|
isOpen,
|
||||||
|
payload: {},
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Drawer isOpen={isOpen} name={name} size={'100%'}>
|
||||||
|
<DrawerSuspense>
|
||||||
|
<ReceiptCustomizeContent />
|
||||||
|
</DrawerSuspense>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ReceiptCustomizeDrawer = R.compose(withDrawers())(
|
||||||
|
ReceiptCustomizeDrawerRoot,
|
||||||
|
);
|
||||||
@@ -7,6 +7,11 @@ import {
|
|||||||
NavbarGroup,
|
NavbarGroup,
|
||||||
Intent,
|
Intent,
|
||||||
Alignment,
|
Alignment,
|
||||||
|
Popover,
|
||||||
|
PopoverInteractionKind,
|
||||||
|
Position,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
|
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
@@ -38,6 +43,8 @@ import { SaleReceiptAction, AbilitySubject } from '@/constants/abilityOption';
|
|||||||
|
|
||||||
import { DialogsName } from '@/constants/dialogs';
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
import { compose } from '@/utils';
|
import { compose } from '@/utils';
|
||||||
|
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||||
|
import { DRAWERS } from '@/constants/drawers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receipts actions bar.
|
* Receipts actions bar.
|
||||||
@@ -55,6 +62,9 @@ function ReceiptActionsBar({
|
|||||||
// #withDialogActions
|
// #withDialogActions
|
||||||
openDialog,
|
openDialog,
|
||||||
|
|
||||||
|
// #withDrawerActions
|
||||||
|
openDrawer,
|
||||||
|
|
||||||
// #withSettingsActions
|
// #withSettingsActions
|
||||||
addSetting,
|
addSetting,
|
||||||
}) {
|
}) {
|
||||||
@@ -103,6 +113,10 @@ function ReceiptActionsBar({
|
|||||||
const handlePrintButtonClick = () => {
|
const handlePrintButtonClick = () => {
|
||||||
downloadExportPdf({ resource: 'SaleReceipt' });
|
downloadExportPdf({ resource: 'SaleReceipt' });
|
||||||
};
|
};
|
||||||
|
// Handle customize button click.
|
||||||
|
const handleCustomizeBtnClick = () => {
|
||||||
|
openDrawer(DRAWERS.RECEIPT_CUSTOMIZE);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<DashboardActionsBar>
|
||||||
@@ -173,6 +187,25 @@ function ReceiptActionsBar({
|
|||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
<NavbarGroup align={Alignment.RIGHT}>
|
<NavbarGroup align={Alignment.RIGHT}>
|
||||||
|
<Popover
|
||||||
|
minimal={true}
|
||||||
|
interactionKind={PopoverInteractionKind.CLICK}
|
||||||
|
position={Position.BOTTOM_RIGHT}
|
||||||
|
modifiers={{
|
||||||
|
offset: { offset: '0, 4' },
|
||||||
|
}}
|
||||||
|
content={
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
onClick={handleCustomizeBtnClick}
|
||||||
|
text={'Customize Receipt'}
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button icon={<Icon icon="cog-16" iconSize={16} />} minimal={true} />
|
||||||
|
</Popover>
|
||||||
|
<NavbarDivider />
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon="refresh-16" iconSize={14} />}
|
icon={<Icon icon="refresh-16" iconSize={14} />}
|
||||||
@@ -193,4 +226,5 @@ export default compose(
|
|||||||
receiptsTableSize: receiptSettings?.tableSize,
|
receiptsTableSize: receiptSettings?.tableSize,
|
||||||
})),
|
})),
|
||||||
withDialogActions,
|
withDialogActions,
|
||||||
|
withDrawerActions,
|
||||||
)(ReceiptActionsBar);
|
)(ReceiptActionsBar);
|
||||||
|
|||||||
10
packages/webapp/src/utils/extract-children.ts
Normal file
10
packages/webapp/src/utils/extract-children.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const extractChildren = <T extends React.ReactNode>(
|
||||||
|
children: React.ReactNode,
|
||||||
|
type: React.ElementType,
|
||||||
|
): T[] => {
|
||||||
|
return React.Children.toArray(children).filter(
|
||||||
|
(node) => React.isValidElement(node) && node.type === type,
|
||||||
|
) as T[];
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user