mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
feat: wip invoice customizer
This commit is contained in:
@@ -77,6 +77,7 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-app-polyfill": "^1.0.6",
|
"react-app-polyfill": "^1.0.6",
|
||||||
"react-body-classname": "^1.3.1",
|
"react-body-classname": "^1.3.1",
|
||||||
|
"react-colorful": "^5.6.1",
|
||||||
"react-content-loader": "^6.0.1",
|
"react-content-loader": "^6.0.1",
|
||||||
"react-dev-utils": "^11.0.4",
|
"react-dev-utils": "^11.0.4",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import CategorizeTransactionDrawer from '@/containers/CashFlow/CategorizeTransac
|
|||||||
import ChangeSubscriptionPlanDrawer from '@/containers/Subscriptions/drawers/ChangeSubscriptionPlanDrawer/ChangeSubscriptionPlanDrawer';
|
import ChangeSubscriptionPlanDrawer from '@/containers/Subscriptions/drawers/ChangeSubscriptionPlanDrawer/ChangeSubscriptionPlanDrawer';
|
||||||
|
|
||||||
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.
|
||||||
@@ -65,6 +66,7 @@ export default function DrawersContainer() {
|
|||||||
<TaxRateDetailsDrawer name={DRAWERS.TAX_RATE_DETAILS} />
|
<TaxRateDetailsDrawer name={DRAWERS.TAX_RATE_DETAILS} />
|
||||||
<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} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,5 +24,9 @@ export enum DRAWERS {
|
|||||||
WAREHOUSE_TRANSFER_DETAILS = 'warehouse-transfer-detail-drawer',
|
WAREHOUSE_TRANSFER_DETAILS = 'warehouse-transfer-detail-drawer',
|
||||||
TAX_RATE_DETAILS = 'tax-rate-detail-drawer',
|
TAX_RATE_DETAILS = 'tax-rate-detail-drawer',
|
||||||
CATEGORIZE_TRANSACTION = 'categorize-transaction',
|
CATEGORIZE_TRANSACTION = 'categorize-transaction',
|
||||||
CHANGE_SUBSCARIPTION_PLAN = 'change-subscription-plan'
|
CHANGE_SUBSCARIPTION_PLAN = 'change-subscription-plan',
|
||||||
|
INVOICE_CUSTOMIZE = 'INVOICE_CUSTOMIZE',
|
||||||
|
ESTIMATE_CUSTOMIZE = 'ESTIMATE_CUSTOMIZE',
|
||||||
|
PAYMENT_RECEIPT_CUSTOMIZE = 'PAYMENT_RECEIPT_CUSTOMIZE',
|
||||||
|
RECEIPT_CUSTOMIZE = 'RECEIPT_CUSTOMIZE',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
.field{
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorPicker{
|
||||||
|
background-color: rgb(103, 114, 229);
|
||||||
|
border-radius: 3px;
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import {
|
||||||
|
InputGroup,
|
||||||
|
Popover,
|
||||||
|
PopoverInteractionKind,
|
||||||
|
Position,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { HexColorPicker } from 'react-colorful';
|
||||||
|
import styles from './ColorField.module.scss';
|
||||||
|
|
||||||
|
export function ColorField() {
|
||||||
|
const [color, setColor] = useState('#aabbcc');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
content={<HexColorPicker color={color} onChange={setColor} />}
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
interactionKind={PopoverInteractionKind.CLICK}
|
||||||
|
modifiers={{
|
||||||
|
offset: { offset: '0, 4' },
|
||||||
|
}}
|
||||||
|
minimal
|
||||||
|
>
|
||||||
|
<InputGroup
|
||||||
|
leftElement={<div className={styles.colorPicker}></div>}
|
||||||
|
className={styles.field}
|
||||||
|
/>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { ColorField } from './ColorField';
|
||||||
|
|
||||||
|
interface FColorFieldProps {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FColorField({ name }: FColorFieldProps) {
|
||||||
|
return <ColorField />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Box, Group } from '@/components';
|
||||||
|
import { InvoiceCustomizePreview } from './InvoiceCustomizePreview';
|
||||||
|
import { InvoiceCustomizeFields } from './InvoiceCustomizeFields';
|
||||||
|
import { InvoiceCustomizeForm } from './InvoiceCustomizerForm';
|
||||||
|
import { Classes } from '@blueprintjs/core';
|
||||||
|
import { InvoiceCustomizeTabsControllerProvider } from './InvoiceCustomizeTabsController';
|
||||||
|
|
||||||
|
export default function InvoiceCustomizeContent() {
|
||||||
|
return (
|
||||||
|
<Box className={Classes.DRAWER_BODY}>
|
||||||
|
<InvoiceCustomizeForm>
|
||||||
|
<Group spacing={0} align="flex-start">
|
||||||
|
<InvoiceCustomizeTabsControllerProvider>
|
||||||
|
<InvoiceCustomizeFields />
|
||||||
|
<InvoiceCustomizePreview />
|
||||||
|
</InvoiceCustomizeTabsControllerProvider>
|
||||||
|
</Group>
|
||||||
|
</InvoiceCustomizeForm>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
|
import { Drawer, DrawerSuspense } from '@/components';
|
||||||
|
import withDrawers from '@/containers/Drawer/withDrawers';
|
||||||
|
|
||||||
|
const InvoiceCustomizeContent = React.lazy(
|
||||||
|
() => import('./InvoiceCustomizeContent'),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refund credit note detail.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function InvoiceCustomizeDrawerRoot({
|
||||||
|
name,
|
||||||
|
// #withDrawer
|
||||||
|
isOpen,
|
||||||
|
payload: {},
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
isOpen={isOpen}
|
||||||
|
name={name}
|
||||||
|
size={'100%'}
|
||||||
|
>
|
||||||
|
<DrawerSuspense>
|
||||||
|
<InvoiceCustomizeContent />
|
||||||
|
</DrawerSuspense>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InvoiceCustomizeDrawer = R.compose(withDrawers())(
|
||||||
|
InvoiceCustomizeDrawerRoot,
|
||||||
|
);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.root {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainFields{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Box, Group } from '@/components';
|
||||||
|
import { InvoiceCustomizeHeader } from './InvoiceCustomizeHeader';
|
||||||
|
import { InvoiceCustomizeTabs } from './InvoiceCustomizeTabs';
|
||||||
|
import styles from './InvoiceCustomizeFields.module.scss';
|
||||||
|
import { InvoiceCustomizeGeneralField } from './InvoiceCustomizeGeneralFields';
|
||||||
|
import { useInvoiceCustomizeTabsController } from './InvoiceCustomizeTabsController';
|
||||||
|
|
||||||
|
export function InvoiceCustomizeFields() {
|
||||||
|
return (
|
||||||
|
<Group spacing={0} align={'stretch'} className={styles.root}>
|
||||||
|
<InvoiceCustomizeTabs />
|
||||||
|
<InvoiceCustomizeFieldsMain />
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InvoiceCustomizeFieldsMain() {
|
||||||
|
const { currentTabId } = useInvoiceCustomizeTabsController();
|
||||||
|
return (
|
||||||
|
<Box className={styles.mainFields}>
|
||||||
|
<InvoiceCustomizeHeader label={'Customize'} />
|
||||||
|
|
||||||
|
{currentTabId === 'general' && <InvoiceCustomizeGeneralField />}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Box, FFormGroup } from '@/components';
|
||||||
|
import { FColorField } from './FColorField';
|
||||||
|
|
||||||
|
export function InvoiceCustomizeGeneralField() {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<FFormGroup name={'primaryColor'} label={'Primary Color'} inline>
|
||||||
|
<FColorField name={'primaryColor'} />
|
||||||
|
</FFormGroup>
|
||||||
|
|
||||||
|
<FFormGroup name={'secondaryColor'} label={'Secondary Color'} inline>
|
||||||
|
<FColorField name={'secondaryColor'} />
|
||||||
|
</FFormGroup>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
.root {
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: 0 1px 0 rgba(17, 20, 24, .15);
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
min-height: 40px;
|
||||||
|
padding: 5px 5px 5px 20px;
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 19px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { Group, Icon } from '@/components';
|
||||||
|
import styles from './InvoiceCustomizeHeader.module.scss';
|
||||||
|
import { Button, Classes } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
interface InvoiceCustomizeHeaderProps {
|
||||||
|
label?: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
closeButton?: boolean;
|
||||||
|
onClose?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InvoiceCustomizeHeader({
|
||||||
|
label,
|
||||||
|
closeButton,
|
||||||
|
onClose,
|
||||||
|
children,
|
||||||
|
}: InvoiceCustomizeHeaderProps) {
|
||||||
|
const handleClose = () => {
|
||||||
|
onClose && onClose();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Group className={styles.root}>
|
||||||
|
{label && <h1 className={styles.title}>{label}</h1>}
|
||||||
|
{closeButton && (
|
||||||
|
<Button
|
||||||
|
aria-label="Close"
|
||||||
|
className={Classes.DIALOG_CLOSE_BUTTON}
|
||||||
|
icon={<Icon icon={'smallCross'} color={'#000'} />}
|
||||||
|
minimal={true}
|
||||||
|
onClick={handleClose}
|
||||||
|
style={{ marginLeft: 'auto' }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { Stack } from '@/components';
|
||||||
|
import { InvoiceCustomizeHeader } from './InvoiceCustomizeHeader';
|
||||||
|
import { InvoiceCustomizePreviewContent } from './InvoiceCustomizePreviewContent';
|
||||||
|
|
||||||
|
export function InvoiceCustomizePreview() {
|
||||||
|
return (
|
||||||
|
<Stack spacing={0} style={{ borderLeft: '1px solid #D9D9D9' }}>
|
||||||
|
<InvoiceCustomizeHeader label={'Preview'} closeButton />
|
||||||
|
<InvoiceCustomizePreviewContent />
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Box } from '@/components';
|
||||||
|
import { PaperTemplate } from './PaperTemplate';
|
||||||
|
|
||||||
|
export function InvoiceCustomizePreviewContent() {
|
||||||
|
return (
|
||||||
|
<Box style={{ padding: 20, backgroundColor: '#F5F5F5' }}>
|
||||||
|
<PaperTemplate />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
.root {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 165px;
|
||||||
|
max-width: 185px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content{
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsList{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Box } from '@/components';
|
||||||
|
import { Tab, Tabs } from '@blueprintjs/core';
|
||||||
|
import { InvoiceCustomizeHeader } from './InvoiceCustomizeHeader';
|
||||||
|
import styles from './InvoiceCustomizeTabs.module.scss';
|
||||||
|
import {
|
||||||
|
InvoiceCustomizeTabsEnum,
|
||||||
|
useInvoiceCustomizeTabsController,
|
||||||
|
} from './InvoiceCustomizeTabsController';
|
||||||
|
|
||||||
|
export function InvoiceCustomizeTabs() {
|
||||||
|
const { setCurrentTabId } = useInvoiceCustomizeTabsController();
|
||||||
|
|
||||||
|
const handleChange = (value: InvoiceCustomizeTabsEnum) => {
|
||||||
|
setCurrentTabId(value);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Box className={styles.root}>
|
||||||
|
<InvoiceCustomizeHeader label={''} />
|
||||||
|
|
||||||
|
<Box className={styles.content}>
|
||||||
|
<Tabs vertical fill onChange={handleChange} className={styles.tabsList}>
|
||||||
|
<Tab id="general" title="General" />
|
||||||
|
<Tab id="content" title="Content" />
|
||||||
|
<Tab id="total" title="Total" />
|
||||||
|
</Tabs>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import React, { createContext, useContext, useState } from 'react';
|
||||||
|
|
||||||
|
export enum InvoiceCustomizeTabsEnum {
|
||||||
|
General = 'general',
|
||||||
|
Items = 'items',
|
||||||
|
Totals = 'totals'
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_TAB_ID = InvoiceCustomizeTabsEnum.General;
|
||||||
|
|
||||||
|
interface InvoiceCustomizeTabsControllerValue {
|
||||||
|
currentTabId: InvoiceCustomizeTabsEnum;
|
||||||
|
setCurrentTabId: React.Dispatch<
|
||||||
|
React.SetStateAction<InvoiceCustomizeTabsEnum>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InvoiceCustomizeTabsController = createContext(
|
||||||
|
{} as InvoiceCustomizeTabsControllerValue,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const useInvoiceCustomizeTabsController = () => {
|
||||||
|
return useContext(InvoiceCustomizeTabsController);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface InvoiceCustomizeTabsControllerProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InvoiceCustomizeTabsControllerProvider = ({
|
||||||
|
children,
|
||||||
|
}: InvoiceCustomizeTabsControllerProps) => {
|
||||||
|
const [currentTabId, setCurrentTabId] =
|
||||||
|
useState<InvoiceCustomizeTabsEnum>(DEFAULT_TAB_ID);
|
||||||
|
|
||||||
|
const value = {
|
||||||
|
currentTabId,
|
||||||
|
setCurrentTabId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InvoiceCustomizeTabsController.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</InvoiceCustomizeTabsController.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Formik, Form } from 'formik';
|
||||||
|
import * as Yup from 'yup';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
invoiceNumber: Yup.string().required('Invoice number is required'),
|
||||||
|
customerName: Yup.string().required('Customer name is required'),
|
||||||
|
amount: Yup.number()
|
||||||
|
.required('Amount is required')
|
||||||
|
.positive('Amount must be positive'),
|
||||||
|
});
|
||||||
|
|
||||||
|
interface InvoiceCustomizeFormProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InvoiceCustomizeForm({ children }: InvoiceCustomizeFormProps) {
|
||||||
|
return (
|
||||||
|
<Formik
|
||||||
|
initialValues={{ invoiceNumber: '', customerName: '', amount: '' }}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
onSubmit={(values) => {}}
|
||||||
|
>
|
||||||
|
<Form>{children}</Form>
|
||||||
|
</Formik>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
|
||||||
|
.root {
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: inset 0 4px 0px 0 #002762, 0 10px 15px rgba(0, 0, 0, 0.15);
|
||||||
|
padding: 22px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bigTitle{
|
||||||
|
font-size: 60px;
|
||||||
|
margin: 0;
|
||||||
|
LINE-HEIGHT: 1;
|
||||||
|
MARGIN-BOTTOM: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.detail {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.detailLabel {
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addressRoot{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addressBillTo{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addressFrom{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table :global {
|
||||||
|
margin-top: 40px;
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
thead th{
|
||||||
|
font-weight: 400;
|
||||||
|
border-bottom: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody{
|
||||||
|
|
||||||
|
tr {
|
||||||
|
|
||||||
|
}
|
||||||
|
td{
|
||||||
|
border: 1px solid #F6F6F6;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.totals{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.totalsItem{
|
||||||
|
display: flex;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
.totalsItemLabel{
|
||||||
|
min-width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logoWrap{
|
||||||
|
height: 120px;
|
||||||
|
width: 120px;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 20px;
|
||||||
|
|
||||||
|
img{
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.footer{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.paragraph{
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paragraphLabel{
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
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}>
|
||||||
|
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 className={styles.addressFrom}>
|
||||||
|
Billed To <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>Rate</th>
|
||||||
|
<th>Total</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Simply dummy text</td>
|
||||||
|
<td>Simply dummy text of the printing and typesetting</td>
|
||||||
|
<td>1 X $100,00</td>
|
||||||
|
<td>$100,00</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<div className={styles.totals}>
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>Sub Total</div>
|
||||||
|
<div>630.00</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>Discount</div>
|
||||||
|
<div>0.00</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>Sample Tax1 (4.70%)</div>
|
||||||
|
<div>11.75</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>Sample Tax2 (7.00%)</div>
|
||||||
|
<div>21.00</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>Total</div>
|
||||||
|
<div>$662.75</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>Payment Made</div>
|
||||||
|
<div>100.00</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.totalsItem}>
|
||||||
|
<div className={styles.totalsItemLabel}>Balance Due</div>
|
||||||
|
<div className={styles.totalsItemLabel}>$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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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';
|
||||||
import {
|
import {
|
||||||
@@ -32,6 +37,8 @@ import withSettingsActions from '@/containers/Settings/withSettingsActions';
|
|||||||
import { compose } from '@/utils';
|
import { compose } from '@/utils';
|
||||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
import { DialogsName } from '@/constants/dialogs';
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||||
|
import { DRAWERS } from '@/constants/drawers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoices table actions bar.
|
* Invoices table actions bar.
|
||||||
@@ -51,6 +58,9 @@ function InvoiceActionsBar({
|
|||||||
|
|
||||||
// #withDialogsActions
|
// #withDialogsActions
|
||||||
openDialog,
|
openDialog,
|
||||||
|
|
||||||
|
// #withDrawerActions
|
||||||
|
openDrawer,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
@@ -97,6 +107,11 @@ function InvoiceActionsBar({
|
|||||||
downloadExportPdf({ resource: 'SaleInvoice' });
|
downloadExportPdf({ resource: 'SaleInvoice' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handles the invoice customize button click.
|
||||||
|
const handleCustomizeBtnClick = () => {
|
||||||
|
openDrawer(DRAWERS.INVOICE_CUSTOMIZE);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<DashboardActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
@@ -164,6 +179,25 @@ function InvoiceActionsBar({
|
|||||||
<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 Invoice'}
|
||||||
|
/>
|
||||||
|
</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} />}
|
||||||
@@ -184,4 +218,5 @@ export default compose(
|
|||||||
invoicesTableSize: invoiceSettings?.tableSize,
|
invoicesTableSize: invoiceSettings?.tableSize,
|
||||||
})),
|
})),
|
||||||
withDialogActions,
|
withDialogActions,
|
||||||
|
withDrawerActions,
|
||||||
)(InvoiceActionsBar);
|
)(InvoiceActionsBar);
|
||||||
|
|||||||
13
pnpm-lock.yaml
generated
13
pnpm-lock.yaml
generated
@@ -687,6 +687,9 @@ importers:
|
|||||||
react-body-classname:
|
react-body-classname:
|
||||||
specifier: ^1.3.1
|
specifier: ^1.3.1
|
||||||
version: 1.3.1(react@18.3.1)
|
version: 1.3.1(react@18.3.1)
|
||||||
|
react-colorful:
|
||||||
|
specifier: ^5.6.1
|
||||||
|
version: 5.6.1(react-dom@18.3.1)(react@18.3.1)
|
||||||
react-content-loader:
|
react-content-loader:
|
||||||
specifier: ^6.0.1
|
specifier: ^6.0.1
|
||||||
version: 6.2.1(react@18.3.1)
|
version: 6.2.1(react@18.3.1)
|
||||||
@@ -21277,6 +21280,16 @@ packages:
|
|||||||
- react
|
- react
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-colorful@5.6.1(react-dom@18.3.1)(react@18.3.1):
|
||||||
|
resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8.0'
|
||||||
|
react-dom: '>=16.8.0'
|
||||||
|
dependencies:
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-content-loader@6.2.1(react@18.3.1):
|
/react-content-loader@6.2.1(react@18.3.1):
|
||||||
resolution: {integrity: sha512-6ONbFX+Hi3SHuP66JB8CPvJn372pj+qwltJV0J8z/8MFrq98I1cbFdZuhDWeQXu3CFxiiDTXJn7DFxx2ZvrO7g==}
|
resolution: {integrity: sha512-6ONbFX+Hi3SHuP66JB8CPvJn372pj+qwltJV0J8z/8MFrq98I1cbFdZuhDWeQXu3CFxiiDTXJn7DFxx2ZvrO7g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|||||||
Reference in New Issue
Block a user