fix: autofill the quick created customer/vendor

This commit is contained in:
Ahmed Bouhuolia
2024-08-13 23:55:53 +02:00
parent ec2b7e332e
commit d2193fdac0
14 changed files with 212 additions and 35 deletions

View File

@@ -1,9 +1,11 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import * as R from 'ramda'; import * as R from 'ramda';
import { useFormikContext } from 'formik';
import { createNewItemFromQuery, createNewItemRenderer } from './utils'; import { createNewItemFromQuery, createNewItemRenderer } from './utils';
import { FSelect } from '../Forms'; import { FSelect } from '../Forms';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useCreateAutofillListener } from '@/hooks/state/autofill';
import { DRAWERS } from '@/constants/drawers'; import { DRAWERS } from '@/constants/drawers';
/** /**
@@ -17,6 +19,7 @@ function CustomerSelectRoot({
// #ownProps // #ownProps
items, items,
allowCreate, allowCreate,
name,
...props ...props
}) { }) {
// Maybe inject create new item props to suggest component. // Maybe inject create new item props to suggest component.
@@ -24,14 +27,21 @@ function CustomerSelectRoot({
const maybeCreateNewItemFromQuery = allowCreate const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery ? createNewItemFromQuery
: null; : null;
const { setFieldValue } = useFormikContext();
// Creates autofill listener once the quick customer drawer submit the form.
const autofillRef = useCreateAutofillListener((payload: any) => {
setFieldValue(name, payload.customerId);
});
// Handles the create item click. // Handles the create item click.
const handleCreateItemClick = () => { const handleCreateItemClick = (item) => {
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER); const displayName = item.name;
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER, { autofillRef, displayName });
}; };
return ( return (
<FSelect <FSelect
name={name}
items={items} items={items}
textAccessor={'display_name'} textAccessor={'display_name'}
labelAccessor={'formatted_balance'} labelAccessor={'formatted_balance'}

View File

@@ -1,9 +1,11 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import * as R from 'ramda'; import * as R from 'ramda';
import { useFormikContext } from 'formik';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { createNewItemFromQuery, createNewItemRenderer } from './utils'; import { createNewItemFromQuery, createNewItemRenderer } from './utils';
import { FSelect } from '../Forms'; import { FSelect } from '../Forms';
import { useCreateAutofillListener } from '@/hooks/state/autofill';
import { DRAWERS } from '@/constants/drawers'; import { DRAWERS } from '@/constants/drawers';
/** /**
@@ -15,6 +17,7 @@ function VendorsSelectRoot({
openDrawer, openDrawer,
// #ownProps // #ownProps
name,
items, items,
allowCreate, allowCreate,
@@ -25,14 +28,24 @@ function VendorsSelectRoot({
const maybeCreateNewItemFromQuery = allowCreate const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery ? createNewItemFromQuery
: null; : null;
const { setFieldValue } = useFormikContext();
// Creates a new autofill listener once the quick vendor drawer submits the form.
const autofillRef = useCreateAutofillListener((payload: any) => {
setFieldValue(name, payload.vendorId);
});
// Handles the create item click. // Handles the create item click.
const handleCreateItemClick = () => { const handleCreateItemClick = (item) => {
openDrawer(DRAWERS.QUICK_WRITE_VENDOR); openDrawer(DRAWERS.QUICK_WRITE_VENDOR, {
autofillRef,
displayName: item.name,
});
}; };
return ( return (
<FSelect <FSelect
name={name}
items={items} items={items}
textAccessor={'display_name'} textAccessor={'display_name'}
labelAccessor={'formatted_balance'} labelAccessor={'formatted_balance'}

View File

@@ -52,7 +52,7 @@ function CustomerFormFormik({
...defaultInitialValues, ...defaultInitialValues,
currency_code: base_currency, currency_code: base_currency,
...transformToForm(contactDuplicate || customer, defaultInitialValues), ...transformToForm(contactDuplicate || customer, defaultInitialValues),
...initialCustomerValues, ...transformToForm(initialCustomerValues, defaultInitialValues),
}), }),
[customer, contactDuplicate, base_currency, initialCustomerValues], [customer, contactDuplicate, base_currency, initialCustomerValues],
); );
@@ -62,7 +62,7 @@ function CustomerFormFormik({
const { setSubmitting, resetForm } = formArgs; const { setSubmitting, resetForm } = formArgs;
const formValues = { ...values }; const formValues = { ...values };
const onSuccess = () => { const onSuccess = (res) => {
AppToaster.show({ AppToaster.show({
message: intl.get( message: intl.get(
isNewMode isNewMode
@@ -73,8 +73,7 @@ function CustomerFormFormik({
}); });
setSubmitting(false); setSubmitting(false);
resetForm(); resetForm();
saveInvoke(onSubmitSuccess, values, formArgs, submitPayload, res.data);
saveInvoke(onSubmitSuccess, values, formArgs, submitPayload);
}; };
const onError = () => { const onError = () => {

View File

@@ -5,14 +5,16 @@ import {
DrawerBody, DrawerBody,
FormattedMessage as T, FormattedMessage as T,
} from '@/components'; } from '@/components';
import QuickCustomerFormDrawer from './QuickCustomerFormDrawer'; import QuickCustomerFormDrawer from './QuickCustomerFormDrawer';
import { DRAWERS } from '@/constants/drawers'; import { DRAWERS } from '@/constants/drawers';
/** /**
* Quick create/edit customer drawer. * Quick create/edit customer drawer.
*/ */
export default function QuickCreateCustomerDrawerContent({ displayName }) { export default function QuickCreateCustomerDrawerContent({
displayName,
autofillRef,
}) {
return ( return (
<React.Fragment> <React.Fragment>
<DrawerHeaderContent <DrawerHeaderContent
@@ -20,7 +22,10 @@ export default function QuickCreateCustomerDrawerContent({ displayName }) {
title={<T id={'create_a_new_customer'} />} title={<T id={'create_a_new_customer'} />}
/> />
<DrawerBody> <DrawerBody>
<QuickCustomerFormDrawer displayName={displayName} /> <QuickCustomerFormDrawer
displayName={displayName}
autofillRef={autofillRef}
/>
</DrawerBody> </DrawerBody>
</React.Fragment> </React.Fragment>
); );

View File

@@ -14,6 +14,7 @@ import CustomerFormFormik, {
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers'; import { DRAWERS } from '@/constants/drawers';
import { useAddAutofillRef } from '@/hooks/state/autofill';
/** /**
* Drawer customer form loading wrapper. * Drawer customer form loading wrapper.
@@ -28,9 +29,22 @@ function DrawerCustomerFormLoading({ children }) {
/** /**
* Quick customer form of the drawer. * Quick customer form of the drawer.
*/ */
function QuickCustomerFormDrawer({ displayName, closeDrawer, customerId }) { function QuickCustomerFormDrawer({
displayName,
autofillRef,
closeDrawer,
customerId,
}) {
const addAutofillRef = useAddAutofillRef();
// Handle the form submit request success. // Handle the form submit request success.
const handleSubmitSuccess = () => { const handleSubmitSuccess = (values, formArgs, submitPayload, res) => {
if (autofillRef) {
addAutofillRef(autofillRef, {
displayName: values.display_name,
customerId: res.id,
});
}
closeDrawer(DRAWERS.QUICK_CREATE_CUSTOMER); closeDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
}; };
// Handle the form cancel action. // Handle the form cancel action.
@@ -43,7 +57,7 @@ function QuickCustomerFormDrawer({ displayName, closeDrawer, customerId }) {
<DrawerCustomerFormLoading> <DrawerCustomerFormLoading>
<CustomerFormCard> <CustomerFormCard>
<CustomerFormFormik <CustomerFormFormik
initialValues={{ display_name: displayName }} initialValues={{ first_name: displayName }}
onSubmitSuccess={handleSubmitSuccess} onSubmitSuccess={handleSubmitSuccess}
onCancel={handleCancelForm} onCancel={handleCancelForm}
/> />

View File

@@ -2,11 +2,10 @@
import React from 'react'; import React from 'react';
import { Drawer, DrawerSuspense } from '@/components'; import { Drawer, DrawerSuspense } from '@/components';
import withDrawers from '@/containers/Drawer/withDrawers'; import withDrawers from '@/containers/Drawer/withDrawers';
import { compose } from '@/utils'; import { compose } from '@/utils';
const QuickCreateCustomerDrawerContent = React.lazy(() => const QuickCreateCustomerDrawerContent = React.lazy(
import('./QuickCreateCustomerDrawerContent'), () => import('./QuickCreateCustomerDrawerContent'),
); );
/** /**
@@ -17,7 +16,7 @@ function QuickCreateCustomerDrawer({
// #withDrawer // #withDrawer
isOpen, isOpen,
payload, payload: { autofillRef, displayName },
}) { }) {
return ( return (
<Drawer <Drawer
@@ -27,7 +26,10 @@ function QuickCreateCustomerDrawer({
size={'80%'} size={'80%'}
> >
<DrawerSuspense> <DrawerSuspense>
<QuickCreateCustomerDrawerContent displayName={payload.displayName} /> <QuickCreateCustomerDrawerContent
displayName={displayName}
autofillRef={autofillRef}
/>
</DrawerSuspense> </DrawerSuspense>
</Drawer> </Drawer>
); );

View File

@@ -16,6 +16,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import withDashboardActions from '@/containers/Dashboard/withDashboardActions'; import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { useAddAutofillRef } from '@/hooks/state/autofill';
import { DRAWERS } from '@/constants/drawers'; import { DRAWERS } from '@/constants/drawers';
/** /**
@@ -36,17 +37,20 @@ function QuickVendorFormDrawer({
closeDrawer, closeDrawer,
vendorId, vendorId,
addQuickActionEvent, addQuickActionEvent,
autofillRef,
}) { }) {
const { payload } = useDrawerContext(); const { payload } = useDrawerContext();
const addAutofillRef = useAddAutofillRef();
// Handle the form submit request success. // Handle the form submit request success.
const handleSubmitSuccess = (values, form, submitPayload, response) => { const handleSubmitSuccess = (values, form, submitPayload, res) => {
if (!submitPayload.noRedirect) { if (!submitPayload.noRedirect) {
closeDrawer(DRAWERS.QUICK_WRITE_VENDOR); closeDrawer(DRAWERS.QUICK_WRITE_VENDOR);
} }
if (payload.quickActionEvent) { if (autofillRef) {
addQuickActionEvent(payload.quickActionEvent, { addAutofillRef(autofillRef, {
vendorId: response.data.id, displayName: values.display_name,
vendorId: res.id,
}); });
} }
}; };
@@ -60,7 +64,7 @@ function QuickVendorFormDrawer({
<DrawerVendorFormLoading> <DrawerVendorFormLoading>
<VendorFormCard> <VendorFormCard>
<VendorFormFormik <VendorFormFormik
initialValues={{ display_name: displayName }} initialValues={{ first_name: displayName }}
onSubmitSuccess={handleSubmitSuccess} onSubmitSuccess={handleSubmitSuccess}
onCancel={handleCancelForm} onCancel={handleCancelForm}
/> />

View File

@@ -12,7 +12,7 @@ import { DRAWERS } from '@/constants/drawers';
/** /**
* Quick create/edit vendor drawer. * Quick create/edit vendor drawer.
*/ */
export default function QuickWriteVendorDrawerContent({ displayName }) { export default function QuickWriteVendorDrawerContent({ displayName, autofillRef }) {
return ( return (
<React.Fragment> <React.Fragment>
<DrawerHeaderContent <DrawerHeaderContent
@@ -21,7 +21,7 @@ export default function QuickWriteVendorDrawerContent({ displayName }) {
/> />
<DrawerBody> <DrawerBody>
<QuickVendorFormDrawer displayName={displayName} /> <QuickVendorFormDrawer displayName={displayName} autofillRef={autofillRef} />
</DrawerBody> </DrawerBody>
</React.Fragment> </React.Fragment>
); );

View File

@@ -17,7 +17,7 @@ function QuickWriteVendorDrawer({
// #withDrawer // #withDrawer
isOpen, isOpen,
payload, payload: { displayName, autofillRef },
}) { }) {
return ( return (
<Drawer <Drawer
@@ -25,10 +25,9 @@ function QuickWriteVendorDrawer({
name={name} name={name}
style={{ minWidth: '700px', maxWidth: '900px' }} style={{ minWidth: '700px', maxWidth: '900px' }}
size={'80%'} size={'80%'}
payload={payload}
> >
<DrawerSuspense> <DrawerSuspense>
<QuickWriteVendorDrawerContent displayName={payload.displayName} /> <QuickWriteVendorDrawerContent displayName={displayName} autofillRef={autofillRef} />
</DrawerSuspense> </DrawerSuspense>
</Drawer> </Drawer>
); );

View File

@@ -34,6 +34,7 @@ function VendorFormFormik({
organization: { base_currency }, organization: { base_currency },
// #ownProps // #ownProps
initialValues,
onSubmitSuccess, onSubmitSuccess,
onSubmitError, onSubmitError,
onCancel, onCancel,
@@ -54,14 +55,15 @@ function VendorFormFormik({
/** /**
* Initial values in create and edit mode. * Initial values in create and edit mode.
*/ */
const initialValues = useMemo( const initialFormValues = useMemo(
() => ({ () => ({
...defaultInitialValues, ...defaultInitialValues,
...transformToForm(initialValues, defaultInitialValues),
currency_code: base_currency, currency_code: base_currency,
...transformToForm(vendor, defaultInitialValues), ...transformToForm(vendor, defaultInitialValues),
...transformToForm(contactDuplicate, defaultInitialValues), ...transformToForm(contactDuplicate, defaultInitialValues),
}), }),
[vendor, contactDuplicate, base_currency], [vendor, contactDuplicate, base_currency, initialValues],
); );
// Handles the form submit. // Handles the form submit.
@@ -84,7 +86,7 @@ function VendorFormFormik({
setSubmitting(false); setSubmitting(false);
resetForm(); resetForm();
safeInvoke(onSubmitSuccess, values, form, submitPayload, response); safeInvoke(onSubmitSuccess, values, form, submitPayload, response.data);
}; };
const onError = () => { const onError = () => {
@@ -112,7 +114,7 @@ function VendorFormFormik({
validationSchema={ validationSchema={
isNewMode ? CreateVendorFormSchema : EditVendorFormSchema isNewMode ? CreateVendorFormSchema : EditVendorFormSchema
} }
initialValues={initialValues} initialValues={initialFormValues}
onSubmit={handleFormSubmit} onSubmit={handleFormSubmit}
> >
<Form> <Form>

View File

@@ -0,0 +1,94 @@
// @ts-nocheck
import { useCallback, useEffect, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import {
addAutofill,
removeAutofill,
resetAutofill,
} from '@/store/dashboard/dashboard.actions';
const getAutofillPayload = (state, autofillRef) => {
return typeof state.dashboard.autofill[autofillRef + ''] !== 'undefined'
? state.dashboard.autofill[autofillRef]
: null;
};
const getAutofillPayloadSelectorFactory = () =>
createSelector(getAutofillPayload, (payload) => payload);
/**
*
* @param {number} autofillRef
* @returns {any}
*/
const useGetAutofillPayload = (autofillRef: number) => {
const getAutofillPayloadSelector = getAutofillPayloadSelectorFactory();
return useSelector((state) => getAutofillPayloadSelector(state, autofillRef));
};
/**
*
* @returns
*/
export const useAddAutofillRef = () => {
const dispatch = useDispatch();
return useCallback(
(autofillRef: number, payload: any) => {
return dispatch(addAutofill(autofillRef, payload));
},
[dispatch],
);
};
/**
*
* @returns
*/
export const useRemoveAutofillRef = () => {
const dispatch = useDispatch();
return useCallback(
(autofillRef: number) => {
return dispatch(removeAutofill(autofillRef));
},
[dispatch],
);
};
/**
*
* @returns
*/
export const useResetAutofillRefs = () => {
const dispatch = useDispatch();
return () => {
return dispatch(resetAutofill());
};
};
/**
*
* @param {(payload: any, ref: number) => void} callback
* @returns {number}
*/
export const useCreateAutofillListener = (
callback: (payload: any, ref: number) => void,
): number => {
const ref = useRef<number>(Date.now());
const autofillPayload = useGetAutofillPayload(ref.current);
const removeAutofill = useRemoveAutofillRef();
useEffect(() => {
if (autofillPayload) {
callback(autofillPayload, ref.current);
removeAutofill(ref.current);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [autofillPayload, removeAutofill]);
return ref.current;
};

View File

@@ -125,3 +125,23 @@ export function closeSidebarSubmenu() {
type: t.SIDEBAR_SUBMENU_CLOSE, type: t.SIDEBAR_SUBMENU_CLOSE,
}; };
} }
export function addAutofill(autofillRef: number, payload: any) {
return {
type: t.ADD_AUTOFILL_REF,
payload: { ref: autofillRef, payload }
}
}
export function removeAutofill(autofillRef: number) {
return {
type: t.REMOVE_AUTOFILL_REF,
payload: { ref: autofillRef}
}
}
export function resetAutofill() {
return {
type: t.RESET_AUTOFILL_REF,
}
}

View File

@@ -1,11 +1,10 @@
// @ts-nocheck // @ts-nocheck
import { createReducer } from '@reduxjs/toolkit'; import { createReducer } from '@reduxjs/toolkit';
import { isUndefined, isNumber } from 'lodash'; import { isUndefined, isNumber, omit } from 'lodash';
import t from '@/store/types'; import t from '@/store/types';
import { persistReducer, purgeStoredState } from 'redux-persist'; import { persistReducer, purgeStoredState } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; import storage from 'redux-persist/lib/storage';
const initialState = { const initialState = {
pageTitle: '', pageTitle: '',
pageSubtitle: '', pageSubtitle: '',
@@ -23,6 +22,7 @@ const initialState = {
appIntlIsLoading: true, appIntlIsLoading: true,
sidebarSubmenu: { isOpen: false, submenuId: null }, sidebarSubmenu: { isOpen: false, submenuId: null },
features: {}, features: {},
autofill: {},
}; };
const STORAGE_KEY = 'bigcapital:dashboard'; const STORAGE_KEY = 'bigcapital:dashboard';
@@ -143,6 +143,18 @@ const reducerInstance = createReducer(initialState, {
[t.RESET]: () => { [t.RESET]: () => {
purgeStoredState(CONFIG); purgeStoredState(CONFIG);
}, },
[t.ADD_AUTOFILL_REF]: (state, action) => {
state.autofill[action.payload.ref] = action.payload.payload || null;
},
[t.REMOVE_AUTOFILL_REF]: (state, action) => {
state.autofill = omit(state.autofill, [action.payload.ref]);
},
[t.RESET_AUTOFILL_REF]: (state, action) => {
state.autofill = {};
},
}); });
export default persistReducer(CONFIG, reducerInstance); export default persistReducer(CONFIG, reducerInstance);

View File

@@ -21,4 +21,7 @@ export default {
SPLASH_START_LOADING: 'SPLASH_START_LOADING', SPLASH_START_LOADING: 'SPLASH_START_LOADING',
SPLASH_STOP_LOADING: 'SPLASH_STOP_LOADING', SPLASH_STOP_LOADING: 'SPLASH_STOP_LOADING',
SET_FEATURE_DASHBOARD_META: 'SET_FEATURE_DASHBOARD_META', SET_FEATURE_DASHBOARD_META: 'SET_FEATURE_DASHBOARD_META',
ADD_AUTOFILL_REF: 'ADD_AUTOFILL_REF',
REMOVE_AUTOFILL_REF: 'REMOVE_AUTOFILL_REF',
RESET_AUTOFILL_REF: 'RESET_AUTOFILL_REF'
}; };