feat: quick create action on select/suggest items fields.

This commit is contained in:
a.bouhuolia
2021-11-10 20:49:50 +02:00
parent d8e9be0246
commit da67217d74
61 changed files with 1885 additions and 745 deletions

View File

@@ -9,42 +9,43 @@ import {
Menu,
MenuItem,
} from '@blueprintjs/core';
import { FormattedMessage as T } from 'components';
import styled from 'styled-components';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
import { useFormikContext } from 'formik';
import { useHistory } from 'react-router-dom';
import { FormattedMessage as T } from 'components';
import { CLASSES } from 'common/classes';
import { Icon } from 'components';
import { useVendorFormContext } from './VendorFormProvider';
import { safeInvoke } from 'utils';
/**
* Vendor floating actions bar.
*/
export default function VendorFloatingActions() {
export default function VendorFloatingActions({ onCancel }) {
// Formik context.
const { resetForm, isSubmitting, submitForm } = useFormikContext();
// Vendor form context.
const { isNewMode, setSubmitPayload } = useVendorFormContext();
// History.
const history = useHistory();
// Handle the submit button.
const handleSubmitBtnClick = (event) => {
setSubmitPayload({ noRedirect: false, });
setSubmitPayload({ noRedirect: false });
submitForm();
};
// Handle the submit & new button click.
const handleSubmitAndNewClick = (event) => {
submitForm();
setSubmitPayload({ noRedirect: true, });
setSubmitPayload({ noRedirect: true });
};
// Handle cancel button click.
const handleCancelBtnClick = (event) => {
history.goBack();
safeInvoke(onCancel, event);
};
// Handle clear button click.
@@ -56,7 +57,7 @@ export default function VendorFloatingActions() {
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
<ButtonGroup>
{/* ----------- Save and New ----------- */}
<Button
<SaveButton
disabled={isSubmitting}
loading={isSubmitting}
intent={Intent.PRIMARY}
@@ -101,3 +102,7 @@ export default function VendorFloatingActions() {
</div>
);
}
const SaveButton = styled(Button)`
min-width: 100px;
`;

View File

@@ -1,13 +1,10 @@
import React, { useMemo, useEffect } from 'react';
import React, { useMemo } from 'react';
import { Formik, Form } from 'formik';
import moment from 'moment';
import { Intent } from '@blueprintjs/core';
import intl from 'react-intl-universal';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
import { CLASSES } from 'common/classes';
import { FormattedMessage as T } from 'components';
import AppToaster from 'components/AppToaster';
import {
CreateVendorFormSchema,
@@ -19,56 +16,27 @@ import VendorFormAfterPrimarySection from './VendorFormAfterPrimarySection';
import VendorTabs from './VendorsTabs';
import VendorFloatingActions from './VendorFloatingActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
import { useVendorFormContext } from './VendorFormProvider';
import { compose, transformToForm } from 'utils';
import { compose, transformToForm, safeInvoke } from 'utils';
const defaultInitialValues = {
salutation: '',
first_name: '',
last_name: '',
company_name: '',
display_name: '',
import { defaultInitialValues } from './utils';
email: '',
work_phone: '',
personal_phone: '',
website: '',
note: '',
active: true,
billing_address_country: '',
billing_address_1: '',
billing_address_2: '',
billing_address_city: '',
billing_address_state: '',
billing_address_postcode: '',
billing_address_phone: '',
shipping_address_country: '',
shipping_address_1: '',
shipping_address_2: '',
shipping_address_city: '',
shipping_address_state: '',
shipping_address_postcode: '',
shipping_address_phone: '',
opening_balance: '',
currency_code: '',
opening_balance_at: moment(new Date()).format('YYYY-MM-DD'),
};
import 'style/pages/Vendors/Form.scss';
/**
* Vendor form.
*/
function VendorForm({
// #withDashboardActions
changePageTitle,
function VendorFormFormik({
// #withCurrentOrganization
organization: { base_currency },
// #ownProps
onSubmitSuccess,
onSubmitError,
onCancel,
className,
}) {
// Vendor form context.
const {
@@ -82,11 +50,6 @@ function VendorForm({
isNewMode,
} = useVendorFormContext();
// const isNewMode = !vendorId;
// History context.
const history = useHistory();
/**
* Initial values in create and edit mode.
*/
@@ -101,14 +64,13 @@ function VendorForm({
);
// Handles the form submit.
const handleFormSubmit = (
values,
{ setSubmitting, resetForm, setErrors },
) => {
const handleFormSubmit = (values, form) => {
const { setSubmitting, resetForm } = form;
const requestForm = { ...values };
setSubmitting(true);
const onSuccess = () => {
const onSuccess = (response) => {
AppToaster.show({
message: intl.get(
isNewMode
@@ -121,16 +83,15 @@ function VendorForm({
setSubmitting(false);
resetForm();
if (!submitPayload.noRedirect) {
history.push('/vendors');
}
safeInvoke(onSubmitSuccess, values, form, submitPayload, response);
};
const onError = () => {
setSubmitPayload(false);
setSubmitting(false);
};
safeInvoke(onSubmitError, values, form, submitPayload);
};
if (isNewMode) {
createVendorMutate(requestForm).then(onSuccess).catch(onError);
} else {
@@ -139,7 +100,13 @@ function VendorForm({
};
return (
<div className={classNames(CLASSES.PAGE_FORM, CLASSES.PAGE_FORM_VENDOR)}>
<div
className={classNames(
CLASSES.PAGE_FORM,
CLASSES.PAGE_FORM_VENDOR,
className,
)}
>
<Formik
validationSchema={
isNewMode ? CreateVendorFormSchema : EditVendorFormSchema
@@ -160,14 +127,11 @@ function VendorForm({
<VendorTabs vendor={vendorId} />
</div>
<VendorFloatingActions />
<VendorFloatingActions onCancel={onCancel} />
</Form>
</Formik>
</div>
);
}
export default compose(
withDashboardActions,
withCurrentOrganization(),
)(VendorForm);
export default compose(withCurrentOrganization())(VendorFormFormik);

View File

@@ -1,26 +1,69 @@
import React from 'react';
import { useParams } from 'react-router-dom';
import { useParams, useHistory } from 'react-router-dom';
import styled from 'styled-components';
import 'style/pages/Vendors/PageForm.scss';
import { DashboardCard } from 'components';
import VendorFrom from './VendorForm';
import { DashboardCard, DashboardInsider } from 'components';
import VendorFormFormik from './VendorFormFormik';
import { VendorFormProvider } from './VendorFormProvider';
import { VendorFormProvider, useVendorFormContext } from './VendorFormProvider';
/**
* Vendor form page loading wrapper.
* @returns {JSX}
*/
function VendorFormPageLoading({ children }) {
const { isFormLoading } = useVendorFormContext();
return (
<VendorDashboardInsider loading={isFormLoading}>
{children}
</VendorDashboardInsider>
);
}
/**
* Vendor form page.
*/
function VendorFormPage() {
export default function VendorFormPage() {
const history = useHistory();
const { id } = useParams();
// Handle the form submit success.
const handleSubmitSuccess = (values, formArgs, submitPayload) => {
if (!submitPayload.noRedirect) {
history.push('/vendors');
}
};
// Handle the form cancel button click.
const handleFormCancel = () => {
history.goBack();
};
return (
<VendorFormProvider vendorId={id}>
<DashboardCard page>
<VendorFrom />
</DashboardCard>
<VendorFormPageLoading>
<DashboardCard page>
<VendorFormPageFormik
onSubmitSuccess={handleSubmitSuccess}
onCancel={handleFormCancel}
/>
</DashboardCard>
</VendorFormPageLoading>
</VendorFormProvider>
);
}
export default VendorFormPage;
const VendorFormPageFormik = styled(VendorFormFormik)`
.page-form {
&__floating-actions {
margin-left: -40px;
margin-right: -40px;
}
}
`;
const VendorDashboardInsider = styled(DashboardInsider)`
padding-bottom: 64px;
`;

View File

@@ -6,7 +6,6 @@ import {
useVendor,
useContact,
useCurrencies,
useCustomer,
useCreateVendor,
useEditVendor,
} from 'hooks/query';
@@ -30,11 +29,10 @@ function VendorFormProvider({ vendorId, ...props }) {
});
// Handle fetch contact duplicate details.
const {
data: contactDuplicate,
isLoading: isContactLoading,
} = useContact(contactId, { enabled: !!contactId });
const { data: contactDuplicate, isLoading: isContactLoading } = useContact(
contactId,
{ enabled: !!contactId },
);
// Create and edit vendor mutations.
const { mutateAsync: createVendorMutate } = useCreateVendor();
const { mutateAsync: editVendorMutate } = useEditVendor();
@@ -45,27 +43,25 @@ function VendorFormProvider({ vendorId, ...props }) {
// determines whether the form new or duplicate mode.
const isNewMode = contactId || !vendorId;
const isFormLoading =
isVendorLoading || isContactLoading || isCurrenciesLoading;
const provider = {
vendorId,
currencies,
vendor,
contactDuplicate: { ...omit(contactDuplicate, ['opening_balance_at']) },
submitPayload,
isNewMode,
isFormLoading,
createVendorMutate,
editVendorMutate,
setSubmitPayload,
};
return (
<DashboardInsider
loading={isVendorLoading || isContactLoading || isCurrenciesLoading}
name={'vendor-form'}
>
<VendorFormContext.Provider value={provider} {...props} />
</DashboardInsider>
);
return <VendorFormContext.Provider value={provider} {...props} />;
}
const useVendorFormContext = () => React.useContext(VendorFormContext);

View File

@@ -0,0 +1,36 @@
import moment from 'moment';
export const defaultInitialValues = {
salutation: '',
first_name: '',
last_name: '',
company_name: '',
display_name: '',
email: '',
work_phone: '',
personal_phone: '',
website: '',
note: '',
active: true,
billing_address_country: '',
billing_address_1: '',
billing_address_2: '',
billing_address_city: '',
billing_address_state: '',
billing_address_postcode: '',
billing_address_phone: '',
shipping_address_country: '',
shipping_address_1: '',
shipping_address_2: '',
shipping_address_city: '',
shipping_address_state: '',
shipping_address_postcode: '',
shipping_address_phone: '',
opening_balance: '',
currency_code: '',
opening_balance_at: moment(new Date()).format('YYYY-MM-DD'),
};