mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
fix: autofill the quick created customer/vendor
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { createNewItemFromQuery, createNewItemRenderer } from './utils';
|
||||
import { FSelect } from '../Forms';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { useCreateAutofillListener } from '@/hooks/state/autofill';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
@@ -17,6 +19,7 @@ function CustomerSelectRoot({
|
||||
// #ownProps
|
||||
items,
|
||||
allowCreate,
|
||||
name,
|
||||
...props
|
||||
}) {
|
||||
// Maybe inject create new item props to suggest component.
|
||||
@@ -24,14 +27,21 @@ function CustomerSelectRoot({
|
||||
const maybeCreateNewItemFromQuery = allowCreate
|
||||
? createNewItemFromQuery
|
||||
: 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.
|
||||
const handleCreateItemClick = () => {
|
||||
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
|
||||
const handleCreateItemClick = (item) => {
|
||||
const displayName = item.name;
|
||||
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER, { autofillRef, displayName });
|
||||
};
|
||||
|
||||
return (
|
||||
<FSelect
|
||||
name={name}
|
||||
items={items}
|
||||
textAccessor={'display_name'}
|
||||
labelAccessor={'formatted_balance'}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import { useFormikContext } from 'formik';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { createNewItemFromQuery, createNewItemRenderer } from './utils';
|
||||
import { FSelect } from '../Forms';
|
||||
import { useCreateAutofillListener } from '@/hooks/state/autofill';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
@@ -15,6 +17,7 @@ function VendorsSelectRoot({
|
||||
openDrawer,
|
||||
|
||||
// #ownProps
|
||||
name,
|
||||
items,
|
||||
allowCreate,
|
||||
|
||||
@@ -25,14 +28,24 @@ function VendorsSelectRoot({
|
||||
const maybeCreateNewItemFromQuery = allowCreate
|
||||
? createNewItemFromQuery
|
||||
: 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.
|
||||
const handleCreateItemClick = () => {
|
||||
openDrawer(DRAWERS.QUICK_WRITE_VENDOR);
|
||||
const handleCreateItemClick = (item) => {
|
||||
openDrawer(DRAWERS.QUICK_WRITE_VENDOR, {
|
||||
autofillRef,
|
||||
displayName: item.name,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<FSelect
|
||||
name={name}
|
||||
items={items}
|
||||
textAccessor={'display_name'}
|
||||
labelAccessor={'formatted_balance'}
|
||||
|
||||
@@ -52,7 +52,7 @@ function CustomerFormFormik({
|
||||
...defaultInitialValues,
|
||||
currency_code: base_currency,
|
||||
...transformToForm(contactDuplicate || customer, defaultInitialValues),
|
||||
...initialCustomerValues,
|
||||
...transformToForm(initialCustomerValues, defaultInitialValues),
|
||||
}),
|
||||
[customer, contactDuplicate, base_currency, initialCustomerValues],
|
||||
);
|
||||
@@ -62,7 +62,7 @@ function CustomerFormFormik({
|
||||
const { setSubmitting, resetForm } = formArgs;
|
||||
const formValues = { ...values };
|
||||
|
||||
const onSuccess = () => {
|
||||
const onSuccess = (res) => {
|
||||
AppToaster.show({
|
||||
message: intl.get(
|
||||
isNewMode
|
||||
@@ -73,8 +73,7 @@ function CustomerFormFormik({
|
||||
});
|
||||
setSubmitting(false);
|
||||
resetForm();
|
||||
|
||||
saveInvoke(onSubmitSuccess, values, formArgs, submitPayload);
|
||||
saveInvoke(onSubmitSuccess, values, formArgs, submitPayload, res.data);
|
||||
};
|
||||
|
||||
const onError = () => {
|
||||
|
||||
@@ -5,14 +5,16 @@ import {
|
||||
DrawerBody,
|
||||
FormattedMessage as T,
|
||||
} from '@/components';
|
||||
|
||||
import QuickCustomerFormDrawer from './QuickCustomerFormDrawer';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
* Quick create/edit customer drawer.
|
||||
*/
|
||||
export default function QuickCreateCustomerDrawerContent({ displayName }) {
|
||||
export default function QuickCreateCustomerDrawerContent({
|
||||
displayName,
|
||||
autofillRef,
|
||||
}) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<DrawerHeaderContent
|
||||
@@ -20,7 +22,10 @@ export default function QuickCreateCustomerDrawerContent({ displayName }) {
|
||||
title={<T id={'create_a_new_customer'} />}
|
||||
/>
|
||||
<DrawerBody>
|
||||
<QuickCustomerFormDrawer displayName={displayName} />
|
||||
<QuickCustomerFormDrawer
|
||||
displayName={displayName}
|
||||
autofillRef={autofillRef}
|
||||
/>
|
||||
</DrawerBody>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -14,6 +14,7 @@ import CustomerFormFormik, {
|
||||
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
import { useAddAutofillRef } from '@/hooks/state/autofill';
|
||||
|
||||
/**
|
||||
* Drawer customer form loading wrapper.
|
||||
@@ -28,9 +29,22 @@ function DrawerCustomerFormLoading({ children }) {
|
||||
/**
|
||||
* 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.
|
||||
const handleSubmitSuccess = () => {
|
||||
const handleSubmitSuccess = (values, formArgs, submitPayload, res) => {
|
||||
if (autofillRef) {
|
||||
addAutofillRef(autofillRef, {
|
||||
displayName: values.display_name,
|
||||
customerId: res.id,
|
||||
});
|
||||
}
|
||||
closeDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
|
||||
};
|
||||
// Handle the form cancel action.
|
||||
@@ -43,7 +57,7 @@ function QuickCustomerFormDrawer({ displayName, closeDrawer, customerId }) {
|
||||
<DrawerCustomerFormLoading>
|
||||
<CustomerFormCard>
|
||||
<CustomerFormFormik
|
||||
initialValues={{ display_name: displayName }}
|
||||
initialValues={{ first_name: displayName }}
|
||||
onSubmitSuccess={handleSubmitSuccess}
|
||||
onCancel={handleCancelForm}
|
||||
/>
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
import React from 'react';
|
||||
import { Drawer, DrawerSuspense } from '@/components';
|
||||
import withDrawers from '@/containers/Drawer/withDrawers';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
const QuickCreateCustomerDrawerContent = React.lazy(() =>
|
||||
import('./QuickCreateCustomerDrawerContent'),
|
||||
const QuickCreateCustomerDrawerContent = React.lazy(
|
||||
() => import('./QuickCreateCustomerDrawerContent'),
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -17,7 +16,7 @@ function QuickCreateCustomerDrawer({
|
||||
|
||||
// #withDrawer
|
||||
isOpen,
|
||||
payload,
|
||||
payload: { autofillRef, displayName },
|
||||
}) {
|
||||
return (
|
||||
<Drawer
|
||||
@@ -27,7 +26,10 @@ function QuickCreateCustomerDrawer({
|
||||
size={'80%'}
|
||||
>
|
||||
<DrawerSuspense>
|
||||
<QuickCreateCustomerDrawerContent displayName={payload.displayName} />
|
||||
<QuickCreateCustomerDrawerContent
|
||||
displayName={displayName}
|
||||
autofillRef={autofillRef}
|
||||
/>
|
||||
</DrawerSuspense>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
|
||||
|
||||
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||
import { useAddAutofillRef } from '@/hooks/state/autofill';
|
||||
import { DRAWERS } from '@/constants/drawers';
|
||||
|
||||
/**
|
||||
@@ -36,17 +37,20 @@ function QuickVendorFormDrawer({
|
||||
closeDrawer,
|
||||
vendorId,
|
||||
addQuickActionEvent,
|
||||
autofillRef,
|
||||
}) {
|
||||
const { payload } = useDrawerContext();
|
||||
const addAutofillRef = useAddAutofillRef();
|
||||
|
||||
// Handle the form submit request success.
|
||||
const handleSubmitSuccess = (values, form, submitPayload, response) => {
|
||||
const handleSubmitSuccess = (values, form, submitPayload, res) => {
|
||||
if (!submitPayload.noRedirect) {
|
||||
closeDrawer(DRAWERS.QUICK_WRITE_VENDOR);
|
||||
}
|
||||
if (payload.quickActionEvent) {
|
||||
addQuickActionEvent(payload.quickActionEvent, {
|
||||
vendorId: response.data.id,
|
||||
if (autofillRef) {
|
||||
addAutofillRef(autofillRef, {
|
||||
displayName: values.display_name,
|
||||
vendorId: res.id,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -60,7 +64,7 @@ function QuickVendorFormDrawer({
|
||||
<DrawerVendorFormLoading>
|
||||
<VendorFormCard>
|
||||
<VendorFormFormik
|
||||
initialValues={{ display_name: displayName }}
|
||||
initialValues={{ first_name: displayName }}
|
||||
onSubmitSuccess={handleSubmitSuccess}
|
||||
onCancel={handleCancelForm}
|
||||
/>
|
||||
|
||||
@@ -12,7 +12,7 @@ import { DRAWERS } from '@/constants/drawers';
|
||||
/**
|
||||
* Quick create/edit vendor drawer.
|
||||
*/
|
||||
export default function QuickWriteVendorDrawerContent({ displayName }) {
|
||||
export default function QuickWriteVendorDrawerContent({ displayName, autofillRef }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<DrawerHeaderContent
|
||||
@@ -21,7 +21,7 @@ export default function QuickWriteVendorDrawerContent({ displayName }) {
|
||||
|
||||
/>
|
||||
<DrawerBody>
|
||||
<QuickVendorFormDrawer displayName={displayName} />
|
||||
<QuickVendorFormDrawer displayName={displayName} autofillRef={autofillRef} />
|
||||
</DrawerBody>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -17,7 +17,7 @@ function QuickWriteVendorDrawer({
|
||||
|
||||
// #withDrawer
|
||||
isOpen,
|
||||
payload,
|
||||
payload: { displayName, autofillRef },
|
||||
}) {
|
||||
return (
|
||||
<Drawer
|
||||
@@ -25,10 +25,9 @@ function QuickWriteVendorDrawer({
|
||||
name={name}
|
||||
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||
size={'80%'}
|
||||
payload={payload}
|
||||
>
|
||||
<DrawerSuspense>
|
||||
<QuickWriteVendorDrawerContent displayName={payload.displayName} />
|
||||
<QuickWriteVendorDrawerContent displayName={displayName} autofillRef={autofillRef} />
|
||||
</DrawerSuspense>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
@@ -34,6 +34,7 @@ function VendorFormFormik({
|
||||
organization: { base_currency },
|
||||
|
||||
// #ownProps
|
||||
initialValues,
|
||||
onSubmitSuccess,
|
||||
onSubmitError,
|
||||
onCancel,
|
||||
@@ -54,14 +55,15 @@ function VendorFormFormik({
|
||||
/**
|
||||
* Initial values in create and edit mode.
|
||||
*/
|
||||
const initialValues = useMemo(
|
||||
const initialFormValues = useMemo(
|
||||
() => ({
|
||||
...defaultInitialValues,
|
||||
...transformToForm(initialValues, defaultInitialValues),
|
||||
currency_code: base_currency,
|
||||
...transformToForm(vendor, defaultInitialValues),
|
||||
...transformToForm(contactDuplicate, defaultInitialValues),
|
||||
}),
|
||||
[vendor, contactDuplicate, base_currency],
|
||||
[vendor, contactDuplicate, base_currency, initialValues],
|
||||
);
|
||||
|
||||
// Handles the form submit.
|
||||
@@ -84,7 +86,7 @@ function VendorFormFormik({
|
||||
setSubmitting(false);
|
||||
resetForm();
|
||||
|
||||
safeInvoke(onSubmitSuccess, values, form, submitPayload, response);
|
||||
safeInvoke(onSubmitSuccess, values, form, submitPayload, response.data);
|
||||
};
|
||||
|
||||
const onError = () => {
|
||||
@@ -112,7 +114,7 @@ function VendorFormFormik({
|
||||
validationSchema={
|
||||
isNewMode ? CreateVendorFormSchema : EditVendorFormSchema
|
||||
}
|
||||
initialValues={initialValues}
|
||||
initialValues={initialFormValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
<Form>
|
||||
|
||||
94
packages/webapp/src/hooks/state/autofill.ts
Normal file
94
packages/webapp/src/hooks/state/autofill.ts
Normal 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;
|
||||
};
|
||||
@@ -125,3 +125,23 @@ export function closeSidebarSubmenu() {
|
||||
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,
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
// @ts-nocheck
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { isUndefined, isNumber } from 'lodash';
|
||||
import { isUndefined, isNumber, omit } from 'lodash';
|
||||
import t from '@/store/types';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
|
||||
|
||||
const initialState = {
|
||||
pageTitle: '',
|
||||
pageSubtitle: '',
|
||||
@@ -23,6 +22,7 @@ const initialState = {
|
||||
appIntlIsLoading: true,
|
||||
sidebarSubmenu: { isOpen: false, submenuId: null },
|
||||
features: {},
|
||||
autofill: {},
|
||||
};
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:dashboard';
|
||||
@@ -143,6 +143,18 @@ const reducerInstance = createReducer(initialState, {
|
||||
[t.RESET]: () => {
|
||||
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);
|
||||
|
||||
@@ -21,4 +21,7 @@ export default {
|
||||
SPLASH_START_LOADING: 'SPLASH_START_LOADING',
|
||||
SPLASH_STOP_LOADING: 'SPLASH_STOP_LOADING',
|
||||
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'
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user