diff --git a/packages/webapp/src/components/DrawersContainer.tsx b/packages/webapp/src/components/DrawersContainer.tsx index 05d2b3413..8a7d04074 100644 --- a/packages/webapp/src/components/DrawersContainer.tsx +++ b/packages/webapp/src/components/DrawersContainer.tsx @@ -12,7 +12,7 @@ import CustomerDetailsDrawer from '@/containers/Drawers/CustomerDetailsDrawer'; import VendorDetailsDrawer from '@/containers/Drawers/VendorDetailsDrawer'; import InventoryAdjustmentDetailDrawer from '@/containers/Drawers/InventoryAdjustmentDetailDrawer'; 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 QuickWriteVendorDrawer from '@/containers/Drawers/QuickWriteVendorDrawer'; import CreditNoteDetailDrawer from '@/containers/Drawers/CreditNoteDetailDrawer'; @@ -59,7 +59,7 @@ export default function DrawersContainer() { - + {/* */} diff --git a/packages/webapp/src/components/Select/DisplayNameList.tsx b/packages/webapp/src/components/Select/DisplayNameList.tsx index d42da993c..442f0ca89 100644 --- a/packages/webapp/src/components/Select/DisplayNameList.tsx +++ b/packages/webapp/src/components/Select/DisplayNameList.tsx @@ -4,6 +4,11 @@ import { FSelect } from '../Forms'; import { useFormikContext } from 'formik'; export type DisplayNameListItem = { label: string }; +type DisplayNameFormat = { + format: string; + values: Array; + required: number[]; +}; export interface DisplayNameListProps extends Omit< @@ -11,6 +16,47 @@ export interface DisplayNameListProps '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) { const { values: { @@ -21,40 +67,11 @@ export function DisplayNameList({ ...restProps }: DisplayNameListProps) { }, } = useFormikContext(); - const formats = useMemo( - () => [ - { - 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] }, - ], - [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], + const formatOptions = useDisplayNameFormatOptions( + salutation, + firstName, + lastName, + companyName, ); return ( @@ -62,6 +79,7 @@ export function DisplayNameList({ ...restProps }: DisplayNameListProps) { items={formatOptions} valueAccessor={'label'} textAccessor={'label'} + labelAccessor={'_label'} placeholder={intl.get('select_display_name_as')} filterable={false} {...restProps} diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerBillingAddress.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerBillingAddress.tsx index 3b21d6fe9..bb7e6a758 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerBillingAddress.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerBillingAddress.tsx @@ -7,11 +7,11 @@ import { FInputGroup, FTextArea, } from '@/components'; -import CustomerFormSectionTitle from './CustomerFormSectionTitle'; +import { CustomerFormSectionTitle } from './CustomerFormSectionTitle'; -export default function CustomerBillingAddress() { +export function CustomerBillingAddress() { return ( - + diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFloatingActions.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFloatingActions.tsx index 4c28203ff..f1b958914 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFloatingActions.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFloatingActions.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import React from 'react'; import styled from 'styled-components'; import { @@ -11,40 +10,32 @@ import { Menu, MenuItem, } from '@blueprintjs/core'; -import classNames from 'classnames'; import { useFormikContext } from 'formik'; import { Group, Icon, FormattedMessage as T } from '@/components'; -import { CLASSES } from '@/constants/classes'; import { useCustomerFormContext } from './CustomerFormProvider'; -import { safeInvoke } from '@/utils'; -/** - * Customer floating actions bar. - */ -export function CustomerFloatingActions({ onCancel }) { +export function CustomerFloatingActions() { // Customer form context. - const { isNewMode, setSubmitPayload } = useCustomerFormContext(); + const { isNewMode, setSubmitPayload } = useCustomerFormContext() as { + isNewMode: boolean; + setSubmitPayload: (payload: { noRedirect: boolean }) => void; + }; // Formik context. const { resetForm, submitForm, isSubmitting } = useFormikContext(); // Handle submit button click. - const handleSubmitBtnClick = (event) => { + const handleSubmitBtnClick = (_event: React.MouseEvent) => { setSubmitPayload({ noRedirect: false }); }; - // Handle cancel button click. - const handleCancelBtnClick = (event) => { - safeInvoke(onCancel, event); - }; - // handle clear button clicl. - const handleClearBtnClick = (event) => { + const handleClearBtnClick = (_event: React.MouseEvent) => { resetForm(); }; // Handle submit & new button click. - const handleSubmitAndNewClick = (event) => { + const handleSubmitAndNewClick = (_event: React.MouseEvent) => { submitForm(); setSubmitPayload({ noRedirect: true }); }; diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerForm.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerForm.tsx deleted file mode 100644 index bcc7df75b..000000000 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerForm.tsx +++ /dev/null @@ -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 ( - - - - ); -} diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormPrimarySection.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormBasicSection.tsx similarity index 89% rename from packages/webapp/src/containers/Customers/CustomerForm/CustomerFormPrimarySection.tsx rename to packages/webapp/src/containers/Customers/CustomerForm/CustomerFormBasicSection.tsx index 18957444b..bf22c5645 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormPrimarySection.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormBasicSection.tsx @@ -14,18 +14,15 @@ import { Icon, Stack, } from '@/components'; -import CustomerTypeRadioField from './CustomerTypeRadioField'; -import CustomerFormSectionTitle from './CustomerFormSectionTitle'; +import { CustomerTypeRadioField } from './CustomerTypeRadioField'; +import { CustomerFormSectionTitle } from './CustomerFormSectionTitle'; import { useAutofocus } from '@/hooks'; -/** - * Customer form primary section. - */ -export default function CustomerFormPrimarySection({}) { +export function CustomerFormBasicSection({}) { const firstNameFieldRef = useAutofocus(); return ( - + Customer details {/**-----------Customer type. -----------*/} @@ -102,7 +99,7 @@ export default function CustomerFormPrimarySection({}) { } - inline={true} + inline > - + { + const sectionId = String(tabId); + setSelectedTabId(sectionId); + + const section = document.querySelector( + `[data-section-id="${sectionId}"]`, + ); + if (section) { + section.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + }; + + return ( + + + .bp4-tab{font-size: 14px;} `} + > + + + + + + + + + + + + ) +} diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFields.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFields.tsx new file mode 100644 index 000000000..e681a5866 --- /dev/null +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFields.tsx @@ -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 ( + + + + + + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFinancialPanel.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFinancialSection.tsx similarity index 82% rename from packages/webapp/src/containers/Customers/CustomerForm/CustomerFinancialPanel.tsx rename to packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFinancialSection.tsx index 38036113b..06fa69d41 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFinancialPanel.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFinancialSection.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import React from 'react'; import { FormGroup, Position, ControlGroup } from '@blueprintjs/core'; import { ErrorMessage, useFormikContext } from 'formik'; @@ -10,8 +9,6 @@ import { CurrencySelectList, BranchSelect, FeatureCan, - Row, - Col, FMoneyInputGroup, ExchangeRateInputGroup, FDateInput, @@ -24,23 +21,20 @@ import { useSetPrimaryBranchToForm, } from './utils'; import { useCurrentOrganization } from '@/hooks/state'; -import CustomerFormSectionTitle from './CustomerFormSectionTitle'; +import { CustomerFormSectionTitle } from './CustomerFormSectionTitle'; -/** - * Customer financial panel. - */ -export default function CustomerFinancialPanel() { +export function CustomerFormFinancialSection() { const { currencies, customerId, branches } = useCustomerFormContext(); // Sets the primary branch to form. useSetPrimaryBranchToForm(); return ( - + - {/*------------ Currency -----------*/} + } @@ -55,16 +49,10 @@ export default function CustomerFinancialPanel() { /> - {/*------------ Opening balance -----------*/} - - {/*------ Opening Balance Exchange Rate -----*/} - - {/*------------ Opening balance at -----------*/} - - {/*------------ Opening branch -----------*/} + } @@ -94,7 +82,7 @@ function CustomerOpeningBalanceAtField() { if (customerId) return null; return ( - } inline @@ -109,14 +97,10 @@ function CustomerOpeningBalanceAtField() { parseDate={(str) => new Date(str)} fill={true} /> - + ); } -/** - * Customer opening balance field. - * @returns {JSX.Element} - */ function CustomerOpeningBalanceField() { const { customerId } = useCustomerFormContext(); const { values } = useFormikContext(); @@ -129,15 +113,16 @@ function CustomerOpeningBalanceField() { label={} name={'opening_balance'} inline - fill shouldUpdate={openingBalanceFieldShouldUpdate} shouldUpdateDeps={{ currencyCode: values.currency_code }} fastField={true} + fill > - + @@ -145,11 +130,6 @@ function CustomerOpeningBalanceField() { ); } -/** - * Customer opening balance exchange rate field if the customer has foreign - * currency. - * @returns {JSX.Element} - */ function CustomerOpeningBalanceExchangeRateField() { const { values } = useFormikContext(); const { customerId } = useCustomerFormContext(); @@ -162,17 +142,14 @@ function CustomerOpeningBalanceExchangeRateField() { return null; } return ( - + {}} + onCancel={() => {}} + formGroupProps={{ label: ' ' }} /> - ); } diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFormik.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFormik.tsx index d1644e3c4..cfb1865b5 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFormik.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormFormik.tsx @@ -1,39 +1,97 @@ -// @ts-nocheck -import React, { useMemo } from 'react'; +import { useMemo } from 'react'; import intl from 'react-intl-universal'; -import classNames from 'classnames'; -import { Formik, Form } from 'formik'; -import { Divider, Intent, Tab, Tabs } from '@blueprintjs/core'; +import { Formik, Form, FormikHelpers } from 'formik'; +import { Intent } from '@blueprintjs/core'; import styled from 'styled-components'; -import { CLASSES } from '@/constants/classes'; import { CreateCustomerForm, EditCustomerForm } from './CustomerForm.schema'; import { compose, transformToForm, saveInvoke, parseBoolean } from '@/utils'; import { useCustomerFormContext } from './CustomerFormProvider'; 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 CustomerFinancialPanel from './CustomerFinancialPanel'; -import CustomerShippingAddress from './CustomerShippingAddress'; -import CustomerBillingAddress from './CustomerBillingAddress'; +import { CustomerFormContent } from './CustomerFormContent'; -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; + onSubmitSuccess?: ( + values: CustomerFormValues, + formArgs: FormikHelpers, + submitPayload: CustomerFormSubmitPayload, + responseData?: unknown, + ) => void; + onSubmitError?: ( + values: CustomerFormValues, + formArgs: FormikHelpers, + submitPayload: CustomerFormSubmitPayload, + errorData?: unknown, + ) => void; + onCancel?: () => void; + className?: string; +}; + +const EMPTY_INITIAL_VALUES: Partial = {}; + +function CustomerFormFormikRoot({ organization: { base_currency }, // #ownProps - initialValues: initialCustomerValues, + initialValues: initialCustomerValues = EMPTY_INITIAL_VALUES, onSubmitSuccess, onSubmitError, - onCancel, + // `onCancel` is accepted for compatibility but currently not used. className, -}) { +}: CustomerFormFormikRootProps) { const { customer, submitPayload, @@ -43,28 +101,28 @@ function CustomerFormFormik({ isNewMode, } = useCustomerFormContext(); - /** - * Initial values in create and edit mode. - */ - const initialValues = useMemo( + const initialValues = useMemo( () => ({ ...defaultInitialValues, currency_code: base_currency, - ...transformToForm(contactDuplicate || customer, defaultInitialValues), + ...transformToForm(contactDuplicate ?? customer ?? {}, defaultInitialValues), ...transformToForm(initialCustomerValues, defaultInitialValues), - }), + }) as CustomerFormValues, [customer, contactDuplicate, base_currency, initialCustomerValues], ); // Handles the form submit. - const handleFormSubmit = (values, formArgs) => { + const handleFormSubmit = ( + values: CustomerFormValues, + formArgs: FormikHelpers, + ) => { const { setSubmitting, resetForm } = formArgs; const formValues = { ...values, active: parseBoolean(values.active, true), }; - const onSuccess = (res) => { + const onSuccess = (res: { data?: unknown }) => { AppToaster.show({ message: intl.get( isNewMode @@ -86,30 +144,25 @@ function CustomerFormFormik({ if (isNewMode) { createCustomerMutate(formValues).then(onSuccess).catch(onError); } else { - editCustomerMutate([customer.id, formValues]) - .then(onSuccess) - .catch(onError); + if (!customer) return; + editCustomerMutate([customer.id, formValues]).then(onSuccess).catch(onError); } }; return ( -
- + validationSchema={isNewMode ? CreateCustomerForm : EditCustomerForm} initialValues={initialValues} onSubmit={handleFormSubmit} >
- - - +
-
+
); } @@ -124,56 +177,4 @@ const CustomerFormFields = styled.div` } `; -export const CustomerFormHeaderPrimary = styled.div` - --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 ( - - - - - - - - - - - - - - ) -} - - -const customerFormSectionDividerClass = css` - margin: 20px 0; -`; - -function CustomerFormBasicSection() { - return ( - - - - - - - - - - ); -} - - +export const CustomerFormFormik = compose(withCurrentOrganization(undefined))(CustomerFormFormikRoot); diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormNotesSection.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormNotesSection.tsx new file mode 100644 index 000000000..e7b80a8ee --- /dev/null +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormNotesSection.tsx @@ -0,0 +1,16 @@ +import { Box, FFormGroup, FormattedMessage as T, FTextArea } from '@/components'; +import { CustomerFormSectionTitle } from './CustomerFormSectionTitle'; + +export function CustomerFormNotesSection() { + return ( + + + + + + } inline> + + + + ); +} diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormPage.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormPage.tsx index f8fe7e7fe..68d791c44 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormPage.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormPage.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components'; import { DashboardCard, DashboardInsider } from '@/components'; -import CustomerFormFormik from './CustomerFormFormik'; +import { CustomerFormFormik } from './CustomerFormFormik'; import { CustomerFormProvider, useCustomerFormContext, @@ -19,9 +19,9 @@ function CustomerFormPageLoading({ children }) { const { isFormLoading } = useCustomerFormContext(); return ( - + {children} - + ); } @@ -49,17 +49,11 @@ export default function CustomerFormPage() { return ( - ); -} - -const CustomerFormPageFormik = styled(CustomerFormFormik)` -`; - -const CustomerDashboardInsider = styled(DashboardInsider)` -`; +} \ No newline at end of file diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormProvider.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormProvider.tsx index aeb767068..e490aed0a 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormProvider.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormProvider.tsx @@ -1,5 +1,4 @@ -// @ts-nocheck -import React, { useState, createContext } from 'react'; +import React, { createContext, useState } from 'react'; import { useLocation } from 'react-router-dom'; import { useCustomer, @@ -12,10 +11,60 @@ import { import { Features } from '@/constants'; import { useFeatureCan } from '@/hooks/state'; -const CustomerFormContext = createContext(); +type CustomerFormSubmitPayload = { + noRedirect?: boolean; +}; -function CustomerFormProvider({ query, customerId, ...props }) { - const { state } = useLocation(); +type Customer = { + 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 + >; + + editCustomerMutate: (args: [number, any]) => Promise; + createCustomerMutate: (values: any) => Promise; +}; + +type CustomerFormProviderProps = { + query?: unknown; + customerId?: number; + children?: React.ReactNode; +}; + +const CustomerFormContext = createContext( + undefined, +); + +function CustomerFormProvider({ query, customerId, children }: CustomerFormProviderProps) { + const { state } = useLocation<{ action?: number | string }>(); const contactId = state?.action; // Features guard. @@ -33,7 +82,7 @@ function CustomerFormProvider({ query, customerId, ...props }) { { enabled: !!contactId }, ); // Handle fetch Currencies data table - const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(); + const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(undefined); // Fetches the branches list. const { @@ -43,23 +92,26 @@ function CustomerFormProvider({ query, customerId, ...props }) { } = useBranches(query, { enabled: isBranchFeatureCan }); // Form submit payload. - const [submitPayload, setSubmitPayload] = useState({}); + const [submitPayload, setSubmitPayload] = useState({}); - const { mutateAsync: editCustomerMutate } = useEditCustomer(); - const { mutateAsync: createCustomerMutate } = useCreateCustomer(); + const editCustomerMutation = useEditCustomer(undefined) as any; + 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. - const isNewMode = contactId || !customerId; + const isNewMode = Boolean(contactId) || !customerId; const isFormLoading = isCustomerLoading || isCurrenciesLoading || isBranchesLoading; - const provider = { + const provider: CustomerFormContextValue = { customerId, - customer, - currencies, - branches, - contactDuplicate, + customer: customer as Customer | undefined, + currencies: (currencies as Currency[]) ?? [], + branches: (branches as Branch[]) ?? [], + contactDuplicate: contactDuplicate as Customer | undefined, submitPayload, isNewMode, @@ -73,9 +125,21 @@ function CustomerFormProvider({ query, customerId, ...props }) { createCustomerMutate, }; - return ; + return ( + + {children} + + ); } -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 }; diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormSectionTitle.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormSectionTitle.tsx index 8e5c8148e..ff927fd7d 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormSectionTitle.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerFormSectionTitle.tsx @@ -1,4 +1,3 @@ -// @ts-nocheck import React from 'react'; import { css } from '@emotion/css'; @@ -9,6 +8,6 @@ const customerFormSectionTitleClass = css` margin-top: 0; `; -export default function CustomerFormSectionTitle({ children }) { +export function CustomerFormSectionTitle({ children }: { children: React.ReactNode | string }) { return

{children}

; } diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerShippingAddress.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerShippingAddress.tsx index 6016b8bd8..6607c3033 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerShippingAddress.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerShippingAddress.tsx @@ -7,11 +7,11 @@ import { FInputGroup, FTextArea, } from '@/components'; -import CustomerFormSectionTitle from './CustomerFormSectionTitle'; +import { CustomerFormSectionTitle } from './CustomerFormSectionTitle'; -export default function CustomerShippingAddress() { +export function CustomerShippingAddress() { return ( - + diff --git a/packages/webapp/src/containers/Customers/CustomerForm/CustomerTypeRadioField.tsx b/packages/webapp/src/containers/Customers/CustomerForm/CustomerTypeRadioField.tsx index 687aa35c9..866d56977 100644 --- a/packages/webapp/src/containers/Customers/CustomerForm/CustomerTypeRadioField.tsx +++ b/packages/webapp/src/containers/Customers/CustomerForm/CustomerTypeRadioField.tsx @@ -8,7 +8,7 @@ import { FormattedMessage as T, FFormGroup } from '@/components'; /** * Customer type selector (button group). */ -export default function CustomerTypeRadioField() { +export function CustomerTypeRadioField() { return ( - + /> */} @@ -74,9 +72,9 @@ const CustomerFormCard = styled(Card)` padding: 25px; margin-bottom: calc(15px + 65px); - ${CustomerFormHeaderPrimary} { - padding-top: 0; - } + // ${CustomerFormHeaderPrimary} { + // padding-top: 0; + // } .page-form { padding: 0;