wip
This commit is contained in:
@@ -12,7 +12,7 @@ import CustomerDetailsDrawer from '@/containers/Drawers/CustomerDetailsDrawer';
|
|||||||
import VendorDetailsDrawer from '@/containers/Drawers/VendorDetailsDrawer';
|
import VendorDetailsDrawer from '@/containers/Drawers/VendorDetailsDrawer';
|
||||||
import InventoryAdjustmentDetailDrawer from '@/containers/Drawers/InventoryAdjustmentDetailDrawer';
|
import InventoryAdjustmentDetailDrawer from '@/containers/Drawers/InventoryAdjustmentDetailDrawer';
|
||||||
import CashflowTransactionDetailDrawer from '@/containers/Drawers/CashflowTransactionDetailDrawer';
|
import CashflowTransactionDetailDrawer from '@/containers/Drawers/CashflowTransactionDetailDrawer';
|
||||||
import QuickCreateCustomerDrawer from '@/containers/Drawers/QuickCreateCustomerDrawer';
|
// import QuickCreateCustomerDrawer from '@/containers/Drawers/QuickCreateCustomerDrawer';
|
||||||
import QuickCreateItemDrawer from '@/containers/Drawers/QuickCreateItemDrawer';
|
import QuickCreateItemDrawer from '@/containers/Drawers/QuickCreateItemDrawer';
|
||||||
import QuickWriteVendorDrawer from '@/containers/Drawers/QuickWriteVendorDrawer';
|
import QuickWriteVendorDrawer from '@/containers/Drawers/QuickWriteVendorDrawer';
|
||||||
import CreditNoteDetailDrawer from '@/containers/Drawers/CreditNoteDetailDrawer';
|
import CreditNoteDetailDrawer from '@/containers/Drawers/CreditNoteDetailDrawer';
|
||||||
@@ -59,7 +59,7 @@ export default function DrawersContainer() {
|
|||||||
<CashflowTransactionDetailDrawer
|
<CashflowTransactionDetailDrawer
|
||||||
name={DRAWERS.CASHFLOW_TRNASACTION_DETAILS}
|
name={DRAWERS.CASHFLOW_TRNASACTION_DETAILS}
|
||||||
/>
|
/>
|
||||||
<QuickCreateCustomerDrawer name={DRAWERS.QUICK_CREATE_CUSTOMER} />
|
{/* <QuickCreateCustomerDrawer name={DRAWERS.QUICK_CREATE_CUSTOMER} /> */}
|
||||||
<QuickCreateItemDrawer name={DRAWERS.QUICK_CREATE_ITEM} />
|
<QuickCreateItemDrawer name={DRAWERS.QUICK_CREATE_ITEM} />
|
||||||
<QuickWriteVendorDrawer name={DRAWERS.QUICK_WRITE_VENDOR} />
|
<QuickWriteVendorDrawer name={DRAWERS.QUICK_WRITE_VENDOR} />
|
||||||
<CreditNoteDetailDrawer name={DRAWERS.CREDIT_NOTE_DETAILS} />
|
<CreditNoteDetailDrawer name={DRAWERS.CREDIT_NOTE_DETAILS} />
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import { FSelect } from '../Forms';
|
|||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
|
|
||||||
export type DisplayNameListItem = { label: string };
|
export type DisplayNameListItem = { label: string };
|
||||||
|
type DisplayNameFormat = {
|
||||||
|
format: string;
|
||||||
|
values: Array<string | undefined>;
|
||||||
|
required: number[];
|
||||||
|
};
|
||||||
|
|
||||||
export interface DisplayNameListProps
|
export interface DisplayNameListProps
|
||||||
extends Omit<
|
extends Omit<
|
||||||
@@ -11,6 +16,47 @@ export interface DisplayNameListProps
|
|||||||
'items' | 'valueAccessor' | 'textAccessor' | 'labelAccessor'
|
'items' | 'valueAccessor' | 'textAccessor' | 'labelAccessor'
|
||||||
> {}
|
> {}
|
||||||
|
|
||||||
|
function useDisplayNameFormatOptions(
|
||||||
|
salutation?: string,
|
||||||
|
firstName?: string,
|
||||||
|
lastName?: string,
|
||||||
|
companyName?: string,
|
||||||
|
): DisplayNameListItem[] {
|
||||||
|
return useMemo(() => {
|
||||||
|
const formats: DisplayNameFormat[] = [
|
||||||
|
{
|
||||||
|
format: '{1} {2} {3}',
|
||||||
|
values: [salutation, firstName, lastName],
|
||||||
|
required: [1],
|
||||||
|
},
|
||||||
|
{ format: '{1} {2}', values: [firstName, lastName], required: [] },
|
||||||
|
{ format: '{1}, {2}', values: [firstName, lastName], required: [1, 2] },
|
||||||
|
{ format: '{1}', values: [companyName], required: [1] },
|
||||||
|
];
|
||||||
|
|
||||||
|
return formats
|
||||||
|
.filter(
|
||||||
|
(format) =>
|
||||||
|
!format.values.some((value, index) => {
|
||||||
|
return !value && format.required.indexOf(index + 1) !== -1;
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.map((formatOption) => {
|
||||||
|
const { format, values } = formatOption;
|
||||||
|
let label = format;
|
||||||
|
|
||||||
|
values.forEach((value, index) => {
|
||||||
|
const replaceWith = value || '';
|
||||||
|
label = label.replace(`{${index + 1}}`, replaceWith).trim();
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
label: label.replace(/\s+/g, ' ').replace(/\s+,/g, ',').trim(),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(({ label }) => Boolean(label));
|
||||||
|
}, [salutation, firstName, lastName, companyName]);
|
||||||
|
}
|
||||||
|
|
||||||
export function DisplayNameList({ ...restProps }: DisplayNameListProps) {
|
export function DisplayNameList({ ...restProps }: DisplayNameListProps) {
|
||||||
const {
|
const {
|
||||||
values: {
|
values: {
|
||||||
@@ -21,40 +67,11 @@ export function DisplayNameList({ ...restProps }: DisplayNameListProps) {
|
|||||||
},
|
},
|
||||||
} = useFormikContext<any>();
|
} = useFormikContext<any>();
|
||||||
|
|
||||||
const formats = useMemo(
|
const formatOptions = useDisplayNameFormatOptions(
|
||||||
() => [
|
salutation,
|
||||||
{
|
firstName,
|
||||||
format: '{1} {2} {3}',
|
lastName,
|
||||||
values: [salutation, firstName, lastName],
|
companyName,
|
||||||
required: [1],
|
|
||||||
},
|
|
||||||
{ format: '{1} {2}', values: [firstName, lastName], required: [] },
|
|
||||||
{ format: '{1}, {2}', values: [firstName, lastName], required: [1, 2] },
|
|
||||||
{ format: '{1}', values: [companyName], required: [1] },
|
|
||||||
],
|
|
||||||
[firstName, lastName, companyName, salutation],
|
|
||||||
);
|
|
||||||
|
|
||||||
const formatOptions: DisplayNameListItem[] = useMemo(
|
|
||||||
() =>
|
|
||||||
formats
|
|
||||||
.filter(
|
|
||||||
(format) =>
|
|
||||||
!format.values.some((value, index) => {
|
|
||||||
return !value && format.required.indexOf(index + 1) !== -1;
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.map((formatOption) => {
|
|
||||||
const { format, values } = formatOption;
|
|
||||||
let label = format;
|
|
||||||
|
|
||||||
values.forEach((value, index) => {
|
|
||||||
const replaceWith = value || '';
|
|
||||||
label = label.replace(`{${index + 1}}`, replaceWith).trim();
|
|
||||||
});
|
|
||||||
return { label: label.replace(/\s+/g, ' ') };
|
|
||||||
}),
|
|
||||||
[formats],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -62,6 +79,7 @@ export function DisplayNameList({ ...restProps }: DisplayNameListProps) {
|
|||||||
items={formatOptions}
|
items={formatOptions}
|
||||||
valueAccessor={'label'}
|
valueAccessor={'label'}
|
||||||
textAccessor={'label'}
|
textAccessor={'label'}
|
||||||
|
labelAccessor={'_label'}
|
||||||
placeholder={intl.get('select_display_name_as')}
|
placeholder={intl.get('select_display_name_as')}
|
||||||
filterable={false}
|
filterable={false}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
FInputGroup,
|
FInputGroup,
|
||||||
FTextArea,
|
FTextArea,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import CustomerFormSectionTitle from './CustomerFormSectionTitle';
|
import { CustomerFormSectionTitle } from './CustomerFormSectionTitle';
|
||||||
|
|
||||||
export default function CustomerBillingAddress() {
|
export function CustomerBillingAddress() {
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box data-section-id="billingAddress">
|
||||||
<CustomerFormSectionTitle>
|
<CustomerFormSectionTitle>
|
||||||
<T id={'billing_address'} />
|
<T id={'billing_address'} />
|
||||||
</CustomerFormSectionTitle>
|
</CustomerFormSectionTitle>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import {
|
import {
|
||||||
@@ -11,40 +10,32 @@ import {
|
|||||||
Menu,
|
Menu,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import classNames from 'classnames';
|
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
import { Group, Icon, FormattedMessage as T } from '@/components';
|
import { Group, Icon, FormattedMessage as T } from '@/components';
|
||||||
import { CLASSES } from '@/constants/classes';
|
|
||||||
import { useCustomerFormContext } from './CustomerFormProvider';
|
import { useCustomerFormContext } from './CustomerFormProvider';
|
||||||
import { safeInvoke } from '@/utils';
|
|
||||||
|
|
||||||
/**
|
export function CustomerFloatingActions() {
|
||||||
* Customer floating actions bar.
|
|
||||||
*/
|
|
||||||
export function CustomerFloatingActions({ onCancel }) {
|
|
||||||
// Customer form context.
|
// Customer form context.
|
||||||
const { isNewMode, setSubmitPayload } = useCustomerFormContext();
|
const { isNewMode, setSubmitPayload } = useCustomerFormContext() as {
|
||||||
|
isNewMode: boolean;
|
||||||
|
setSubmitPayload: (payload: { noRedirect: boolean }) => void;
|
||||||
|
};
|
||||||
|
|
||||||
// Formik context.
|
// Formik context.
|
||||||
const { resetForm, submitForm, isSubmitting } = useFormikContext();
|
const { resetForm, submitForm, isSubmitting } = useFormikContext();
|
||||||
|
|
||||||
// Handle submit button click.
|
// Handle submit button click.
|
||||||
const handleSubmitBtnClick = (event) => {
|
const handleSubmitBtnClick = (_event: React.MouseEvent<HTMLElement>) => {
|
||||||
setSubmitPayload({ noRedirect: false });
|
setSubmitPayload({ noRedirect: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle cancel button click.
|
|
||||||
const handleCancelBtnClick = (event) => {
|
|
||||||
safeInvoke(onCancel, event);
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle clear button clicl.
|
// handle clear button clicl.
|
||||||
const handleClearBtnClick = (event) => {
|
const handleClearBtnClick = (_event: React.MouseEvent<HTMLElement>) => {
|
||||||
resetForm();
|
resetForm();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle submit & new button click.
|
// Handle submit & new button click.
|
||||||
const handleSubmitAndNewClick = (event) => {
|
const handleSubmitAndNewClick = (_event: React.MouseEvent<HTMLElement>) => {
|
||||||
submitForm();
|
submitForm();
|
||||||
setSubmitPayload({ noRedirect: true });
|
setSubmitPayload({ noRedirect: true });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
|
||||||
import { CustomerFormProvider } from './CustomerFormProvider';
|
|
||||||
import CustomerFormFormik from './CustomerFormFormik';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstracted customer form.
|
|
||||||
*/
|
|
||||||
export default function CustomerForm({ customerId }) {
|
|
||||||
return (
|
|
||||||
<CustomerFormProvider customerId={customerId}>
|
|
||||||
<CustomerFormFormik />
|
|
||||||
</CustomerFormProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
+10
-9
@@ -14,18 +14,15 @@ import {
|
|||||||
Icon,
|
Icon,
|
||||||
Stack,
|
Stack,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import CustomerTypeRadioField from './CustomerTypeRadioField';
|
import { CustomerTypeRadioField } from './CustomerTypeRadioField';
|
||||||
import CustomerFormSectionTitle from './CustomerFormSectionTitle';
|
import { CustomerFormSectionTitle } from './CustomerFormSectionTitle';
|
||||||
import { useAutofocus } from '@/hooks';
|
import { useAutofocus } from '@/hooks';
|
||||||
|
|
||||||
/**
|
export function CustomerFormBasicSection({}) {
|
||||||
* Customer form primary section.
|
|
||||||
*/
|
|
||||||
export default function CustomerFormPrimarySection({}) {
|
|
||||||
const firstNameFieldRef = useAutofocus();
|
const firstNameFieldRef = useAutofocus();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box data-section-id="primary">
|
||||||
<CustomerFormSectionTitle>Customer details</CustomerFormSectionTitle>
|
<CustomerFormSectionTitle>Customer details</CustomerFormSectionTitle>
|
||||||
|
|
||||||
{/**-----------Customer type. -----------*/}
|
{/**-----------Customer type. -----------*/}
|
||||||
@@ -102,7 +99,7 @@ export default function CustomerFormPrimarySection({}) {
|
|||||||
<FFormGroup
|
<FFormGroup
|
||||||
name={'email'}
|
name={'email'}
|
||||||
label={<T id={'vendor_email'} />}
|
label={<T id={'vendor_email'} />}
|
||||||
inline={true}
|
inline
|
||||||
>
|
>
|
||||||
<FInputGroup
|
<FInputGroup
|
||||||
name={'email'}
|
name={'email'}
|
||||||
@@ -118,7 +115,11 @@ export default function CustomerFormPrimarySection({}) {
|
|||||||
inline={true}
|
inline={true}
|
||||||
>
|
>
|
||||||
<Stack spacing={10}>
|
<Stack spacing={10}>
|
||||||
<FInputGroup name={'work_phone'} placeholder={intl.get('work')} />
|
<FInputGroup
|
||||||
|
name={'work_phone'}
|
||||||
|
placeholder={intl.get('work')}
|
||||||
|
leftIcon="phone"
|
||||||
|
/>
|
||||||
<FInputGroup
|
<FInputGroup
|
||||||
name={'personal_phone'}
|
name={'personal_phone'}
|
||||||
placeholder={intl.get('mobile')}
|
placeholder={intl.get('mobile')}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { Tab } from "@blueprintjs/core";
|
||||||
|
import { Card, Group } from "@/components";
|
||||||
|
import { Tabs } from "@blueprintjs/core";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { CustomerFloatingActions } from "./CustomerFloatingActions";
|
||||||
|
import { CustomerFormSections } from "./CustomerFormFields";
|
||||||
|
|
||||||
|
const customerFormSections = {
|
||||||
|
primary: 'primary',
|
||||||
|
financial: 'financial',
|
||||||
|
billingAddress: 'billingAddress',
|
||||||
|
shippingAddress: 'shippingAddress',
|
||||||
|
notes: 'notes',
|
||||||
|
};
|
||||||
|
export function CustomerFormContent() {
|
||||||
|
const [selectedTabId, setSelectedTabId] = useState(customerFormSections.primary);
|
||||||
|
|
||||||
|
const handleTabChange = (tabId: string) => {
|
||||||
|
const sectionId = String(tabId);
|
||||||
|
setSelectedTabId(sectionId);
|
||||||
|
|
||||||
|
const section = document.querySelector(
|
||||||
|
`[data-section-id="${sectionId}"]`,
|
||||||
|
);
|
||||||
|
if (section) {
|
||||||
|
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className={css`padding-bottom: 0 !important;`}>
|
||||||
|
<Group verticalAlign={'top'} alignItems={'flex-start'} flexWrap={'nowrap'}>
|
||||||
|
<Tabs
|
||||||
|
vertical
|
||||||
|
large
|
||||||
|
selectedTabId={selectedTabId}
|
||||||
|
onChange={handleTabChange}
|
||||||
|
className={css`position: sticky; top: 20px; .bp4-large > .bp4-tab{font-size: 14px;} `}
|
||||||
|
>
|
||||||
|
<Tab id={customerFormSections.primary} title={'Basic'} />
|
||||||
|
<Tab id={customerFormSections.financial} title={'Financial'} />
|
||||||
|
<Tab id={customerFormSections.billingAddress} title={'Billing address'} />
|
||||||
|
<Tab id={customerFormSections.shippingAddress} title={'Ship address'} />
|
||||||
|
<Tab id={customerFormSections.notes} title={'Notes'} />
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
<CustomerFormSections />
|
||||||
|
</Group>
|
||||||
|
<CustomerFloatingActions />
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Divider } from '@blueprintjs/core';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { Box } from '@/components';
|
||||||
|
|
||||||
|
import { CustomerFormBasicSection } from './CustomerFormBasicSection';
|
||||||
|
import { CustomerFormFinancialSection } from './CustomerFormFinancialSection';
|
||||||
|
import { CustomerBillingAddress } from './CustomerBillingAddress';
|
||||||
|
import { CustomerShippingAddress } from './CustomerShippingAddress';
|
||||||
|
import { CustomerFormNotesSection } from './CustomerFormNotesSection';
|
||||||
|
|
||||||
|
const customerFormSectionDividerClass = css`
|
||||||
|
margin: 20px 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function CustomerFormSections() {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<CustomerFormBasicSection />
|
||||||
|
<Divider className={customerFormSectionDividerClass} />
|
||||||
|
|
||||||
|
<CustomerFormFinancialSection />
|
||||||
|
<Divider className={customerFormSectionDividerClass} />
|
||||||
|
|
||||||
|
<CustomerBillingAddress />
|
||||||
|
<Divider className={customerFormSectionDividerClass} />
|
||||||
|
|
||||||
|
<CustomerShippingAddress />
|
||||||
|
<Divider className={customerFormSectionDividerClass} />
|
||||||
|
|
||||||
|
<CustomerFormNotesSection />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
+13
-36
@@ -1,4 +1,3 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
|
import { FormGroup, Position, ControlGroup } from '@blueprintjs/core';
|
||||||
import { ErrorMessage, useFormikContext } from 'formik';
|
import { ErrorMessage, useFormikContext } from 'formik';
|
||||||
@@ -10,8 +9,6 @@ import {
|
|||||||
CurrencySelectList,
|
CurrencySelectList,
|
||||||
BranchSelect,
|
BranchSelect,
|
||||||
FeatureCan,
|
FeatureCan,
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
FMoneyInputGroup,
|
FMoneyInputGroup,
|
||||||
ExchangeRateInputGroup,
|
ExchangeRateInputGroup,
|
||||||
FDateInput,
|
FDateInput,
|
||||||
@@ -24,23 +21,20 @@ import {
|
|||||||
useSetPrimaryBranchToForm,
|
useSetPrimaryBranchToForm,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { useCurrentOrganization } from '@/hooks/state';
|
import { useCurrentOrganization } from '@/hooks/state';
|
||||||
import CustomerFormSectionTitle from './CustomerFormSectionTitle';
|
import { CustomerFormSectionTitle } from './CustomerFormSectionTitle';
|
||||||
|
|
||||||
/**
|
export function CustomerFormFinancialSection() {
|
||||||
* Customer financial panel.
|
|
||||||
*/
|
|
||||||
export default function CustomerFinancialPanel() {
|
|
||||||
const { currencies, customerId, branches } = useCustomerFormContext();
|
const { currencies, customerId, branches } = useCustomerFormContext();
|
||||||
|
|
||||||
// Sets the primary branch to form.
|
// Sets the primary branch to form.
|
||||||
useSetPrimaryBranchToForm();
|
useSetPrimaryBranchToForm();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box data-section-id="financial">
|
||||||
<CustomerFormSectionTitle>
|
<CustomerFormSectionTitle>
|
||||||
<T id={'financial'} />
|
<T id={'financial'} />
|
||||||
</CustomerFormSectionTitle>
|
</CustomerFormSectionTitle>
|
||||||
{/*------------ Currency -----------*/}
|
|
||||||
<FFormGroup
|
<FFormGroup
|
||||||
name={'currency_code'}
|
name={'currency_code'}
|
||||||
label={<T id={'currency'} />}
|
label={<T id={'currency'} />}
|
||||||
@@ -55,16 +49,10 @@ export default function CustomerFinancialPanel() {
|
|||||||
/>
|
/>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
{/*------------ Opening balance -----------*/}
|
|
||||||
<CustomerOpeningBalanceField />
|
<CustomerOpeningBalanceField />
|
||||||
|
|
||||||
{/*------ Opening Balance Exchange Rate -----*/}
|
|
||||||
<CustomerOpeningBalanceExchangeRateField />
|
<CustomerOpeningBalanceExchangeRateField />
|
||||||
|
|
||||||
{/*------------ Opening balance at -----------*/}
|
|
||||||
<CustomerOpeningBalanceAtField />
|
<CustomerOpeningBalanceAtField />
|
||||||
|
|
||||||
{/*------------ Opening branch -----------*/}
|
|
||||||
<FeatureCan feature={Features.Branches}>
|
<FeatureCan feature={Features.Branches}>
|
||||||
<FFormGroup
|
<FFormGroup
|
||||||
label={<T id={'customer.label.opening_branch'} />}
|
label={<T id={'customer.label.opening_branch'} />}
|
||||||
@@ -94,7 +82,7 @@ function CustomerOpeningBalanceAtField() {
|
|||||||
if (customerId) return null;
|
if (customerId) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormGroup
|
<FFormGroup
|
||||||
name={'opening_balance_at'}
|
name={'opening_balance_at'}
|
||||||
label={<T id={'opening_balance_at'} />}
|
label={<T id={'opening_balance_at'} />}
|
||||||
inline
|
inline
|
||||||
@@ -109,14 +97,10 @@ function CustomerOpeningBalanceAtField() {
|
|||||||
parseDate={(str) => new Date(str)}
|
parseDate={(str) => new Date(str)}
|
||||||
fill={true}
|
fill={true}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FFormGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Customer opening balance field.
|
|
||||||
* @returns {JSX.Element}
|
|
||||||
*/
|
|
||||||
function CustomerOpeningBalanceField() {
|
function CustomerOpeningBalanceField() {
|
||||||
const { customerId } = useCustomerFormContext();
|
const { customerId } = useCustomerFormContext();
|
||||||
const { values } = useFormikContext();
|
const { values } = useFormikContext();
|
||||||
@@ -129,15 +113,16 @@ function CustomerOpeningBalanceField() {
|
|||||||
label={<T id={'opening_balance'} />}
|
label={<T id={'opening_balance'} />}
|
||||||
name={'opening_balance'}
|
name={'opening_balance'}
|
||||||
inline
|
inline
|
||||||
fill
|
|
||||||
shouldUpdate={openingBalanceFieldShouldUpdate}
|
shouldUpdate={openingBalanceFieldShouldUpdate}
|
||||||
shouldUpdateDeps={{ currencyCode: values.currency_code }}
|
shouldUpdateDeps={{ currencyCode: values.currency_code }}
|
||||||
fastField={true}
|
fastField={true}
|
||||||
|
fill
|
||||||
>
|
>
|
||||||
<ControlGroup fill>
|
<ControlGroup fill>
|
||||||
<InputPrependText text={values.currency_code} />
|
<InputPrependText text={values.currency_code as string} />
|
||||||
<FMoneyInputGroup
|
<FMoneyInputGroup
|
||||||
name={'opening_balance'}
|
name={'opening_balance'}
|
||||||
|
fastField
|
||||||
inputGroupProps={{ fill: true }}
|
inputGroupProps={{ fill: true }}
|
||||||
/>
|
/>
|
||||||
</ControlGroup>
|
</ControlGroup>
|
||||||
@@ -145,11 +130,6 @@ function CustomerOpeningBalanceField() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Customer opening balance exchange rate field if the customer has foreign
|
|
||||||
* currency.
|
|
||||||
* @returns {JSX.Element}
|
|
||||||
*/
|
|
||||||
function CustomerOpeningBalanceExchangeRateField() {
|
function CustomerOpeningBalanceExchangeRateField() {
|
||||||
const { values } = useFormikContext();
|
const { values } = useFormikContext();
|
||||||
const { customerId } = useCustomerFormContext();
|
const { customerId } = useCustomerFormContext();
|
||||||
@@ -162,17 +142,14 @@ function CustomerOpeningBalanceExchangeRateField() {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<FFormGroup
|
|
||||||
label={' '}
|
|
||||||
name={'opening_balance_exchange_rate'}
|
|
||||||
inline
|
|
||||||
fill
|
|
||||||
>
|
|
||||||
<ExchangeRateInputGroup
|
<ExchangeRateInputGroup
|
||||||
fromCurrency={values.currency_code}
|
fromCurrency={values.currency_code}
|
||||||
toCurrency={currentOrganization.base_currency}
|
toCurrency={currentOrganization.base_currency}
|
||||||
name={'opening_balance_exchange_rate'}
|
name={'opening_balance_exchange_rate'}
|
||||||
|
onRecalcConfirm={() => {}}
|
||||||
|
onCancel={() => {}}
|
||||||
|
formGroupProps={{ label: ' ' }}
|
||||||
/>
|
/>
|
||||||
</FFormGroup>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,39 +1,97 @@
|
|||||||
// @ts-nocheck
|
import { useMemo } from 'react';
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import classNames from 'classnames';
|
import { Formik, Form, FormikHelpers } from 'formik';
|
||||||
import { Formik, Form } from 'formik';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import { Divider, Intent, Tab, Tabs } from '@blueprintjs/core';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { CLASSES } from '@/constants/classes';
|
|
||||||
import { CreateCustomerForm, EditCustomerForm } from './CustomerForm.schema';
|
import { CreateCustomerForm, EditCustomerForm } from './CustomerForm.schema';
|
||||||
import { compose, transformToForm, saveInvoke, parseBoolean } from '@/utils';
|
import { compose, transformToForm, saveInvoke, parseBoolean } from '@/utils';
|
||||||
import { useCustomerFormContext } from './CustomerFormProvider';
|
import { useCustomerFormContext } from './CustomerFormProvider';
|
||||||
import { defaultInitialValues } from './utils';
|
import { defaultInitialValues } from './utils';
|
||||||
import { css } from '@emotion/css';
|
|
||||||
|
|
||||||
import { AppToaster, Box, Card, Group } from '@/components';
|
|
||||||
import CustomerFormPrimarySection from './CustomerFormPrimarySection';
|
|
||||||
import CustomerFormAfterPrimarySection from './CustomerFormAfterPrimarySection';
|
|
||||||
import CustomersTabs from './CustomersTabs';
|
|
||||||
import { CustomerFloatingActions } from './CustomerFloatingActions';
|
|
||||||
|
|
||||||
|
import { AppToaster, Box } from '@/components';
|
||||||
import { withCurrentOrganization } from '@/containers/Organization/withCurrentOrganization';
|
import { withCurrentOrganization } from '@/containers/Organization/withCurrentOrganization';
|
||||||
import CustomerFinancialPanel from './CustomerFinancialPanel';
|
import { CustomerFormContent } from './CustomerFormContent';
|
||||||
import CustomerShippingAddress from './CustomerShippingAddress';
|
|
||||||
import CustomerBillingAddress from './CustomerBillingAddress';
|
|
||||||
|
|
||||||
function CustomerFormFormik({
|
type CustomerFormValues = {
|
||||||
|
customer_type: string;
|
||||||
|
salutation: string;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
company_name: string;
|
||||||
|
display_name: string;
|
||||||
|
|
||||||
|
email?: string;
|
||||||
|
work_phone?: string;
|
||||||
|
personal_phone?: string;
|
||||||
|
website?: string;
|
||||||
|
note?: string;
|
||||||
|
active: boolean | string;
|
||||||
|
|
||||||
|
billing_address_country: string;
|
||||||
|
billing_address1: string;
|
||||||
|
billing_address2: string;
|
||||||
|
billing_address_city: string;
|
||||||
|
billing_address_state: string;
|
||||||
|
billing_address_postcode?: string;
|
||||||
|
billing_address_phone?: string;
|
||||||
|
|
||||||
|
shipping_address_country: string;
|
||||||
|
shipping_address1: string;
|
||||||
|
shipping_address2: string;
|
||||||
|
shipping_address_city: string;
|
||||||
|
shipping_address_state: string;
|
||||||
|
shipping_address_postcode?: string;
|
||||||
|
shipping_address_phone?: string;
|
||||||
|
|
||||||
|
currency_code: string;
|
||||||
|
opening_balance?: string | number;
|
||||||
|
opening_balance_at?: string;
|
||||||
|
opening_balance_exchange_rate?: string;
|
||||||
|
opening_balance_branch_id?: string;
|
||||||
|
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CustomerFormSubmitPayload = {
|
||||||
|
noRedirect?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CustomerFormFormikRootProps = {
|
||||||
|
organization: {
|
||||||
|
base_currency: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// #ownProps
|
||||||
|
initialValues?: Partial<CustomerFormValues>;
|
||||||
|
onSubmitSuccess?: (
|
||||||
|
values: CustomerFormValues,
|
||||||
|
formArgs: FormikHelpers<CustomerFormValues>,
|
||||||
|
submitPayload: CustomerFormSubmitPayload,
|
||||||
|
responseData?: unknown,
|
||||||
|
) => void;
|
||||||
|
onSubmitError?: (
|
||||||
|
values: CustomerFormValues,
|
||||||
|
formArgs: FormikHelpers<CustomerFormValues>,
|
||||||
|
submitPayload: CustomerFormSubmitPayload,
|
||||||
|
errorData?: unknown,
|
||||||
|
) => void;
|
||||||
|
onCancel?: () => void;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const EMPTY_INITIAL_VALUES: Partial<CustomerFormValues> = {};
|
||||||
|
|
||||||
|
function CustomerFormFormikRoot({
|
||||||
organization: { base_currency },
|
organization: { base_currency },
|
||||||
|
|
||||||
// #ownProps
|
// #ownProps
|
||||||
initialValues: initialCustomerValues,
|
initialValues: initialCustomerValues = EMPTY_INITIAL_VALUES,
|
||||||
onSubmitSuccess,
|
onSubmitSuccess,
|
||||||
onSubmitError,
|
onSubmitError,
|
||||||
onCancel,
|
// `onCancel` is accepted for compatibility but currently not used.
|
||||||
className,
|
className,
|
||||||
}) {
|
}: CustomerFormFormikRootProps) {
|
||||||
const {
|
const {
|
||||||
customer,
|
customer,
|
||||||
submitPayload,
|
submitPayload,
|
||||||
@@ -43,28 +101,28 @@ function CustomerFormFormik({
|
|||||||
isNewMode,
|
isNewMode,
|
||||||
} = useCustomerFormContext();
|
} = useCustomerFormContext();
|
||||||
|
|
||||||
/**
|
const initialValues = useMemo<CustomerFormValues>(
|
||||||
* Initial values in create and edit mode.
|
|
||||||
*/
|
|
||||||
const initialValues = useMemo(
|
|
||||||
() => ({
|
() => ({
|
||||||
...defaultInitialValues,
|
...defaultInitialValues,
|
||||||
currency_code: base_currency,
|
currency_code: base_currency,
|
||||||
...transformToForm(contactDuplicate || customer, defaultInitialValues),
|
...transformToForm(contactDuplicate ?? customer ?? {}, defaultInitialValues),
|
||||||
...transformToForm(initialCustomerValues, defaultInitialValues),
|
...transformToForm(initialCustomerValues, defaultInitialValues),
|
||||||
}),
|
}) as CustomerFormValues,
|
||||||
[customer, contactDuplicate, base_currency, initialCustomerValues],
|
[customer, contactDuplicate, base_currency, initialCustomerValues],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handles the form submit.
|
// Handles the form submit.
|
||||||
const handleFormSubmit = (values, formArgs) => {
|
const handleFormSubmit = (
|
||||||
|
values: CustomerFormValues,
|
||||||
|
formArgs: FormikHelpers<CustomerFormValues>,
|
||||||
|
) => {
|
||||||
const { setSubmitting, resetForm } = formArgs;
|
const { setSubmitting, resetForm } = formArgs;
|
||||||
const formValues = {
|
const formValues = {
|
||||||
...values,
|
...values,
|
||||||
active: parseBoolean(values.active, true),
|
active: parseBoolean(values.active, true),
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSuccess = (res) => {
|
const onSuccess = (res: { data?: unknown }) => {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
message: intl.get(
|
message: intl.get(
|
||||||
isNewMode
|
isNewMode
|
||||||
@@ -86,30 +144,25 @@ function CustomerFormFormik({
|
|||||||
if (isNewMode) {
|
if (isNewMode) {
|
||||||
createCustomerMutate(formValues).then(onSuccess).catch(onError);
|
createCustomerMutate(formValues).then(onSuccess).catch(onError);
|
||||||
} else {
|
} else {
|
||||||
editCustomerMutate([customer.id, formValues])
|
if (!customer) return;
|
||||||
.then(onSuccess)
|
editCustomerMutate([customer.id, formValues]).then(onSuccess).catch(onError);
|
||||||
.catch(onError);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Box mx={'auto'} maxWidth={800}>
|
||||||
className={classNames(CLASSES.PAGE_FORM, className)}
|
<Formik<CustomerFormValues>
|
||||||
>
|
|
||||||
<Formik
|
|
||||||
validationSchema={isNewMode ? CreateCustomerForm : EditCustomerForm}
|
validationSchema={isNewMode ? CreateCustomerForm : EditCustomerForm}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
onSubmit={handleFormSubmit}
|
onSubmit={handleFormSubmit}
|
||||||
>
|
>
|
||||||
<Form>
|
<Form>
|
||||||
<CustomerFormFields>
|
<CustomerFormFields>
|
||||||
<Box px={'20px'} py={'10px'} mx={'auto'} maxWidth={'800px'}>
|
<CustomerFormContent />
|
||||||
<CustomerFormContent />
|
|
||||||
</Box>
|
|
||||||
</CustomerFormFields>
|
</CustomerFormFields>
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,56 +177,4 @@ const CustomerFormFields = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CustomerFormHeaderPrimary = styled.div`
|
export const CustomerFormFormik = compose(withCurrentOrganization(undefined))(CustomerFormFormikRoot);
|
||||||
--x-border: #e4e4e4;
|
|
||||||
|
|
||||||
.bp4-dark & {
|
|
||||||
--x-border: var(--color-dark-gray3);
|
|
||||||
}
|
|
||||||
padding: 10px 0 0;
|
|
||||||
margin: 0 0 20px;
|
|
||||||
overflow: hidden;
|
|
||||||
border-bottom: 1px solid var(--x-border);
|
|
||||||
max-width: 1000px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default compose(withCurrentOrganization())(CustomerFormFormik);
|
|
||||||
|
|
||||||
function CustomerFormContent() {
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<Group verticalAlign={'top'} alignItems={'flex-start'} flexWrap={'nowrap'}>
|
|
||||||
<Tabs vertical large defaultSelectedTabId={'primary'} className={css`position: sticky; top: 20px;`}>
|
|
||||||
<Tab id={'primary'} title={'Basic'} />
|
|
||||||
<Tab id={'financial'} title={'Financial'} />
|
|
||||||
<Tab id={'billing_address'} title={'Billing address'} />
|
|
||||||
<Tab id={'shipping_address'} title={'Ship address'} />
|
|
||||||
</Tabs>
|
|
||||||
|
|
||||||
<CustomerFormBasicSection />
|
|
||||||
</Group>
|
|
||||||
<CustomerFloatingActions />
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const customerFormSectionDividerClass = css`
|
|
||||||
margin: 20px 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
function CustomerFormBasicSection() {
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<CustomerFormPrimarySection />
|
|
||||||
<Divider className={customerFormSectionDividerClass} />
|
|
||||||
<CustomerFinancialPanel />
|
|
||||||
<Divider className={customerFormSectionDividerClass} />
|
|
||||||
<CustomerBillingAddress />
|
|
||||||
<Divider className={customerFormSectionDividerClass} />
|
|
||||||
<CustomerShippingAddress />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Box, FFormGroup, FormattedMessage as T, FTextArea } from '@/components';
|
||||||
|
import { CustomerFormSectionTitle } from './CustomerFormSectionTitle';
|
||||||
|
|
||||||
|
export function CustomerFormNotesSection() {
|
||||||
|
return (
|
||||||
|
<Box data-section-id="notes">
|
||||||
|
<CustomerFormSectionTitle>
|
||||||
|
<T id={'notes'} />
|
||||||
|
</CustomerFormSectionTitle>
|
||||||
|
|
||||||
|
<FFormGroup name={'note'} label={<T id={'note'} />} inline>
|
||||||
|
<FTextArea name={'note'} fill />
|
||||||
|
</FFormGroup>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import styled from 'styled-components';
|
|||||||
|
|
||||||
import { DashboardCard, DashboardInsider } from '@/components';
|
import { DashboardCard, DashboardInsider } from '@/components';
|
||||||
|
|
||||||
import CustomerFormFormik from './CustomerFormFormik';
|
import { CustomerFormFormik } from './CustomerFormFormik';
|
||||||
import {
|
import {
|
||||||
CustomerFormProvider,
|
CustomerFormProvider,
|
||||||
useCustomerFormContext,
|
useCustomerFormContext,
|
||||||
@@ -19,9 +19,9 @@ function CustomerFormPageLoading({ children }) {
|
|||||||
const { isFormLoading } = useCustomerFormContext();
|
const { isFormLoading } = useCustomerFormContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomerDashboardInsider loading={isFormLoading}>
|
<DashboardInsider loading={isFormLoading}>
|
||||||
{children}
|
{children}
|
||||||
</CustomerDashboardInsider>
|
</DashboardInsider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ export default function CustomerFormPage() {
|
|||||||
return (
|
return (
|
||||||
<CustomerFormProvider customerId={customerId}>
|
<CustomerFormProvider customerId={customerId}>
|
||||||
<CustomerFormPageLoading>
|
<CustomerFormPageLoading>
|
||||||
<CustomerFormPageFormik
|
<CustomerFormFormik
|
||||||
onSubmitSuccess={handleSubmitSuccess}
|
onSubmitSuccess={handleSubmitSuccess}
|
||||||
onCancel={handleFormCancel}
|
onCancel={handleFormCancel}
|
||||||
/>
|
/>
|
||||||
@@ -57,9 +57,3 @@ export default function CustomerFormPage() {
|
|||||||
</CustomerFormProvider>
|
</CustomerFormProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CustomerFormPageFormik = styled(CustomerFormFormik)`
|
|
||||||
`;
|
|
||||||
|
|
||||||
const CustomerDashboardInsider = styled(DashboardInsider)`
|
|
||||||
`;
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// @ts-nocheck
|
import React, { createContext, useState } from 'react';
|
||||||
import React, { useState, createContext } from 'react';
|
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
useCustomer,
|
useCustomer,
|
||||||
@@ -12,10 +11,60 @@ import {
|
|||||||
import { Features } from '@/constants';
|
import { Features } from '@/constants';
|
||||||
import { useFeatureCan } from '@/hooks/state';
|
import { useFeatureCan } from '@/hooks/state';
|
||||||
|
|
||||||
const CustomerFormContext = createContext();
|
type CustomerFormSubmitPayload = {
|
||||||
|
noRedirect?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
function CustomerFormProvider({ query, customerId, ...props }) {
|
type Customer = {
|
||||||
const { state } = useLocation();
|
id: number;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Currency = {
|
||||||
|
currency_code: string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Branch = {
|
||||||
|
id: number;
|
||||||
|
primary?: boolean;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CustomerFormContextValue = {
|
||||||
|
customerId?: number;
|
||||||
|
customer?: Customer;
|
||||||
|
currencies: Currency[];
|
||||||
|
branches: Branch[];
|
||||||
|
contactDuplicate?: Customer;
|
||||||
|
submitPayload: CustomerFormSubmitPayload;
|
||||||
|
isNewMode: boolean;
|
||||||
|
|
||||||
|
isCustomerLoading: boolean;
|
||||||
|
isCurrenciesLoading: boolean;
|
||||||
|
isBranchesSuccess: boolean;
|
||||||
|
isFormLoading: boolean;
|
||||||
|
|
||||||
|
setSubmitPayload: React.Dispatch<
|
||||||
|
React.SetStateAction<CustomerFormSubmitPayload>
|
||||||
|
>;
|
||||||
|
|
||||||
|
editCustomerMutate: (args: [number, any]) => Promise<any>;
|
||||||
|
createCustomerMutate: (values: any) => Promise<any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CustomerFormProviderProps = {
|
||||||
|
query?: unknown;
|
||||||
|
customerId?: number;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomerFormContext = createContext<CustomerFormContextValue | undefined>(
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
function CustomerFormProvider({ query, customerId, children }: CustomerFormProviderProps) {
|
||||||
|
const { state } = useLocation<{ action?: number | string }>();
|
||||||
const contactId = state?.action;
|
const contactId = state?.action;
|
||||||
|
|
||||||
// Features guard.
|
// Features guard.
|
||||||
@@ -33,7 +82,7 @@ function CustomerFormProvider({ query, customerId, ...props }) {
|
|||||||
{ enabled: !!contactId },
|
{ enabled: !!contactId },
|
||||||
);
|
);
|
||||||
// Handle fetch Currencies data table
|
// Handle fetch Currencies data table
|
||||||
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
|
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(undefined);
|
||||||
|
|
||||||
// Fetches the branches list.
|
// Fetches the branches list.
|
||||||
const {
|
const {
|
||||||
@@ -43,23 +92,26 @@ function CustomerFormProvider({ query, customerId, ...props }) {
|
|||||||
} = useBranches(query, { enabled: isBranchFeatureCan });
|
} = useBranches(query, { enabled: isBranchFeatureCan });
|
||||||
|
|
||||||
// Form submit payload.
|
// Form submit payload.
|
||||||
const [submitPayload, setSubmitPayload] = useState({});
|
const [submitPayload, setSubmitPayload] = useState<CustomerFormSubmitPayload>({});
|
||||||
|
|
||||||
const { mutateAsync: editCustomerMutate } = useEditCustomer();
|
const editCustomerMutation = useEditCustomer(undefined) as any;
|
||||||
const { mutateAsync: createCustomerMutate } = useCreateCustomer();
|
const createCustomerMutation = useCreateCustomer(undefined) as any;
|
||||||
|
const editCustomerMutate = editCustomerMutation.mutateAsync as CustomerFormContextValue['editCustomerMutate'];
|
||||||
|
const createCustomerMutate =
|
||||||
|
createCustomerMutation.mutateAsync as CustomerFormContextValue['createCustomerMutate'];
|
||||||
|
|
||||||
// determines whether the form new or duplicate mode.
|
// determines whether the form new or duplicate mode.
|
||||||
const isNewMode = contactId || !customerId;
|
const isNewMode = Boolean(contactId) || !customerId;
|
||||||
|
|
||||||
const isFormLoading =
|
const isFormLoading =
|
||||||
isCustomerLoading || isCurrenciesLoading || isBranchesLoading;
|
isCustomerLoading || isCurrenciesLoading || isBranchesLoading;
|
||||||
|
|
||||||
const provider = {
|
const provider: CustomerFormContextValue = {
|
||||||
customerId,
|
customerId,
|
||||||
customer,
|
customer: customer as Customer | undefined,
|
||||||
currencies,
|
currencies: (currencies as Currency[]) ?? [],
|
||||||
branches,
|
branches: (branches as Branch[]) ?? [],
|
||||||
contactDuplicate,
|
contactDuplicate: contactDuplicate as Customer | undefined,
|
||||||
submitPayload,
|
submitPayload,
|
||||||
isNewMode,
|
isNewMode,
|
||||||
|
|
||||||
@@ -73,9 +125,21 @@ function CustomerFormProvider({ query, customerId, ...props }) {
|
|||||||
createCustomerMutate,
|
createCustomerMutate,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <CustomerFormContext.Provider value={provider} {...props} />;
|
return (
|
||||||
|
<CustomerFormContext.Provider value={provider}>
|
||||||
|
{children}
|
||||||
|
</CustomerFormContext.Provider>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const useCustomerFormContext = () => React.useContext(CustomerFormContext);
|
const useCustomerFormContext = () => {
|
||||||
|
const ctx = React.useContext(CustomerFormContext);
|
||||||
|
if (!ctx) {
|
||||||
|
throw new Error(
|
||||||
|
'useCustomerFormContext must be used within a CustomerFormProvider',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
|
||||||
export { CustomerFormProvider, useCustomerFormContext };
|
export { CustomerFormProvider, useCustomerFormContext };
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
|
||||||
@@ -9,6 +8,6 @@ const customerFormSectionTitleClass = css`
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function CustomerFormSectionTitle({ children }) {
|
export function CustomerFormSectionTitle({ children }: { children: React.ReactNode | string }) {
|
||||||
return <h4 className={customerFormSectionTitleClass}>{children}</h4>;
|
return <h4 className={customerFormSectionTitleClass}>{children}</h4>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
FInputGroup,
|
FInputGroup,
|
||||||
FTextArea,
|
FTextArea,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import CustomerFormSectionTitle from './CustomerFormSectionTitle';
|
import { CustomerFormSectionTitle } from './CustomerFormSectionTitle';
|
||||||
|
|
||||||
export default function CustomerShippingAddress() {
|
export function CustomerShippingAddress() {
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box data-section-id="shippingAddress">
|
||||||
<CustomerFormSectionTitle>
|
<CustomerFormSectionTitle>
|
||||||
<T id={'shipping_address'} />
|
<T id={'shipping_address'} />
|
||||||
</CustomerFormSectionTitle>
|
</CustomerFormSectionTitle>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { FormattedMessage as T, FFormGroup } from '@/components';
|
|||||||
/**
|
/**
|
||||||
* Customer type selector (button group).
|
* Customer type selector (button group).
|
||||||
*/
|
*/
|
||||||
export default function CustomerTypeRadioField() {
|
export function CustomerTypeRadioField() {
|
||||||
return (
|
return (
|
||||||
<FFormGroup
|
<FFormGroup
|
||||||
name={'customer_type'}
|
name={'customer_type'}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Tabs, Tab } from '@blueprintjs/core';
|
|||||||
|
|
||||||
import CustomerAddressTabs from './CustomerAddressTabs';
|
import CustomerAddressTabs from './CustomerAddressTabs';
|
||||||
import CustomerAttachmentTabs from './CustomerAttachmentTabs';
|
import CustomerAttachmentTabs from './CustomerAttachmentTabs';
|
||||||
import CustomerFinancialPanel from './CustomerFinancialPanel';
|
import CustomerFinancialPanel from './CustomerFormFinancialSection';
|
||||||
import CustomerNotePanel from './CustomerNotePanel';
|
import CustomerNotePanel from './CustomerNotePanel';
|
||||||
|
|
||||||
export default function CustomersTabs() {
|
export default function CustomersTabs() {
|
||||||
|
|||||||
+6
-8
@@ -8,9 +8,7 @@ import {
|
|||||||
CustomerFormProvider,
|
CustomerFormProvider,
|
||||||
useCustomerFormContext,
|
useCustomerFormContext,
|
||||||
} from '@/containers/Customers/CustomerForm/CustomerFormProvider';
|
} from '@/containers/Customers/CustomerForm/CustomerFormProvider';
|
||||||
import CustomerFormFormik, {
|
import { CustomerFormFormik } from '@/containers/Customers/CustomerForm/CustomerFormFormik';
|
||||||
CustomerFormHeaderPrimary,
|
|
||||||
} from '@/containers/Customers/CustomerForm/CustomerFormFormik';
|
|
||||||
|
|
||||||
import { withDrawerActions } from '@/containers/Drawer/withDrawerActions';
|
import { withDrawerActions } from '@/containers/Drawer/withDrawerActions';
|
||||||
import { DRAWERS } from '@/constants/drawers';
|
import { DRAWERS } from '@/constants/drawers';
|
||||||
@@ -56,11 +54,11 @@ function QuickCustomerFormDrawer({
|
|||||||
<CustomerFormProvider customerId={customerId}>
|
<CustomerFormProvider customerId={customerId}>
|
||||||
<DrawerCustomerFormLoading>
|
<DrawerCustomerFormLoading>
|
||||||
<CustomerFormCard>
|
<CustomerFormCard>
|
||||||
<CustomerFormFormik
|
{/* <CustomerFormFormik
|
||||||
initialValues={{ first_name: displayName }}
|
initialValues={{ first_name: displayName }}
|
||||||
onSubmitSuccess={handleSubmitSuccess}
|
onSubmitSuccess={handleSubmitSuccess}
|
||||||
onCancel={handleCancelForm}
|
onCancel={handleCancelForm}
|
||||||
/>
|
/> */}
|
||||||
</CustomerFormCard>
|
</CustomerFormCard>
|
||||||
</DrawerCustomerFormLoading>
|
</DrawerCustomerFormLoading>
|
||||||
</CustomerFormProvider>
|
</CustomerFormProvider>
|
||||||
@@ -74,9 +72,9 @@ const CustomerFormCard = styled(Card)`
|
|||||||
padding: 25px;
|
padding: 25px;
|
||||||
margin-bottom: calc(15px + 65px);
|
margin-bottom: calc(15px + 65px);
|
||||||
|
|
||||||
${CustomerFormHeaderPrimary} {
|
// ${CustomerFormHeaderPrimary} {
|
||||||
padding-top: 0;
|
// padding-top: 0;
|
||||||
}
|
// }
|
||||||
.page-form {
|
.page-form {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user