Exit form fixes (#1889)
* Add onBeforeUnload handler to prevent accidental refresh * Update button messages * Fix exit form not working after submit * Make onBeforeUnload disable if env is development * Fix onClose * Remove internal date time field state * Update messages and dialog * Prevent navigation on 400 error * Add submit disabled ref in exit form * Update exit form dialog for disabled save * Update confirmLeave forms to set ref if save is disabled * Remove unused error handling * Remove explicit ref type * Remove unused import * Fix disabled type * Add disable check function to generic forms * Add custom isDisabled method to sale and voucher forms * Add default isDisabled functions to confirmLeave forms * Update tests * Remove unused code * Rebase fixes + update tests * Refactor form and useform * Refactor disabling forms * Change "saveDisabled" name to "isSaveDisabled" for improved readability * Change "isDisabled" function to "checkIfSaveIsDisabled" * Update exit form disabling conditions for zone rates forms
This commit is contained in:
parent
7576afed4e
commit
a5ac6bb92e
59 changed files with 717 additions and 390 deletions
|
@ -2231,19 +2231,23 @@
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_Form_dot_cancelButton": {
|
"src_dot_components_dot_Form_dot_cancelButton": {
|
||||||
"context": "ExitFormPrompt cancel button",
|
"context": "ExitFormPrompt cancel button",
|
||||||
"string": "leave without saving"
|
"string": "Discard changes"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_Form_dot_confirmButton": {
|
"src_dot_components_dot_Form_dot_confirmButton": {
|
||||||
"context": "ExitFormPrompt confirm button",
|
"context": "ExitFormPrompt confirm button",
|
||||||
"string": "save & continue"
|
"string": "Save changes"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_Form_dot_description": {
|
"src_dot_components_dot_Form_dot_continueEditingButton": {
|
||||||
"context": "ExitFormPrompt description",
|
"context": "ExitFormPrompt continue editing button",
|
||||||
"string": "You have unsaved changes on this view. What would you like to do with them?"
|
"string": "Continue editing"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_Form_dot_title": {
|
"src_dot_components_dot_Form_dot_title": {
|
||||||
"context": "ExitFormPrompt title",
|
"context": "ExitFormPrompt title",
|
||||||
"string": "Are you sure you want to leave?"
|
"string": "Would you like to save changes?"
|
||||||
|
},
|
||||||
|
"src_dot_components_dot_Form_dot_unableToSaveTitle": {
|
||||||
|
"context": "ExitFormPrompt title",
|
||||||
|
"string": "You have unsaved changes"
|
||||||
},
|
},
|
||||||
"src_dot_components_dot_ImageUpload_dot_1731007575": {
|
"src_dot_components_dot_ImageUpload_dot_1731007575": {
|
||||||
"context": "image upload",
|
"context": "image upload",
|
||||||
|
|
|
@ -56,8 +56,13 @@ const CustomAppCreatePage: React.FC<CustomAppCreatePageProps> = props => {
|
||||||
const permissionsError = getAppErrorMessage(formErrors.permissions, intl);
|
const permissionsError = getAppErrorMessage(formErrors.permissions, intl);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ data, change, hasChanged, submit }) => (
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ data, change, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.apps)}
|
{intl.formatMessage(sectionNames.apps)}
|
||||||
|
@ -96,7 +101,7 @@ const CustomAppCreatePage: React.FC<CustomAppCreatePageProps> = props => {
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -101,8 +101,13 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ data, change, hasChanged, submit }) => (
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ data, change, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.apps)}
|
{intl.formatMessage(sectionNames.apps)}
|
||||||
|
@ -182,7 +187,7 @@ const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -156,12 +156,17 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={handleSubmit}>
|
<Form
|
||||||
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
{({
|
{({
|
||||||
change,
|
change,
|
||||||
set,
|
set,
|
||||||
data,
|
data,
|
||||||
hasChanged,
|
isSaveDisabled,
|
||||||
submit,
|
submit,
|
||||||
errors,
|
errors,
|
||||||
setError,
|
setError,
|
||||||
|
@ -239,7 +244,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -31,8 +31,8 @@ export const CategoryCreatePage: React.FC<CategoryCreatePageProps> = ({
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CategoryCreateForm onSubmit={onSubmit}>
|
<CategoryCreateForm onSubmit={onSubmit} disabled={disabled}>
|
||||||
{({ data, change, handlers, submit, hasChanged }) => (
|
{({ data, change, handlers, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.categories)}
|
{intl.formatMessage(sectionNames.categories)}
|
||||||
|
@ -74,7 +74,7 @@ export const CategoryCreatePage: React.FC<CategoryCreatePageProps> = ({
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -33,6 +33,7 @@ export interface UseCategoryCreateFormResult
|
||||||
export interface CategoryCreateFormProps {
|
export interface CategoryCreateFormProps {
|
||||||
children: (props: UseCategoryCreateFormResult) => React.ReactNode;
|
children: (props: UseCategoryCreateFormResult) => React.ReactNode;
|
||||||
onSubmit: (data: CategoryCreateData) => Promise<any[]>;
|
onSubmit: (data: CategoryCreateData) => Promise<any[]>;
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialData: CategoryCreateFormData = {
|
const initialData: CategoryCreateFormData = {
|
||||||
|
@ -45,7 +46,8 @@ const initialData: CategoryCreateFormData = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function useCategoryCreateForm(
|
function useCategoryCreateForm(
|
||||||
onSubmit: (data: CategoryCreateData) => Promise<any[]>
|
onSubmit: (data: CategoryCreateData) => Promise<any[]>,
|
||||||
|
disabled: boolean
|
||||||
): UseCategoryCreateFormResult {
|
): UseCategoryCreateFormResult {
|
||||||
const {
|
const {
|
||||||
handleChange,
|
handleChange,
|
||||||
|
@ -53,7 +55,8 @@ function useCategoryCreateForm(
|
||||||
hasChanged,
|
hasChanged,
|
||||||
triggerChange,
|
triggerChange,
|
||||||
setChanged,
|
setChanged,
|
||||||
formId
|
formId,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = useForm(initialData, undefined, { confirmLeave: true });
|
} = useForm(initialData, undefined, { confirmLeave: true });
|
||||||
|
|
||||||
const handleFormSubmit = useHandleFormSubmit({
|
const handleFormSubmit = useHandleFormSubmit({
|
||||||
|
@ -87,6 +90,9 @@ function useCategoryCreateForm(
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
|
const isSaveDisabled = disabled || !hasChanged;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data: getData(),
|
data: getData(),
|
||||||
|
@ -95,15 +101,17 @@ function useCategoryCreateForm(
|
||||||
changeMetadata
|
changeMetadata
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const CategoryCreateForm: React.FC<CategoryCreateFormProps> = ({
|
const CategoryCreateForm: React.FC<CategoryCreateFormProps> = ({
|
||||||
children,
|
children,
|
||||||
onSubmit
|
onSubmit,
|
||||||
|
disabled
|
||||||
}) => {
|
}) => {
|
||||||
const props = useCategoryCreateForm(onSubmit);
|
const props = useCategoryCreateForm(onSubmit, disabled);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,8 +92,12 @@ export const CategoryUpdatePage: React.FC<CategoryUpdatePageProps> = ({
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CategoryUpdateForm category={category} onSubmit={onSubmit}>
|
<CategoryUpdateForm
|
||||||
{({ data, change, handlers, submit, hasChanged }) => (
|
category={category}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ data, change, handlers, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.categories)}
|
{intl.formatMessage(sectionNames.categories)}
|
||||||
|
@ -217,7 +221,7 @@ export const CategoryUpdatePage: React.FC<CategoryUpdatePageProps> = ({
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -38,6 +38,7 @@ export interface CategoryUpdateFormProps {
|
||||||
children: (props: UseCategoryUpdateFormResult) => React.ReactNode;
|
children: (props: UseCategoryUpdateFormResult) => React.ReactNode;
|
||||||
category: CategoryDetailsFragment;
|
category: CategoryDetailsFragment;
|
||||||
onSubmit: (data: CategoryUpdateData) => Promise<any[]>;
|
onSubmit: (data: CategoryUpdateData) => Promise<any[]>;
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInitialData = (category?: CategoryDetailsFragment) => ({
|
const getInitialData = (category?: CategoryDetailsFragment) => ({
|
||||||
|
@ -52,7 +53,8 @@ const getInitialData = (category?: CategoryDetailsFragment) => ({
|
||||||
|
|
||||||
function useCategoryUpdateForm(
|
function useCategoryUpdateForm(
|
||||||
category: CategoryDetailsFragment,
|
category: CategoryDetailsFragment,
|
||||||
onSubmit: (data: CategoryUpdateData) => Promise<any[]>
|
onSubmit: (data: CategoryUpdateData) => Promise<any[]>,
|
||||||
|
disabled: boolean
|
||||||
): UseCategoryUpdateFormResult {
|
): UseCategoryUpdateFormResult {
|
||||||
const {
|
const {
|
||||||
handleChange,
|
handleChange,
|
||||||
|
@ -60,7 +62,8 @@ function useCategoryUpdateForm(
|
||||||
triggerChange,
|
triggerChange,
|
||||||
hasChanged,
|
hasChanged,
|
||||||
setChanged,
|
setChanged,
|
||||||
formId
|
formId,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = useForm(getInitialData(category), undefined, { confirmLeave: true });
|
} = useForm(getInitialData(category), undefined, { confirmLeave: true });
|
||||||
|
|
||||||
const handleFormSubmit = useHandleFormSubmit({
|
const handleFormSubmit = useHandleFormSubmit({
|
||||||
|
@ -101,6 +104,9 @@ function useCategoryUpdateForm(
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
|
const isSaveDisabled = disabled || !hasChanged;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data: getData(),
|
data: getData(),
|
||||||
|
@ -109,16 +115,18 @@ function useCategoryUpdateForm(
|
||||||
changeMetadata
|
changeMetadata
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const CategoryUpdateForm: React.FC<CategoryUpdateFormProps> = ({
|
const CategoryUpdateForm: React.FC<CategoryUpdateFormProps> = ({
|
||||||
children,
|
children,
|
||||||
category,
|
category,
|
||||||
onSubmit
|
onSubmit,
|
||||||
|
disabled
|
||||||
}) => {
|
}) => {
|
||||||
const props = useCategoryUpdateForm(category, onSubmit);
|
const props = useCategoryUpdateForm(category, onSubmit, disabled);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import ShippingZonesCard from "@saleor/channels/components/ShippingZonesCard/ShippingZonesCard";
|
import ShippingZonesCard from "@saleor/channels/components/ShippingZonesCard/ShippingZonesCard";
|
||||||
import CardSpacer from "@saleor/components/CardSpacer";
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
import Form from "@saleor/components/Form";
|
import Form, { FormDataWithOpts } from "@saleor/components/Form";
|
||||||
import Grid from "@saleor/components/Grid";
|
import Grid from "@saleor/components/Grid";
|
||||||
import Savebar from "@saleor/components/Savebar";
|
import Savebar from "@saleor/components/Savebar";
|
||||||
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField";
|
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField";
|
||||||
|
@ -94,9 +94,25 @@ const ChannelDetailsPage = function<TErrors>({
|
||||||
!shippingZonesToDisplay.some(({ id }) => id === searchedZoneId)
|
!shippingZonesToDisplay.some(({ id }) => id === searchedZoneId)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const checkIfSaveIsDisabled = (data: FormDataWithOpts<FormData>) => {
|
||||||
|
const formDisabled =
|
||||||
|
!data.name ||
|
||||||
|
!data.slug ||
|
||||||
|
!data.currencyCode ||
|
||||||
|
!data.defaultCountry ||
|
||||||
|
!(data.name.trim().length > 0);
|
||||||
|
|
||||||
|
return disabled || formDisabled || !data.hasChanged;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave onSubmit={onSubmit} initial={initialData}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit, set }) => {
|
confirmLeave
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
initial={initialData}
|
||||||
|
checkIfSaveIsDisabled={checkIfSaveIsDisabled}
|
||||||
|
>
|
||||||
|
{({ change, data, submit, set, isSaveDisabled }) => {
|
||||||
const handleCurrencyCodeSelect = createSingleAutocompleteSelectHandler(
|
const handleCurrencyCodeSelect = createSingleAutocompleteSelectHandler(
|
||||||
change,
|
change,
|
||||||
setSelectedCurrencyCode,
|
setSelectedCurrencyCode,
|
||||||
|
@ -147,13 +163,6 @@ const ChannelDetailsPage = function<TErrors>({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const formDisabled =
|
|
||||||
!data.name ||
|
|
||||||
!data.slug ||
|
|
||||||
!data.currencyCode ||
|
|
||||||
!data.defaultCountry ||
|
|
||||||
!(data.name.trim().length > 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Grid>
|
<Grid>
|
||||||
|
@ -197,7 +206,7 @@ const ChannelDetailsPage = function<TErrors>({
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={disabled || formDisabled || !onSubmit || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -54,8 +54,9 @@ const CollectionCreatePage: React.FC<CollectionCreatePageProps> = ({
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
currentChannels={currentChannels}
|
currentChannels={currentChannels}
|
||||||
setChannels={onChannelsChange}
|
setChannels={onChannelsChange}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ change, data, handlers, hasChanged, submit }) => (
|
{({ change, data, handlers, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.collections)}
|
{intl.formatMessage(sectionNames.collections)}
|
||||||
|
@ -156,7 +157,7 @@ const CollectionCreatePage: React.FC<CollectionCreatePageProps> = ({
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -49,6 +49,7 @@ export interface CollectionCreateFormProps {
|
||||||
setChannels: (data: ChannelCollectionData[]) => void;
|
setChannels: (data: ChannelCollectionData[]) => void;
|
||||||
children: (props: UseCollectionCreateFormResult) => React.ReactNode;
|
children: (props: UseCollectionCreateFormResult) => React.ReactNode;
|
||||||
onSubmit: (data: CollectionCreateData) => SubmitPromise;
|
onSubmit: (data: CollectionCreateData) => SubmitPromise;
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInitialData = (
|
const getInitialData = (
|
||||||
|
@ -71,7 +72,8 @@ const getInitialData = (
|
||||||
function useCollectionCreateForm(
|
function useCollectionCreateForm(
|
||||||
currentChannels: ChannelCollectionData[],
|
currentChannels: ChannelCollectionData[],
|
||||||
setChannels: (data: ChannelCollectionData[]) => void,
|
setChannels: (data: ChannelCollectionData[]) => void,
|
||||||
onSubmit: (data: CollectionCreateData) => SubmitPromise
|
onSubmit: (data: CollectionCreateData) => SubmitPromise,
|
||||||
|
disabled: boolean
|
||||||
): UseCollectionCreateFormResult {
|
): UseCollectionCreateFormResult {
|
||||||
const {
|
const {
|
||||||
handleChange,
|
handleChange,
|
||||||
|
@ -79,7 +81,8 @@ function useCollectionCreateForm(
|
||||||
triggerChange,
|
triggerChange,
|
||||||
setChanged,
|
setChanged,
|
||||||
hasChanged,
|
hasChanged,
|
||||||
formId
|
formId,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = useForm(getInitialData(currentChannels), undefined, {
|
} = useForm(getInitialData(currentChannels), undefined, {
|
||||||
confirmLeave: true,
|
confirmLeave: true,
|
||||||
formId: COLLECTION_CREATE_FORM_ID
|
formId: COLLECTION_CREATE_FORM_ID
|
||||||
|
@ -122,6 +125,9 @@ function useCollectionCreateForm(
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
|
const isSaveDisabled = disabled || !hasChanged;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data: getData(),
|
data: getData(),
|
||||||
|
@ -131,7 +137,8 @@ function useCollectionCreateForm(
|
||||||
changeMetadata
|
changeMetadata
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,9 +146,15 @@ const CollectionCreateForm: React.FC<CollectionCreateFormProps> = ({
|
||||||
currentChannels,
|
currentChannels,
|
||||||
setChannels,
|
setChannels,
|
||||||
children,
|
children,
|
||||||
onSubmit
|
onSubmit,
|
||||||
|
disabled
|
||||||
}) => {
|
}) => {
|
||||||
const props = useCollectionCreateForm(currentChannels, setChannels, onSubmit);
|
const props = useCollectionCreateForm(
|
||||||
|
currentChannels,
|
||||||
|
setChannels,
|
||||||
|
onSubmit,
|
||||||
|
disabled
|
||||||
|
);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -73,8 +73,10 @@ const CollectionDetailsPage: React.FC<CollectionDetailsPageProps> = ({
|
||||||
currentChannels={currentChannels}
|
currentChannels={currentChannels}
|
||||||
setChannels={onChannelsChange}
|
setChannels={onChannelsChange}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
hasChannelChanged={hasChannelChanged}
|
||||||
>
|
>
|
||||||
{({ change, data, handlers, hasChanged, submit }) => (
|
{({ change, data, handlers, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.collections)}
|
{intl.formatMessage(sectionNames.collections)}
|
||||||
|
@ -150,7 +152,7 @@ const CollectionDetailsPage: React.FC<CollectionDetailsPageProps> = ({
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={disabled || (!hasChanged && !hasChannelChanged)}
|
disabled={isSaveDisabled}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onCollectionRemove}
|
onDelete={onCollectionRemove}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -48,6 +48,8 @@ export interface CollectionUpdateFormProps {
|
||||||
currentChannels: ChannelCollectionData[];
|
currentChannels: ChannelCollectionData[];
|
||||||
setChannels: (data: ChannelCollectionData[]) => void;
|
setChannels: (data: ChannelCollectionData[]) => void;
|
||||||
onSubmit: (data: CollectionUpdateData) => Promise<any[]>;
|
onSubmit: (data: CollectionUpdateData) => Promise<any[]>;
|
||||||
|
disabled: boolean;
|
||||||
|
hasChannelChanged: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInitialData = (
|
const getInitialData = (
|
||||||
|
@ -68,7 +70,9 @@ function useCollectionUpdateForm(
|
||||||
collection: CollectionDetailsFragment,
|
collection: CollectionDetailsFragment,
|
||||||
currentChannels: ChannelCollectionData[],
|
currentChannels: ChannelCollectionData[],
|
||||||
setChannels: (data: ChannelCollectionData[]) => void,
|
setChannels: (data: ChannelCollectionData[]) => void,
|
||||||
onSubmit: (data: CollectionUpdateData) => Promise<any[]>
|
onSubmit: (data: CollectionUpdateData) => Promise<any[]>,
|
||||||
|
disabled: boolean,
|
||||||
|
hasChannelChanged: boolean
|
||||||
): UseCollectionUpdateFormResult {
|
): UseCollectionUpdateFormResult {
|
||||||
const {
|
const {
|
||||||
handleChange,
|
handleChange,
|
||||||
|
@ -76,7 +80,8 @@ function useCollectionUpdateForm(
|
||||||
triggerChange,
|
triggerChange,
|
||||||
setChanged,
|
setChanged,
|
||||||
hasChanged,
|
hasChanged,
|
||||||
formId
|
formId,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = useForm(getInitialData(collection, currentChannels), undefined, {
|
} = useForm(getInitialData(collection, currentChannels), undefined, {
|
||||||
confirmLeave: true,
|
confirmLeave: true,
|
||||||
formId: COLLECTION_DETAILS_FORM_ID
|
formId: COLLECTION_DETAILS_FORM_ID
|
||||||
|
@ -126,6 +131,9 @@ function useCollectionUpdateForm(
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
|
const isSaveDisabled = disabled || (!hasChanged && !hasChannelChanged);
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data: getData(),
|
data: getData(),
|
||||||
|
@ -135,7 +143,8 @@ function useCollectionUpdateForm(
|
||||||
changeMetadata
|
changeMetadata
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,13 +153,17 @@ const CollectionUpdateForm: React.FC<CollectionUpdateFormProps> = ({
|
||||||
currentChannels,
|
currentChannels,
|
||||||
setChannels,
|
setChannels,
|
||||||
children,
|
children,
|
||||||
onSubmit
|
onSubmit,
|
||||||
|
disabled,
|
||||||
|
hasChannelChanged
|
||||||
}) => {
|
}) => {
|
||||||
const props = useCollectionUpdateForm(
|
const props = useCollectionUpdateForm(
|
||||||
collection,
|
collection,
|
||||||
currentChannels,
|
currentChannels,
|
||||||
setChannels,
|
setChannels,
|
||||||
onSubmit
|
onSubmit,
|
||||||
|
disabled,
|
||||||
|
hasChannelChanged
|
||||||
);
|
);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
|
|
|
@ -6,8 +6,8 @@ import {
|
||||||
ProductErrorWithAttributesFragment
|
ProductErrorWithAttributesFragment
|
||||||
} from "@saleor/graphql";
|
} from "@saleor/graphql";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { DateTime, joinDateTime, splitDateTime } from "@saleor/misc";
|
import { joinDateTime, splitDateTime } from "@saleor/misc";
|
||||||
import React, { useEffect, useState } from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
type DateTimeFieldProps = Omit<TextFieldProps, "label" | "error"> & {
|
type DateTimeFieldProps = Omit<TextFieldProps, "label" | "error"> & {
|
||||||
|
@ -21,14 +21,11 @@ export const DateTimeField: React.FC<DateTimeFieldProps> = ({
|
||||||
error,
|
error,
|
||||||
name,
|
name,
|
||||||
onChange,
|
onChange,
|
||||||
value: initialValue
|
value
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [value, setValue] = useState<DateTime>(
|
|
||||||
initialValue ? splitDateTime(initialValue) : { date: "", time: "" }
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => onChange(joinDateTime(value.date, value.time)), [value]);
|
const parsedValue = value ? splitDateTime(value) : { date: "", time: "" };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -41,10 +38,11 @@ export const DateTimeField: React.FC<DateTimeFieldProps> = ({
|
||||||
name={`${name}:date`}
|
name={`${name}:date`}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
const date = event.target.value;
|
const date = event.target.value;
|
||||||
setValue(value => ({ ...value, date }));
|
|
||||||
|
onChange(joinDateTime(date, parsedValue.time));
|
||||||
}}
|
}}
|
||||||
type="date"
|
type="date"
|
||||||
value={value.date}
|
value={parsedValue.date}
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
|
@ -56,10 +54,11 @@ export const DateTimeField: React.FC<DateTimeFieldProps> = ({
|
||||||
name={`${name}:time`}
|
name={`${name}:time`}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
const time = event.target.value;
|
const time = event.target.value;
|
||||||
setValue(value => ({ ...value, time }));
|
|
||||||
|
onChange(joinDateTime(parsedValue.date, time));
|
||||||
}}
|
}}
|
||||||
type="time"
|
type="time"
|
||||||
value={value.time}
|
value={parsedValue.time}
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { Button, Dialog, DialogContent, makeStyles } from "@material-ui/core";
|
import { Button, Dialog, DialogContent, makeStyles } from "@material-ui/core";
|
||||||
import HorizontalSpacer from "@saleor/apps/components/HorizontalSpacer";
|
import HorizontalSpacer from "@saleor/apps/components/HorizontalSpacer";
|
||||||
import CardSpacer from "@saleor/components/CardSpacer";
|
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import { exitFormPromptMessages as messages } from "./messages";
|
import { exitFormPromptMessages as messages } from "./messages";
|
||||||
|
|
||||||
|
@ -19,6 +18,12 @@ const useStyles = makeStyles(
|
||||||
buttonsContainer: {
|
buttonsContainer: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "flex-end"
|
justifyContent: "flex-end"
|
||||||
|
},
|
||||||
|
dialogContent: {
|
||||||
|
"@media (min-width: 800px)": {
|
||||||
|
minWidth: 500
|
||||||
|
},
|
||||||
|
paddingTop: 0
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{ name: "ExitFormPrompt" }
|
{ name: "ExitFormPrompt" }
|
||||||
|
@ -29,24 +34,27 @@ interface ExitFormDialogProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onLeave: () => void;
|
onLeave: () => void;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
isSubmitDisabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExitFormDialog: React.FC<ExitFormDialogProps> = ({
|
const ExitFormDialog: React.FC<ExitFormDialogProps> = ({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onLeave,
|
onLeave,
|
||||||
onClose,
|
onClose,
|
||||||
isOpen
|
isOpen,
|
||||||
|
isSubmitDisabled
|
||||||
}) => {
|
}) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog className={classes.container} open={isOpen}>
|
<Dialog className={classes.container} open={isOpen} onClose={onClose}>
|
||||||
<CardTitle title={intl.formatMessage(messages.title)} onClose={onClose} />
|
<CardTitle
|
||||||
<DialogContent>
|
title={intl.formatMessage(
|
||||||
<FormattedMessage {...messages.description} />
|
isSubmitDisabled ? messages.unableToSaveTitle : messages.title
|
||||||
<CardSpacer />
|
)}
|
||||||
<CardSpacer />
|
/>
|
||||||
|
<DialogContent className={classes.dialogContent}>
|
||||||
<div className={classes.buttonsContainer}>
|
<div className={classes.buttonsContainer}>
|
||||||
<Button onClick={onLeave}>
|
<Button onClick={onLeave}>
|
||||||
{intl.formatMessage(messages.cancelButton)}
|
{intl.formatMessage(messages.cancelButton)}
|
||||||
|
@ -55,10 +63,14 @@ const ExitFormDialog: React.FC<ExitFormDialogProps> = ({
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={onSubmit}
|
onClick={isSubmitDisabled ? onClose : onSubmit}
|
||||||
data-test-id="save-and-continue"
|
data-test-id="save-and-continue"
|
||||||
>
|
>
|
||||||
{intl.formatMessage(messages.confirmButton)}
|
{intl.formatMessage(
|
||||||
|
isSubmitDisabled
|
||||||
|
? messages.continueEditingButton
|
||||||
|
: messages.confirmButton
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import { SubmitPromise } from "@saleor/hooks/useForm";
|
import { SubmitPromise } from "@saleor/hooks/useForm";
|
||||||
|
import { isInDevelopment } from "@saleor/misc";
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useHistory } from "react-router";
|
import { useHistory } from "react-router";
|
||||||
import useRouter from "use-react-router";
|
import useRouter from "use-react-router";
|
||||||
|
|
||||||
import ExitFormDialog from "./ExitFormDialog";
|
import ExitFormDialog from "./ExitFormDialog";
|
||||||
|
import useBeforeUnload from "./useBeforeUnload";
|
||||||
|
|
||||||
export interface ExitFormDialogData {
|
export interface ExitFormDialogData {
|
||||||
setIsDirty: (id: symbol, isDirty: boolean) => void;
|
setIsDirty: (id: symbol, isDirty: boolean) => void;
|
||||||
|
@ -12,6 +14,7 @@ export interface ExitFormDialogData {
|
||||||
shouldBlockNavigation: () => boolean;
|
shouldBlockNavigation: () => boolean;
|
||||||
setIsSubmitting: (value: boolean) => void;
|
setIsSubmitting: (value: boolean) => void;
|
||||||
submit: () => SubmitPromise;
|
submit: () => SubmitPromise;
|
||||||
|
setIsSubmitDisabled: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SubmitFn = (dataOrEvent?: any) => SubmitPromise<any[]>;
|
export type SubmitFn = (dataOrEvent?: any) => SubmitPromise<any[]>;
|
||||||
|
@ -37,7 +40,8 @@ export const ExitFormDialogContext = React.createContext<ExitFormDialogData>({
|
||||||
setExitDialogSubmitRef: () => undefined,
|
setExitDialogSubmitRef: () => undefined,
|
||||||
shouldBlockNavigation: () => false,
|
shouldBlockNavigation: () => false,
|
||||||
setIsSubmitting: () => undefined,
|
setIsSubmitting: () => undefined,
|
||||||
submit: () => Promise.resolve([])
|
submit: () => Promise.resolve([]),
|
||||||
|
setIsSubmitDisabled: () => undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
|
@ -56,6 +60,11 @@ export function useExitFormDialogProvider() {
|
||||||
const { history: routerHistory } = useRouter();
|
const { history: routerHistory } = useRouter();
|
||||||
|
|
||||||
const [showDialog, setShowDialog] = useState(defaultValues.showDialog);
|
const [showDialog, setShowDialog] = useState(defaultValues.showDialog);
|
||||||
|
const isSubmitDisabled = useRef(false);
|
||||||
|
|
||||||
|
const setIsSubmitDisabled = (status: boolean) => {
|
||||||
|
isSubmitDisabled.current = status;
|
||||||
|
};
|
||||||
|
|
||||||
const isSubmitting = useRef(defaultValues.isSubmitting);
|
const isSubmitting = useRef(defaultValues.isSubmitting);
|
||||||
const formsData = useRef<FormsData>({});
|
const formsData = useRef<FormsData>({});
|
||||||
|
@ -209,10 +218,11 @@ export function useExitFormDialogProvider() {
|
||||||
const errors = await Promise.all(
|
const errors = await Promise.all(
|
||||||
getDirtyFormsSubmitFn().map(submitFn => submitFn())
|
getDirtyFormsSubmitFn().map(submitFn => submitFn())
|
||||||
);
|
);
|
||||||
const isError = errors.flat().some(errors => errors);
|
|
||||||
|
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
|
|
||||||
|
const isError = errors.flat().some(errors => errors);
|
||||||
|
|
||||||
if (!isError) {
|
if (!isError) {
|
||||||
continueNavigation();
|
continueNavigation();
|
||||||
}
|
}
|
||||||
|
@ -239,7 +249,8 @@ export function useExitFormDialogProvider() {
|
||||||
setEnableExitDialog,
|
setEnableExitDialog,
|
||||||
setExitDialogSubmitRef: setSubmitRef,
|
setExitDialogSubmitRef: setSubmitRef,
|
||||||
setIsSubmitting,
|
setIsSubmitting,
|
||||||
submit: handleSubmit
|
submit: handleSubmit,
|
||||||
|
setIsSubmitDisabled
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -247,7 +258,9 @@ export function useExitFormDialogProvider() {
|
||||||
showDialog,
|
showDialog,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
handleLeave,
|
handleLeave,
|
||||||
handleClose
|
handleClose,
|
||||||
|
shouldBlockNav,
|
||||||
|
isSubmitDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,9 +270,20 @@ const ExitFormDialogProvider = ({ children }) => {
|
||||||
handleLeave,
|
handleLeave,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
providerData,
|
providerData,
|
||||||
showDialog
|
showDialog,
|
||||||
|
shouldBlockNav,
|
||||||
|
isSubmitDisabled
|
||||||
} = useExitFormDialogProvider();
|
} = useExitFormDialogProvider();
|
||||||
|
|
||||||
|
useBeforeUnload(e => {
|
||||||
|
// If form is dirty and user does a refresh,
|
||||||
|
// the browser will ask about unsaved changes
|
||||||
|
if (shouldBlockNav() && !isInDevelopment) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.returnValue = "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExitFormDialogContext.Provider value={providerData}>
|
<ExitFormDialogContext.Provider value={providerData}>
|
||||||
<ExitFormDialog
|
<ExitFormDialog
|
||||||
|
@ -267,6 +291,7 @@ const ExitFormDialogProvider = ({ children }) => {
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
onLeave={handleLeave}
|
onLeave={handleLeave}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
|
isSubmitDisabled={isSubmitDisabled.current}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
</ExitFormDialogContext.Provider>
|
</ExitFormDialogContext.Provider>
|
||||||
|
|
|
@ -3,6 +3,13 @@ import React from "react";
|
||||||
|
|
||||||
import { FormId } from "./ExitFormDialogProvider";
|
import { FormId } from "./ExitFormDialogProvider";
|
||||||
|
|
||||||
|
export type FormDataWithOpts<TData> = TData &
|
||||||
|
Pick<UseFormResult<TData>, "hasChanged">;
|
||||||
|
|
||||||
|
export type CheckIfSaveIsDisabledFnType<T> = (
|
||||||
|
data: FormDataWithOpts<T>
|
||||||
|
) => boolean;
|
||||||
|
|
||||||
export interface FormProps<TData, TErrors>
|
export interface FormProps<TData, TErrors>
|
||||||
extends Omit<React.HTMLProps<HTMLFormElement>, "onSubmit"> {
|
extends Omit<React.HTMLProps<HTMLFormElement>, "onSubmit"> {
|
||||||
children: (props: UseFormResult<TData>) => React.ReactNode;
|
children: (props: UseFormResult<TData>) => React.ReactNode;
|
||||||
|
@ -11,6 +18,7 @@ export interface FormProps<TData, TErrors>
|
||||||
resetOnSubmit?: boolean;
|
resetOnSubmit?: boolean;
|
||||||
onSubmit?: (data: TData) => SubmitPromise<TErrors[]> | void;
|
onSubmit?: (data: TData) => SubmitPromise<TErrors[]> | void;
|
||||||
formId?: FormId;
|
formId?: FormId;
|
||||||
|
checkIfSaveIsDisabled?: CheckIfSaveIsDisabledFnType<TData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Form<TData, Terrors>({
|
function Form<TData, Terrors>({
|
||||||
|
@ -20,9 +28,16 @@ function Form<TData, Terrors>({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
confirmLeave = false,
|
confirmLeave = false,
|
||||||
formId,
|
formId,
|
||||||
|
checkIfSaveIsDisabled,
|
||||||
|
disabled,
|
||||||
...rest
|
...rest
|
||||||
}: FormProps<TData, Terrors>) {
|
}: FormProps<TData, Terrors>) {
|
||||||
const renderProps = useForm(initial, onSubmit, { confirmLeave, formId });
|
const renderProps = useForm(initial, onSubmit, {
|
||||||
|
confirmLeave,
|
||||||
|
formId,
|
||||||
|
checkIfSaveIsDisabled,
|
||||||
|
disabled
|
||||||
|
});
|
||||||
|
|
||||||
function handleSubmit(event?: React.FormEvent<any>, cb?: () => void) {
|
function handleSubmit(event?: React.FormEvent<any>, cb?: () => void) {
|
||||||
const { reset, submit } = renderProps;
|
const { reset, submit } = renderProps;
|
||||||
|
|
|
@ -2,20 +2,23 @@ import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
export const exitFormPromptMessages = defineMessages({
|
export const exitFormPromptMessages = defineMessages({
|
||||||
title: {
|
title: {
|
||||||
defaultMessage: "Are you sure you want to leave?",
|
defaultMessage: "Would you like to save changes?",
|
||||||
description: "ExitFormPrompt title"
|
description: "ExitFormPrompt title"
|
||||||
},
|
},
|
||||||
description: {
|
unableToSaveTitle: {
|
||||||
defaultMessage:
|
defaultMessage: "You have unsaved changes",
|
||||||
"You have unsaved changes on this view. What would you like to do with them?",
|
description: "ExitFormPrompt title"
|
||||||
description: "ExitFormPrompt description"
|
|
||||||
},
|
},
|
||||||
cancelButton: {
|
cancelButton: {
|
||||||
defaultMessage: "leave without saving",
|
defaultMessage: "Discard changes",
|
||||||
description: "ExitFormPrompt cancel button"
|
description: "ExitFormPrompt cancel button"
|
||||||
},
|
},
|
||||||
confirmButton: {
|
confirmButton: {
|
||||||
defaultMessage: "save & continue",
|
defaultMessage: "Save changes",
|
||||||
description: "ExitFormPrompt confirm button"
|
description: "ExitFormPrompt confirm button"
|
||||||
|
},
|
||||||
|
continueEditingButton: {
|
||||||
|
defaultMessage: "Continue editing",
|
||||||
|
description: "ExitFormPrompt continue editing button"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
19
src/components/Form/useBeforeUnload.ts
Normal file
19
src/components/Form/useBeforeUnload.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
const useBeforeUnload = fn => {
|
||||||
|
const cb = useRef(fn);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
cb.current = fn;
|
||||||
|
}, [fn]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const onBeforeUnload = (...args) => cb.current?.(...args);
|
||||||
|
|
||||||
|
window.addEventListener("beforeunload", onBeforeUnload);
|
||||||
|
|
||||||
|
return () => window.removeEventListener("beforeunload", onBeforeUnload);
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useBeforeUnload;
|
|
@ -1,4 +1,4 @@
|
||||||
import { useContext, useRef } from "react";
|
import React, { useContext, useRef } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ExitFormDialogContext,
|
ExitFormDialogContext,
|
||||||
|
@ -8,7 +8,14 @@ import {
|
||||||
} from "./ExitFormDialogProvider";
|
} from "./ExitFormDialogProvider";
|
||||||
|
|
||||||
export interface UseExitFormDialogResult
|
export interface UseExitFormDialogResult
|
||||||
extends Omit<ExitFormDialogData, "setIsDirty" | "setExitDialogSubmitRef">,
|
extends Pick<
|
||||||
|
ExitFormDialogData,
|
||||||
|
| "setEnableExitDialog"
|
||||||
|
| "shouldBlockNavigation"
|
||||||
|
| "setIsSubmitting"
|
||||||
|
| "setIsSubmitDisabled"
|
||||||
|
| "submit"
|
||||||
|
>,
|
||||||
WithFormId {
|
WithFormId {
|
||||||
setIsDirty: (isDirty: boolean) => void;
|
setIsDirty: (isDirty: boolean) => void;
|
||||||
setExitDialogSubmitRef: (submitFn: SubmitFn) => void;
|
setExitDialogSubmitRef: (submitFn: SubmitFn) => void;
|
||||||
|
@ -16,19 +23,29 @@ export interface UseExitFormDialogResult
|
||||||
|
|
||||||
export interface UseExitFormDialogProps {
|
export interface UseExitFormDialogProps {
|
||||||
formId: symbol;
|
formId: symbol;
|
||||||
|
isDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useExitFormDialog = (
|
export const useExitFormDialog = (
|
||||||
{ formId }: UseExitFormDialogProps = { formId: undefined }
|
{ formId, isDisabled }: UseExitFormDialogProps = { formId: undefined }
|
||||||
): UseExitFormDialogResult => {
|
): UseExitFormDialogResult => {
|
||||||
const id = useRef(formId || Symbol()).current;
|
const id = useRef(formId || Symbol()).current;
|
||||||
|
|
||||||
const { setIsDirty, setExitDialogSubmitRef, ...rest } = useContext(
|
const exitDialogProps = useContext(ExitFormDialogContext);
|
||||||
ExitFormDialogContext
|
const {
|
||||||
);
|
setIsDirty,
|
||||||
|
setIsSubmitDisabled,
|
||||||
|
setExitDialogSubmitRef
|
||||||
|
} = exitDialogProps;
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (isDisabled !== undefined) {
|
||||||
|
setIsSubmitDisabled(isDisabled);
|
||||||
|
}
|
||||||
|
}, [isDisabled]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...rest,
|
...exitDialogProps,
|
||||||
formId: id,
|
formId: id,
|
||||||
setIsDirty: (value: boolean) => setIsDirty(id, value),
|
setIsDirty: (value: boolean) => setIsDirty(id, value),
|
||||||
setExitDialogSubmitRef: (submitFn: SubmitFn) =>
|
setExitDialogSubmitRef: (submitFn: SubmitFn) =>
|
||||||
|
|
|
@ -135,8 +135,13 @@ const CustomerCreatePage: React.FC<CustomerCreatePageProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={handleSubmit}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit }) => {
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit }) => {
|
||||||
const handleCountrySelect = createSingleAutocompleteSelectHandler(
|
const handleCountrySelect = createSingleAutocompleteSelectHandler(
|
||||||
change,
|
change,
|
||||||
setCountryDisplayName,
|
setCountryDisplayName,
|
||||||
|
@ -182,7 +187,7 @@ const CustomerCreatePage: React.FC<CustomerCreatePageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBar}
|
state={saveButtonBar}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
|
|
|
@ -80,8 +80,13 @@ const CustomerDetailsPage: React.FC<CustomerDetailsPageProps> = ({
|
||||||
} = useMetadataChangeTrigger();
|
} = useMetadataChangeTrigger();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit }) => {
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit }) => {
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -136,7 +141,7 @@ const CustomerDetailsPage: React.FC<CustomerDetailsPageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBar}
|
state={saveButtonBar}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { validateSalePrice } from "@saleor/channels/utils";
|
||||||
import CardSpacer from "@saleor/components/CardSpacer";
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import Form from "@saleor/components/Form";
|
import Form, { FormDataWithOpts } from "@saleor/components/Form";
|
||||||
import Grid from "@saleor/components/Grid";
|
import Grid from "@saleor/components/Grid";
|
||||||
import Metadata, { MetadataFormData } from "@saleor/components/Metadata";
|
import Metadata, { MetadataFormData } from "@saleor/components/Metadata";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
@ -81,23 +81,26 @@ const SaleCreatePage: React.FC<SaleCreatePageProps> = ({
|
||||||
privateMetadata: []
|
privateMetadata: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkIfSaveIsDisabled = (data: FormDataWithOpts<FormData>) =>
|
||||||
|
data.channelListings?.some(channel => validateSalePrice(data, channel)) ||
|
||||||
|
disabled ||
|
||||||
|
!data.hasChanged;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
confirmLeave
|
confirmLeave
|
||||||
initial={initialForm}
|
initial={initialForm}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
formId={SALE_CREATE_FORM_ID}
|
formId={SALE_CREATE_FORM_ID}
|
||||||
|
checkIfSaveIsDisabled={checkIfSaveIsDisabled}
|
||||||
>
|
>
|
||||||
{({ change, data, hasChanged, submit, triggerChange }) => {
|
{({ change, data, submit, triggerChange, isSaveDisabled }) => {
|
||||||
const handleChannelChange = createSaleChannelsChangeHandler(
|
const handleChannelChange = createSaleChannelsChangeHandler(
|
||||||
data.channelListings,
|
data.channelListings,
|
||||||
onChannelsChange,
|
onChannelsChange,
|
||||||
triggerChange,
|
triggerChange,
|
||||||
data.type
|
data.type
|
||||||
);
|
);
|
||||||
const formDisabled = data.channelListings?.some(channel =>
|
|
||||||
validateSalePrice(data, channel)
|
|
||||||
);
|
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -152,7 +155,7 @@ const SaleCreatePage: React.FC<SaleCreatePageProps> = ({
|
||||||
<Metadata data={data} onChange={changeMetadata} />
|
<Metadata data={data} onChange={changeMetadata} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || formDisabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ChannelSaleData, validateSalePrice } from "@saleor/channels/utils";
|
||||||
import CardSpacer from "@saleor/components/CardSpacer";
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import Form from "@saleor/components/Form";
|
import Form, { FormDataWithOpts } from "@saleor/components/Form";
|
||||||
import Grid from "@saleor/components/Grid";
|
import Grid from "@saleor/components/Grid";
|
||||||
import Metadata, { MetadataFormData } from "@saleor/components/Metadata";
|
import Metadata, { MetadataFormData } from "@saleor/components/Metadata";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
@ -156,23 +156,29 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
||||||
metadata: sale?.metadata.map(mapMetadataItemToInput),
|
metadata: sale?.metadata.map(mapMetadataItemToInput),
|
||||||
privateMetadata: sale?.privateMetadata.map(mapMetadataItemToInput)
|
privateMetadata: sale?.privateMetadata.map(mapMetadataItemToInput)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkIfSaveIsDisabled = (
|
||||||
|
data: FormDataWithOpts<SaleDetailsPageFormData>
|
||||||
|
) =>
|
||||||
|
data.channelListings?.some(channel => validateSalePrice(data, channel)) ||
|
||||||
|
disabled ||
|
||||||
|
(!data.hasChanged && !hasChannelChanged);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
confirmLeave
|
confirmLeave
|
||||||
initial={initialForm}
|
initial={initialForm}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
formId={SALE_UPDATE_FORM_ID}
|
formId={SALE_UPDATE_FORM_ID}
|
||||||
|
checkIfSaveIsDisabled={checkIfSaveIsDisabled}
|
||||||
>
|
>
|
||||||
{({ change, data, hasChanged, submit, triggerChange }) => {
|
{({ change, data, submit, triggerChange, isSaveDisabled }) => {
|
||||||
const handleChannelChange = createSaleChannelsChangeHandler(
|
const handleChannelChange = createSaleChannelsChangeHandler(
|
||||||
data.channelListings,
|
data.channelListings,
|
||||||
onChannelsChange,
|
onChannelsChange,
|
||||||
triggerChange,
|
triggerChange,
|
||||||
data.type
|
data.type
|
||||||
);
|
);
|
||||||
const formDisabled = data.channelListings?.some(channel =>
|
|
||||||
validateSalePrice(data, channel)
|
|
||||||
);
|
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -370,9 +376,7 @@ const SaleDetailsPage: React.FC<SaleDetailsPageProps> = ({
|
||||||
<Metadata data={data} onChange={changeMetadata} />
|
<Metadata data={data} onChange={changeMetadata} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={
|
disabled={isSaveDisabled}
|
||||||
disabled || formDisabled || (!hasChanged && !hasChannelChanged)
|
|
||||||
}
|
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onRemove}
|
onDelete={onRemove}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ChannelVoucherData } from "@saleor/channels/utils";
|
||||||
import CardSpacer from "@saleor/components/CardSpacer";
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import Form from "@saleor/components/Form";
|
import Form, { FormDataWithOpts } from "@saleor/components/Form";
|
||||||
import Grid from "@saleor/components/Grid";
|
import Grid from "@saleor/components/Grid";
|
||||||
import Metadata from "@saleor/components/Metadata";
|
import Metadata from "@saleor/components/Metadata";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
@ -91,14 +91,26 @@ const VoucherCreatePage: React.FC<VoucherCreatePageProps> = ({
|
||||||
privateMetadata: []
|
privateMetadata: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkIfSaveIsDisabled = (data: FormDataWithOpts<FormData>) =>
|
||||||
|
(data.discountType.toString() !== "SHIPPING" &&
|
||||||
|
data.channelListings?.some(
|
||||||
|
channel =>
|
||||||
|
validatePrice(channel.discountValue) ||
|
||||||
|
(data.requirementsPicker === RequirementsPicker.ORDER &&
|
||||||
|
validatePrice(channel.minSpent))
|
||||||
|
)) ||
|
||||||
|
disabled ||
|
||||||
|
(!data.hasChanged && hasChannelChanged);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
confirmLeave
|
confirmLeave
|
||||||
initial={initialForm}
|
initial={initialForm}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
formId={VOUCHER_CREATE_FORM_ID}
|
formId={VOUCHER_CREATE_FORM_ID}
|
||||||
|
checkIfSaveIsDisabled={checkIfSaveIsDisabled}
|
||||||
>
|
>
|
||||||
{({ change, data, hasChanged, submit, triggerChange, set }) => {
|
{({ change, data, submit, triggerChange, set, isSaveDisabled }) => {
|
||||||
const handleDiscountTypeChange = createDiscountTypeChangeHandler(
|
const handleDiscountTypeChange = createDiscountTypeChangeHandler(
|
||||||
change
|
change
|
||||||
);
|
);
|
||||||
|
@ -107,14 +119,6 @@ const VoucherCreatePage: React.FC<VoucherCreatePageProps> = ({
|
||||||
onChannelsChange,
|
onChannelsChange,
|
||||||
triggerChange
|
triggerChange
|
||||||
);
|
);
|
||||||
const formDisabled =
|
|
||||||
data.discountType.toString() !== "SHIPPING" &&
|
|
||||||
data.channelListings?.some(
|
|
||||||
channel =>
|
|
||||||
validatePrice(channel.discountValue) ||
|
|
||||||
(data.requirementsPicker === RequirementsPicker.ORDER &&
|
|
||||||
validatePrice(channel.minSpent))
|
|
||||||
);
|
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -199,9 +203,7 @@ const VoucherCreatePage: React.FC<VoucherCreatePageProps> = ({
|
||||||
<Metadata data={data} onChange={changeMetadata} />
|
<Metadata data={data} onChange={changeMetadata} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={
|
disabled={isSaveDisabled}
|
||||||
disabled || formDisabled || (!hasChanged && !hasChannelChanged)
|
|
||||||
}
|
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { CheckIfSaveIsDisabledFnType } from "@saleor/components/Form";
|
||||||
import { FormId } from "@saleor/components/Form/ExitFormDialogProvider";
|
import { FormId } from "@saleor/components/Form/ExitFormDialogProvider";
|
||||||
import {
|
import {
|
||||||
useExitFormDialog,
|
useExitFormDialog,
|
||||||
|
@ -25,9 +26,11 @@ export type FormErrors<T> = {
|
||||||
[field in keyof T]?: string | React.ReactNode;
|
[field in keyof T]?: string | React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface UseFormOpts {
|
export interface UseFormOpts<T> {
|
||||||
confirmLeave: boolean;
|
confirmLeave: boolean;
|
||||||
formId?: FormId;
|
formId?: FormId;
|
||||||
|
checkIfSaveIsDisabled?: CheckIfSaveIsDisabledFnType<T>;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UseFormResult<TData>
|
export interface UseFormResult<TData>
|
||||||
|
@ -42,6 +45,7 @@ export interface UseFormResult<TData>
|
||||||
errors: FormErrors<TData>;
|
errors: FormErrors<TData>;
|
||||||
setError: (name: keyof TData, error: string | React.ReactNode) => void;
|
setError: (name: keyof TData, error: string | React.ReactNode) => void;
|
||||||
clearErrors: (name?: keyof TData | Array<keyof TData>) => void;
|
clearErrors: (name?: keyof TData | Array<keyof TData>) => void;
|
||||||
|
setIsSubmitDisabled: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommonUseFormResult<TData> {
|
export interface CommonUseFormResult<TData> {
|
||||||
|
@ -49,6 +53,7 @@ export interface CommonUseFormResult<TData> {
|
||||||
change: FormChange;
|
change: FormChange;
|
||||||
hasChanged: boolean;
|
hasChanged: boolean;
|
||||||
submit: (dataOrEvent?: any) => SubmitPromise<any[]>;
|
submit: (dataOrEvent?: any) => SubmitPromise<any[]>;
|
||||||
|
isSaveDisabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommonUseFormResultWithHandlers<TData, THandlers>
|
export interface CommonUseFormResultWithHandlers<TData, THandlers>
|
||||||
|
@ -84,9 +89,14 @@ function handleRefresh<T extends FormData>(
|
||||||
function useForm<T extends FormData, TErrors>(
|
function useForm<T extends FormData, TErrors>(
|
||||||
initialData: T,
|
initialData: T,
|
||||||
onSubmit?: (data: T) => SubmitPromise<TErrors[]> | void,
|
onSubmit?: (data: T) => SubmitPromise<TErrors[]> | void,
|
||||||
opts: UseFormOpts = { confirmLeave: false, formId: undefined }
|
opts: UseFormOpts<T> = { confirmLeave: false, formId: undefined }
|
||||||
): UseFormResult<T> {
|
): UseFormResult<T> {
|
||||||
const { confirmLeave, formId: propsFormId } = opts;
|
const {
|
||||||
|
confirmLeave,
|
||||||
|
formId: propsFormId,
|
||||||
|
checkIfSaveIsDisabled,
|
||||||
|
disabled
|
||||||
|
} = opts;
|
||||||
const [hasChanged, setChanged] = useState(false);
|
const [hasChanged, setChanged] = useState(false);
|
||||||
const [errors, setErrors] = useState<FormErrors<T>>({});
|
const [errors, setErrors] = useState<FormErrors<T>>({});
|
||||||
const [data, setData] = useStateFromProps(initialData, {
|
const [data, setData] = useStateFromProps(initialData, {
|
||||||
|
@ -94,12 +104,33 @@ function useForm<T extends FormData, TErrors>(
|
||||||
onRefresh: newData => handleRefresh(data, newData, handleSetChanged)
|
onRefresh: newData => handleRefresh(data, newData, handleSetChanged)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const basicFormDisableConditions = () => !hasChanged || disabled;
|
||||||
|
|
||||||
|
const isSaveDisabled = () => {
|
||||||
|
if (checkIfSaveIsDisabled) {
|
||||||
|
return checkIfSaveIsDisabled({
|
||||||
|
...data,
|
||||||
|
hasChanged
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disabled !== undefined) {
|
||||||
|
return basicFormDisableConditions();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setIsDirty: setIsFormDirtyInExitDialog,
|
setIsDirty: setIsFormDirtyInExitDialog,
|
||||||
setExitDialogSubmitRef,
|
setExitDialogSubmitRef,
|
||||||
setEnableExitDialog,
|
setEnableExitDialog,
|
||||||
|
setIsSubmitDisabled,
|
||||||
formId
|
formId
|
||||||
} = useExitFormDialog({ formId: propsFormId });
|
} = useExitFormDialog({
|
||||||
|
formId: propsFormId,
|
||||||
|
isDisabled: isSaveDisabled()
|
||||||
|
});
|
||||||
|
|
||||||
const handleFormSubmit = useHandleFormSubmit({
|
const handleFormSubmit = useHandleFormSubmit({
|
||||||
formId,
|
formId,
|
||||||
|
@ -216,7 +247,9 @@ function useForm<T extends FormData, TErrors>(
|
||||||
toggleValue,
|
toggleValue,
|
||||||
handleChange,
|
handleChange,
|
||||||
triggerChange: handleSetChanged,
|
triggerChange: handleSetChanged,
|
||||||
setChanged: handleSetChanged
|
setChanged: handleSetChanged,
|
||||||
|
setIsSubmitDisabled,
|
||||||
|
isSaveDisabled: isSaveDisabled()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,14 @@ function useHandleFormSubmit<TData, TErrors>({
|
||||||
|
|
||||||
const errors = await result;
|
const errors = await result;
|
||||||
|
|
||||||
|
setIsSubmitting(false);
|
||||||
|
|
||||||
if (errors?.length === 0) {
|
if (errors?.length === 0) {
|
||||||
setChanged(false);
|
setChanged(false);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsSubmitting(false);
|
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -522,3 +522,6 @@ export const combinedMultiAutocompleteChoices = (
|
||||||
selected: MultiAutocompleteChoiceType[],
|
selected: MultiAutocompleteChoiceType[],
|
||||||
choices: MultiAutocompleteChoiceType[]
|
choices: MultiAutocompleteChoiceType[]
|
||||||
) => uniqBy([...selected, ...choices], "value");
|
) => uniqBy([...selected, ...choices], "value");
|
||||||
|
|
||||||
|
export const isInDevelopment =
|
||||||
|
!process.env.NODE_ENV || process.env.NODE_ENV === "development";
|
||||||
|
|
|
@ -67,8 +67,9 @@ const OrderRefundPage: React.FC<OrderRefundPageProps> = props => {
|
||||||
order={order}
|
order={order}
|
||||||
defaultType={defaultType}
|
defaultType={defaultType}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ data, handlers, change, submit }) => {
|
{({ data, handlers, change, submit, isSaveDisabled }) => {
|
||||||
const isProductRefund = data.type === OrderRefundType.PRODUCTS;
|
const isProductRefund = data.type === OrderRefundType.PRODUCTS;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -156,7 +157,7 @@ const OrderRefundPage: React.FC<OrderRefundPageProps> = props => {
|
||||||
}
|
}
|
||||||
data={data}
|
data={data}
|
||||||
order={order}
|
order={order}
|
||||||
disabled={disabled}
|
disabled={isSaveDisabled}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
onRefund={submit}
|
onRefund={submit}
|
||||||
|
|
|
@ -57,6 +57,7 @@ interface OrderRefundFormProps {
|
||||||
order: OrderRefundDataQuery["order"];
|
order: OrderRefundDataQuery["order"];
|
||||||
defaultType: OrderRefundType;
|
defaultType: OrderRefundType;
|
||||||
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise;
|
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise;
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrderRefundPageFormData(
|
function getOrderRefundPageFormData(
|
||||||
|
@ -73,7 +74,8 @@ function getOrderRefundPageFormData(
|
||||||
function useOrderRefundForm(
|
function useOrderRefundForm(
|
||||||
order: OrderRefundDataQuery["order"],
|
order: OrderRefundDataQuery["order"],
|
||||||
defaultType: OrderRefundType,
|
defaultType: OrderRefundType,
|
||||||
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise
|
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise,
|
||||||
|
disabled: boolean
|
||||||
): UseOrderRefundFormResult {
|
): UseOrderRefundFormResult {
|
||||||
const {
|
const {
|
||||||
handleChange,
|
handleChange,
|
||||||
|
@ -81,12 +83,15 @@ function useOrderRefundForm(
|
||||||
hasChanged,
|
hasChanged,
|
||||||
triggerChange,
|
triggerChange,
|
||||||
data: formData,
|
data: formData,
|
||||||
formId
|
formId,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = useForm(getOrderRefundPageFormData(defaultType), undefined, {
|
} = useForm(getOrderRefundPageFormData(defaultType), undefined, {
|
||||||
confirmLeave: true
|
confirmLeave: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setExitDialogSubmitRef } = useExitFormDialog();
|
const { setExitDialogSubmitRef } = useExitFormDialog({
|
||||||
|
formId
|
||||||
|
});
|
||||||
|
|
||||||
const refundedProductQuantities = useFormset<null, string>(
|
const refundedProductQuantities = useFormset<null, string>(
|
||||||
order?.lines
|
order?.lines
|
||||||
|
@ -188,7 +193,8 @@ function useOrderRefundForm(
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
const disabled = !order;
|
const isSaveDisabled = disabled || !order;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
|
@ -201,7 +207,8 @@ function useOrderRefundForm(
|
||||||
setMaximalRefundedProductQuantities: handleMaximalRefundedProductQuantitiesSet
|
setMaximalRefundedProductQuantities: handleMaximalRefundedProductQuantitiesSet
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,9 +216,10 @@ const OrderRefundForm: React.FC<OrderRefundFormProps> = ({
|
||||||
children,
|
children,
|
||||||
order,
|
order,
|
||||||
defaultType,
|
defaultType,
|
||||||
onSubmit
|
onSubmit,
|
||||||
|
disabled
|
||||||
}) => {
|
}) => {
|
||||||
const props = useOrderRefundForm(order, defaultType, onSubmit);
|
const props = useOrderRefundForm(order, defaultType, onSubmit, disabled);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,110 +45,97 @@ const OrderRefundPage: React.FC<OrderReturnPageProps> = props => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
return (
|
return (
|
||||||
<OrderRefundForm order={order} onSubmit={onSubmit}>
|
<OrderRefundForm order={order} onSubmit={onSubmit}>
|
||||||
{({ data, handlers, change, submit }) => {
|
{({ data, handlers, change, submit, isSaveDisabled }) => (
|
||||||
const {
|
<Container>
|
||||||
fulfilledItemsQuantities,
|
<Backlink onClick={onBack}>
|
||||||
waitingItemsQuantities,
|
{intl.formatMessage(messages.appTitle, {
|
||||||
unfulfilledItemsQuantities
|
orderNumber: order?.number
|
||||||
} = data;
|
})}
|
||||||
|
</Backlink>
|
||||||
const hasAnyItemsSelected =
|
<PageHeader
|
||||||
fulfilledItemsQuantities.some(({ value }) => !!value) ||
|
title={intl.formatMessage(messages.pageTitle, {
|
||||||
waitingItemsQuantities.some(({ value }) => !!value) ||
|
orderNumber: order?.number
|
||||||
unfulfilledItemsQuantities.some(({ value }) => !!value);
|
})}
|
||||||
|
/>
|
||||||
return (
|
<Grid>
|
||||||
<Container>
|
<div>
|
||||||
<Backlink onClick={onBack}>
|
{!!data.unfulfilledItemsQuantities.length && (
|
||||||
{intl.formatMessage(messages.appTitle, {
|
<>
|
||||||
orderNumber: order?.number
|
<ItemsCard
|
||||||
})}
|
errors={errors}
|
||||||
</Backlink>
|
order={order}
|
||||||
<PageHeader
|
lines={getUnfulfilledLines(order)}
|
||||||
title={intl.formatMessage(messages.pageTitle, {
|
itemsQuantities={data.unfulfilledItemsQuantities}
|
||||||
orderNumber: order?.number
|
itemsSelections={data.itemsToBeReplaced}
|
||||||
})}
|
onChangeQuantity={handlers.changeUnfulfiledItemsQuantity}
|
||||||
/>
|
onSetMaxQuantity={
|
||||||
<Grid>
|
handlers.handleSetMaximalUnfulfiledItemsQuantities
|
||||||
<div>
|
}
|
||||||
{!!data.unfulfilledItemsQuantities.length && (
|
onChangeSelected={handlers.changeItemsToBeReplaced}
|
||||||
<>
|
/>
|
||||||
|
<CardSpacer />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{renderCollection(
|
||||||
|
getWaitingFulfillments(order),
|
||||||
|
({ id, lines }) => (
|
||||||
|
<React.Fragment key={id}>
|
||||||
<ItemsCard
|
<ItemsCard
|
||||||
errors={errors}
|
errors={errors}
|
||||||
order={order}
|
order={order}
|
||||||
lines={getUnfulfilledLines(order)}
|
fulfilmentId={id}
|
||||||
itemsQuantities={data.unfulfilledItemsQuantities}
|
lines={getParsedLines(lines)}
|
||||||
|
itemsQuantities={data.waitingItemsQuantities}
|
||||||
itemsSelections={data.itemsToBeReplaced}
|
itemsSelections={data.itemsToBeReplaced}
|
||||||
onChangeQuantity={handlers.changeUnfulfiledItemsQuantity}
|
onChangeQuantity={handlers.changeWaitingItemsQuantity}
|
||||||
onSetMaxQuantity={
|
onSetMaxQuantity={handlers.handleSetMaximalItemsQuantities(
|
||||||
handlers.handleSetMaximalUnfulfiledItemsQuantities
|
id
|
||||||
}
|
)}
|
||||||
onChangeSelected={handlers.changeItemsToBeReplaced}
|
onChangeSelected={handlers.changeItemsToBeReplaced}
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
<CardSpacer />
|
||||||
</>
|
</React.Fragment>
|
||||||
)}
|
)
|
||||||
{renderCollection(
|
)}
|
||||||
getWaitingFulfillments(order),
|
{renderCollection(
|
||||||
({ id, lines }) => (
|
getFulfilledFulfillemnts(order),
|
||||||
<React.Fragment key={id}>
|
({ id, lines }) => (
|
||||||
<ItemsCard
|
<React.Fragment key={id}>
|
||||||
errors={errors}
|
<ItemsCard
|
||||||
order={order}
|
errors={errors}
|
||||||
fulfilmentId={id}
|
order={order}
|
||||||
lines={getParsedLines(lines)}
|
fulfilmentId={id}
|
||||||
itemsQuantities={data.waitingItemsQuantities}
|
lines={getParsedLines(lines)}
|
||||||
itemsSelections={data.itemsToBeReplaced}
|
itemsQuantities={data.fulfilledItemsQuantities}
|
||||||
onChangeQuantity={handlers.changeWaitingItemsQuantity}
|
itemsSelections={data.itemsToBeReplaced}
|
||||||
onSetMaxQuantity={handlers.handleSetMaximalItemsQuantities(
|
onChangeQuantity={handlers.changeFulfiledItemsQuantity}
|
||||||
id
|
onSetMaxQuantity={handlers.handleSetMaximalItemsQuantities(
|
||||||
)}
|
id
|
||||||
onChangeSelected={handlers.changeItemsToBeReplaced}
|
)}
|
||||||
/>
|
onChangeSelected={handlers.changeItemsToBeReplaced}
|
||||||
<CardSpacer />
|
/>
|
||||||
</React.Fragment>
|
<CardSpacer />
|
||||||
)
|
</React.Fragment>
|
||||||
)}
|
)
|
||||||
{renderCollection(
|
)}
|
||||||
getFulfilledFulfillemnts(order),
|
</div>
|
||||||
({ id, lines }) => (
|
<div>
|
||||||
<React.Fragment key={id}>
|
<OrderAmount
|
||||||
<ItemsCard
|
allowNoRefund
|
||||||
errors={errors}
|
isReturn
|
||||||
order={order}
|
amountData={getReturnProductsAmountValues(order, data)}
|
||||||
fulfilmentId={id}
|
data={data}
|
||||||
lines={getParsedLines(lines)}
|
order={order}
|
||||||
itemsQuantities={data.fulfilledItemsQuantities}
|
disableSubmitButton={isSaveDisabled}
|
||||||
itemsSelections={data.itemsToBeReplaced}
|
disabled={loading}
|
||||||
onChangeQuantity={handlers.changeFulfiledItemsQuantity}
|
errors={errors}
|
||||||
onSetMaxQuantity={handlers.handleSetMaximalItemsQuantities(
|
onChange={change}
|
||||||
id
|
onRefund={submit}
|
||||||
)}
|
/>
|
||||||
onChangeSelected={handlers.changeItemsToBeReplaced}
|
</div>
|
||||||
/>
|
</Grid>
|
||||||
<CardSpacer />
|
</Container>
|
||||||
</React.Fragment>
|
)}
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<OrderAmount
|
|
||||||
allowNoRefund
|
|
||||||
isReturn
|
|
||||||
amountData={getReturnProductsAmountValues(order, data)}
|
|
||||||
data={data}
|
|
||||||
order={order}
|
|
||||||
disableSubmitButton={!hasAnyItemsSelected}
|
|
||||||
disabled={loading}
|
|
||||||
errors={errors}
|
|
||||||
onChange={change}
|
|
||||||
onRefund={submit}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</OrderRefundForm>
|
</OrderRefundForm>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -85,12 +85,15 @@ function useOrderReturnForm(
|
||||||
hasChanged,
|
hasChanged,
|
||||||
data: formData,
|
data: formData,
|
||||||
triggerChange,
|
triggerChange,
|
||||||
formId
|
formId,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = useForm(getOrderRefundPageFormData(), undefined, {
|
} = useForm(getOrderRefundPageFormData(), undefined, {
|
||||||
confirmLeave: true
|
confirmLeave: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setExitDialogSubmitRef } = useExitFormDialog();
|
const { setExitDialogSubmitRef } = useExitFormDialog({
|
||||||
|
formId
|
||||||
|
});
|
||||||
|
|
||||||
const unfulfiledItemsQuantites = useFormset<LineItemData, number>(
|
const unfulfiledItemsQuantites = useFormset<LineItemData, number>(
|
||||||
getOrderUnfulfilledLines(order).map(getParsedLineData({ initialValue: 0 }))
|
getOrderUnfulfilledLines(order).map(getParsedLineData({ initialValue: 0 }))
|
||||||
|
@ -241,6 +244,14 @@ function useOrderReturnForm(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasAnyItemsSelected =
|
||||||
|
fulfiledItemsQuatities.data.some(({ value }) => !!value) ||
|
||||||
|
waitingItemsQuantities.data.some(({ value }) => !!value) ||
|
||||||
|
unfulfiledItemsQuantites.data.some(({ value }) => !!value);
|
||||||
|
|
||||||
|
const isSaveDisabled = !hasAnyItemsSelected;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data,
|
data,
|
||||||
|
@ -259,7 +270,8 @@ function useOrderReturnForm(
|
||||||
handleSetMaximalUnfulfiledItemsQuantities
|
handleSetMaximalUnfulfiledItemsQuantities
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,9 @@ const OrderSettingsPage: React.FC<OrderSettingsPageProps> = props => {
|
||||||
orderSettings={orderSettings}
|
orderSettings={orderSettings}
|
||||||
shop={shop}
|
shop={shop}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ data, submit, hasChanged, change }) => (
|
{({ data, submit, change, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.orders)}
|
{intl.formatMessage(sectionNames.orders)}
|
||||||
|
@ -73,7 +74,7 @@ const OrderSettingsPage: React.FC<OrderSettingsPageProps> = props => {
|
||||||
<Savebar
|
<Savebar
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -2,7 +2,10 @@ import {
|
||||||
OrderSettingsFragment,
|
OrderSettingsFragment,
|
||||||
ShopOrderSettingsFragment
|
ShopOrderSettingsFragment
|
||||||
} from "@saleor/graphql";
|
} from "@saleor/graphql";
|
||||||
import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm";
|
import useForm, {
|
||||||
|
CommonUseFormResult,
|
||||||
|
SubmitPromise
|
||||||
|
} from "@saleor/hooks/useForm";
|
||||||
import useHandleFormSubmit from "@saleor/hooks/useHandleFormSubmit";
|
import useHandleFormSubmit from "@saleor/hooks/useHandleFormSubmit";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -13,18 +16,15 @@ export interface OrderSettingsFormData {
|
||||||
automaticallyFulfillNonShippableGiftCard: boolean;
|
automaticallyFulfillNonShippableGiftCard: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UseOrderSettingsFormResult {
|
export type UseOrderSettingsFormResult = CommonUseFormResult<
|
||||||
change: FormChange;
|
OrderSettingsFormData
|
||||||
data: OrderSettingsFormData;
|
>;
|
||||||
hasChanged: boolean;
|
|
||||||
submit: () => SubmitPromise<any[]>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderSettingsFormProps {
|
export interface OrderSettingsFormProps {
|
||||||
children: (props: UseOrderSettingsFormResult) => React.ReactNode;
|
children: (props: UseOrderSettingsFormResult) => React.ReactNode;
|
||||||
orderSettings: OrderSettingsFragment;
|
orderSettings: OrderSettingsFragment;
|
||||||
shop: ShopOrderSettingsFragment;
|
shop: ShopOrderSettingsFragment;
|
||||||
onSubmit: (data: OrderSettingsFormData) => SubmitPromise;
|
onSubmit: (data: OrderSettingsFormData) => SubmitPromise;
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrderSeettingsFormData(
|
function getOrderSeettingsFormData(
|
||||||
|
@ -44,15 +44,19 @@ function getOrderSeettingsFormData(
|
||||||
function useOrderSettingsForm(
|
function useOrderSettingsForm(
|
||||||
orderSettings: OrderSettingsFragment,
|
orderSettings: OrderSettingsFragment,
|
||||||
shop: ShopOrderSettingsFragment,
|
shop: ShopOrderSettingsFragment,
|
||||||
onSubmit: (data: OrderSettingsFormData) => SubmitPromise
|
onSubmit: (data: OrderSettingsFormData) => SubmitPromise,
|
||||||
|
disabled: boolean
|
||||||
): UseOrderSettingsFormResult {
|
): UseOrderSettingsFormResult {
|
||||||
const { data, handleChange, formId, hasChanged, setChanged } = useForm(
|
const {
|
||||||
getOrderSeettingsFormData(orderSettings, shop),
|
data,
|
||||||
undefined,
|
handleChange,
|
||||||
{
|
formId,
|
||||||
confirmLeave: true
|
hasChanged,
|
||||||
}
|
setChanged,
|
||||||
);
|
setIsSubmitDisabled
|
||||||
|
} = useForm(getOrderSeettingsFormData(orderSettings, shop), undefined, {
|
||||||
|
confirmLeave: true
|
||||||
|
});
|
||||||
|
|
||||||
const handleFormSubmit = useHandleFormSubmit({
|
const handleFormSubmit = useHandleFormSubmit({
|
||||||
formId,
|
formId,
|
||||||
|
@ -61,12 +65,15 @@ function useOrderSettingsForm(
|
||||||
});
|
});
|
||||||
|
|
||||||
const submit = () => handleFormSubmit(data);
|
const submit = () => handleFormSubmit(data);
|
||||||
|
const isSaveDisabled = disabled || !hasChanged;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data,
|
data,
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +81,10 @@ const OrderSettingsForm: React.FC<OrderSettingsFormProps> = ({
|
||||||
children,
|
children,
|
||||||
orderSettings,
|
orderSettings,
|
||||||
shop,
|
shop,
|
||||||
onSubmit
|
onSubmit,
|
||||||
|
disabled
|
||||||
}) => {
|
}) => {
|
||||||
const props = useOrderSettingsForm(orderSettings, shop, onSubmit);
|
const props = useOrderSettingsForm(orderSettings, shop, onSubmit, disabled);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,8 +58,13 @@ const PageTypeCreatePage: React.FC<PageTypeCreatePageProps> = props => {
|
||||||
} = useMetadataChangeTrigger();
|
} = useMetadataChangeTrigger();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={formInitialData} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit }) => {
|
confirmLeave
|
||||||
|
initial={formInitialData}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, submit, isSaveDisabled }) => {
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -103,7 +108,7 @@ const PageTypeCreatePage: React.FC<PageTypeCreatePageProps> = props => {
|
||||||
<Savebar
|
<Savebar
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -110,8 +110,13 @@ const PageTypeDetailsPage: React.FC<PageTypeDetailsPageProps> = props => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={formInitialData} onSubmit={handleSubmit}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit }) => {
|
confirmLeave
|
||||||
|
initial={formInitialData}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit }) => {
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -174,7 +179,7 @@ const PageTypeDetailsPage: React.FC<PageTypeDetailsPageProps> = props => {
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -135,8 +135,9 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
|
||||||
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
||||||
assignReferencesAttributeId={assignReferencesAttributeId}
|
assignReferencesAttributeId={assignReferencesAttributeId}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
{({ change, data, valid, handlers, hasChanged, submit }) => (
|
{({ change, data, handlers, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.pages)}
|
{intl.formatMessage(sectionNames.pages)}
|
||||||
|
@ -242,7 +243,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={loading || !hasChanged || !valid}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={page === null ? undefined : onRemove}
|
onDelete={page === null ? undefined : onRemove}
|
||||||
|
|
|
@ -97,6 +97,7 @@ export interface PageFormProps extends UsePageFormOpts {
|
||||||
children: (props: UsePageUpdateFormResult) => React.ReactNode;
|
children: (props: UsePageUpdateFormResult) => React.ReactNode;
|
||||||
page: PageDetailsFragment;
|
page: PageDetailsFragment;
|
||||||
onSubmit: (data: PageData) => SubmitPromise;
|
onSubmit: (data: PageData) => SubmitPromise;
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInitialFormData = (page?: PageDetailsFragment): PageFormData => ({
|
const getInitialFormData = (page?: PageDetailsFragment): PageFormData => ({
|
||||||
|
@ -114,6 +115,7 @@ const getInitialFormData = (page?: PageDetailsFragment): PageFormData => ({
|
||||||
function usePageForm(
|
function usePageForm(
|
||||||
page: PageDetailsFragment,
|
page: PageDetailsFragment,
|
||||||
onSubmit: (data: PageData) => SubmitPromise,
|
onSubmit: (data: PageData) => SubmitPromise,
|
||||||
|
disabled: boolean,
|
||||||
opts: UsePageFormOpts
|
opts: UsePageFormOpts
|
||||||
): UsePageUpdateFormResult {
|
): UsePageUpdateFormResult {
|
||||||
const pageExists = page !== null;
|
const pageExists = page !== null;
|
||||||
|
@ -138,7 +140,7 @@ function usePageForm(
|
||||||
confirmLeave: true
|
confirmLeave: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setExitDialogSubmitRef } = useExitFormDialog({
|
const { setExitDialogSubmitRef, setIsSubmitDisabled } = useExitFormDialog({
|
||||||
formId
|
formId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -238,6 +240,9 @@ function usePageForm(
|
||||||
|
|
||||||
const valid = pageExists || !!opts.selectedPageType;
|
const valid = pageExists || !!opts.selectedPageType;
|
||||||
|
|
||||||
|
const isSaveDisabled = disabled || !hasChanged || !valid;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data: getData(),
|
data: getData(),
|
||||||
|
@ -255,7 +260,8 @@ function usePageForm(
|
||||||
selectPageType: handlePageTypeSelect
|
selectPageType: handlePageTypeSelect
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,9 +269,10 @@ const PageForm: React.FC<PageFormProps> = ({
|
||||||
children,
|
children,
|
||||||
page,
|
page,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
disabled,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
const props = usePageForm(page, onSubmit, rest);
|
const props = usePageForm(page, onSubmit, disabled, rest);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,8 +55,13 @@ const PermissionGroupCreatePage: React.FC<PermissionGroupCreatePageProps> = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ data, change, submit, hasChanged }) => (
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ data, change, submit, isSaveDisabled }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
{intl.formatMessage(sectionNames.permissionGroups)}
|
{intl.formatMessage(sectionNames.permissionGroups)}
|
||||||
|
@ -95,7 +100,7 @@ const PermissionGroupCreatePage: React.FC<PermissionGroupCreatePageProps> = ({
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -75,8 +75,9 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = ({
|
||||||
initial={initialFormData()}
|
initial={initialFormData()}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
key={selectedChannelId}
|
key={selectedChannelId}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ data, hasChanged, submit, set }) => {
|
{({ data, submit, set, isSaveDisabled }) => {
|
||||||
const onChange = (event: ChangeEvent) => {
|
const onChange = (event: ChangeEvent) => {
|
||||||
const { name, value } = event.target;
|
const { name, value } = event.target;
|
||||||
const newData = {
|
const newData = {
|
||||||
|
@ -159,7 +160,7 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -91,8 +91,13 @@ const ProductTypeCreatePage: React.FC<ProductTypeCreatePageProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialData} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit }) => {
|
confirmLeave
|
||||||
|
initial={initialData}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit }) => {
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
const changeKind = makeProductTypeKindChangeHandler(
|
const changeKind = makeProductTypeKindChangeHandler(
|
||||||
|
@ -145,7 +150,7 @@ const ProductTypeCreatePage: React.FC<ProductTypeCreatePageProps> = ({
|
||||||
<Savebar
|
<Savebar
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -156,8 +156,13 @@ const ProductTypeDetailsPage: React.FC<ProductTypeDetailsPageProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form initial={formInitialData} onSubmit={handleSubmit} confirmLeave>
|
<Form
|
||||||
{({ change, data, hasChanged, submit, setChanged }) => {
|
initial={formInitialData}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
confirmLeave
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit, setChanged }) => {
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -256,7 +261,7 @@ const ProductTypeDetailsPage: React.FC<ProductTypeDetailsPageProps> = ({
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -202,16 +202,9 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
|
||||||
fetchReferenceProducts={fetchReferenceProducts}
|
fetchReferenceProducts={fetchReferenceProducts}
|
||||||
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
||||||
assignReferencesAttributeId={assignReferencesAttributeId}
|
assignReferencesAttributeId={assignReferencesAttributeId}
|
||||||
|
loading={loading}
|
||||||
>
|
>
|
||||||
{({
|
{({ change, data, formErrors, handlers, submit, isSaveDisabled }) => {
|
||||||
change,
|
|
||||||
data,
|
|
||||||
formErrors,
|
|
||||||
disabled: formDisabled,
|
|
||||||
handlers,
|
|
||||||
hasChanged,
|
|
||||||
submit
|
|
||||||
}) => {
|
|
||||||
// Comparing explicitly to false because `hasVariants` can be undefined
|
// Comparing explicitly to false because `hasVariants` can be undefined
|
||||||
const isSimpleProduct = data.productType?.hasVariants === false;
|
const isSimpleProduct = data.productType?.hasVariants === false;
|
||||||
|
|
||||||
|
@ -367,7 +360,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={loading || !onSubmit || formDisabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
/>
|
/>
|
||||||
{canOpenAssignReferencesAttributeDialog && (
|
{canOpenAssignReferencesAttributeDialog && (
|
||||||
<AssignAttributeValueDialog
|
<AssignAttributeValueDialog
|
||||||
|
|
|
@ -163,11 +163,13 @@ export interface ProductCreateFormProps extends UseProductCreateFormOpts {
|
||||||
children: (props: UseProductCreateFormResult) => React.ReactNode;
|
children: (props: UseProductCreateFormResult) => React.ReactNode;
|
||||||
initial?: Partial<ProductCreateFormData>;
|
initial?: Partial<ProductCreateFormData>;
|
||||||
onSubmit: (data: ProductCreateData) => SubmitPromise;
|
onSubmit: (data: ProductCreateData) => SubmitPromise;
|
||||||
|
loading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useProductCreateForm(
|
function useProductCreateForm(
|
||||||
initial: Partial<ProductCreateFormData>,
|
initial: Partial<ProductCreateFormData>,
|
||||||
onSubmit: (data: ProductCreateData) => SubmitPromise,
|
onSubmit: (data: ProductCreateData) => SubmitPromise,
|
||||||
|
loading: boolean,
|
||||||
opts: UseProductCreateFormOpts
|
opts: UseProductCreateFormOpts
|
||||||
): UseProductCreateFormResult {
|
): UseProductCreateFormResult {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -231,10 +233,6 @@ function useProductCreateForm(
|
||||||
triggerChange
|
triggerChange
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setExitDialogSubmitRef } = useExitFormDialog({
|
|
||||||
formId: PRODUCT_CREATE_FORM_ID
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
makeChangeHandler: makeMetadataChangeHandler
|
makeChangeHandler: makeMetadataChangeHandler
|
||||||
} = useMetadataChangeTrigger();
|
} = useMetadataChangeTrigger();
|
||||||
|
@ -357,6 +355,10 @@ function useProductCreateForm(
|
||||||
|
|
||||||
const submit = () => handleFormSubmit(data);
|
const submit = () => handleFormSubmit(data);
|
||||||
|
|
||||||
|
const { setExitDialogSubmitRef, setIsSubmitDisabled } = useExitFormDialog({
|
||||||
|
formId: PRODUCT_CREATE_FORM_ID
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
const shouldEnableSave = () => {
|
const shouldEnableSave = () => {
|
||||||
|
@ -387,12 +389,15 @@ function useProductCreateForm(
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const disabled = !shouldEnableSave();
|
const isSaveEnabled = !shouldEnableSave();
|
||||||
|
|
||||||
|
const isSaveDisabled = loading || !onSubmit || isSaveEnabled || !hasChanged;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data,
|
data,
|
||||||
disabled,
|
disabled: isSaveEnabled,
|
||||||
formErrors: form.errors,
|
formErrors: form.errors,
|
||||||
handlers: {
|
handlers: {
|
||||||
addStock: handleStockAdd,
|
addStock: handleStockAdd,
|
||||||
|
@ -416,7 +421,8 @@ function useProductCreateForm(
|
||||||
selectTaxRate: handleTaxTypeSelect
|
selectTaxRate: handleTaxTypeSelect
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,9 +430,10 @@ const ProductCreateForm: React.FC<ProductCreateFormProps> = ({
|
||||||
children,
|
children,
|
||||||
initial,
|
initial,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
loading,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
const props = useProductCreateForm(initial || {}, onSubmit, rest);
|
const props = useProductCreateForm(initial || {}, onSubmit, loading, rest);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -284,16 +284,10 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
||||||
fetchReferenceProducts={fetchReferenceProducts}
|
fetchReferenceProducts={fetchReferenceProducts}
|
||||||
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
||||||
assignReferencesAttributeId={assignReferencesAttributeId}
|
assignReferencesAttributeId={assignReferencesAttributeId}
|
||||||
|
disabled={disabled}
|
||||||
|
hasChannelChanged={hasChannelChanged}
|
||||||
>
|
>
|
||||||
{({
|
{({ change, data, formErrors, handlers, submit, isSaveDisabled }) => (
|
||||||
change,
|
|
||||||
data,
|
|
||||||
formErrors,
|
|
||||||
disabled: formDisabled,
|
|
||||||
handlers,
|
|
||||||
hasChanged,
|
|
||||||
submit
|
|
||||||
}) => (
|
|
||||||
<>
|
<>
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
|
@ -508,9 +502,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={
|
disabled={isSaveDisabled}
|
||||||
disabled || formDisabled || (!hasChanged && !hasChannelChanged)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
{canOpenAssignReferencesAttributeDialog && (
|
{canOpenAssignReferencesAttributeDialog && (
|
||||||
<AssignAttributeValueDialog
|
<AssignAttributeValueDialog
|
||||||
|
|
|
@ -157,7 +157,6 @@ export interface UseProductUpdateFormResult
|
||||||
ProductUpdateData,
|
ProductUpdateData,
|
||||||
ProductUpdateHandlers
|
ProductUpdateHandlers
|
||||||
> {
|
> {
|
||||||
disabled: boolean;
|
|
||||||
formErrors: FormErrors<ProductUpdateSubmitData>;
|
formErrors: FormErrors<ProductUpdateSubmitData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +192,8 @@ export interface ProductUpdateFormProps extends UseProductUpdateFormOpts {
|
||||||
children: (props: UseProductUpdateFormResult) => React.ReactNode;
|
children: (props: UseProductUpdateFormResult) => React.ReactNode;
|
||||||
product: ProductFragment;
|
product: ProductFragment;
|
||||||
onSubmit: (data: ProductUpdateSubmitData) => SubmitPromise;
|
onSubmit: (data: ProductUpdateSubmitData) => SubmitPromise;
|
||||||
|
disabled: boolean;
|
||||||
|
hasChannelChanged: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStocksData = (
|
const getStocksData = (
|
||||||
|
@ -222,6 +223,8 @@ const getStocksData = (
|
||||||
function useProductUpdateForm(
|
function useProductUpdateForm(
|
||||||
product: ProductFragment,
|
product: ProductFragment,
|
||||||
onSubmit: (data: ProductUpdateSubmitData) => SubmitPromise,
|
onSubmit: (data: ProductUpdateSubmitData) => SubmitPromise,
|
||||||
|
disabled: boolean,
|
||||||
|
hasChannelChanged: boolean,
|
||||||
opts: UseProductUpdateFormOpts
|
opts: UseProductUpdateFormOpts
|
||||||
): UseProductUpdateFormResult {
|
): UseProductUpdateFormResult {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -244,7 +247,8 @@ function useProductUpdateForm(
|
||||||
toggleValue,
|
toggleValue,
|
||||||
data: formData,
|
data: formData,
|
||||||
setChanged,
|
setChanged,
|
||||||
hasChanged
|
hasChanged,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = form;
|
} = form;
|
||||||
|
|
||||||
const attributes = useFormset(getAttributeInputFromProduct(product));
|
const attributes = useFormset(getAttributeInputFromProduct(product));
|
||||||
|
@ -435,12 +439,15 @@ function useProductUpdateForm(
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const disabled = !shouldEnableSave();
|
const isSaveEnabled = !shouldEnableSave();
|
||||||
|
|
||||||
|
const isSaveDisabled =
|
||||||
|
disabled || isSaveEnabled || (!hasChanged && !hasChannelChanged);
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data,
|
data,
|
||||||
disabled,
|
|
||||||
formErrors: form.errors,
|
formErrors: form.errors,
|
||||||
handlers: {
|
handlers: {
|
||||||
addStock: handleStockAdd,
|
addStock: handleStockAdd,
|
||||||
|
@ -464,7 +471,8 @@ function useProductUpdateForm(
|
||||||
selectTaxRate: handleTaxTypeSelect
|
selectTaxRate: handleTaxTypeSelect
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,9 +480,17 @@ const ProductUpdateForm: React.FC<ProductUpdateFormProps> = ({
|
||||||
children,
|
children,
|
||||||
product,
|
product,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
disabled,
|
||||||
|
hasChannelChanged,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
const props = useProductUpdateForm(product, onSubmit, rest);
|
const props = useProductUpdateForm(
|
||||||
|
product,
|
||||||
|
onSubmit,
|
||||||
|
disabled,
|
||||||
|
hasChannelChanged,
|
||||||
|
rest
|
||||||
|
);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -149,15 +149,9 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
|
||||||
fetchReferenceProducts={fetchReferenceProducts}
|
fetchReferenceProducts={fetchReferenceProducts}
|
||||||
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
||||||
assignReferencesAttributeId={assignReferencesAttributeId}
|
assignReferencesAttributeId={assignReferencesAttributeId}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({
|
{({ change, data, formErrors, handlers, submit, isSaveDisabled }) => (
|
||||||
change,
|
|
||||||
data,
|
|
||||||
formErrors,
|
|
||||||
disabled: formDisabled,
|
|
||||||
handlers,
|
|
||||||
submit
|
|
||||||
}) => (
|
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>{product?.name}</Backlink>
|
<Backlink onClick={onBack}>{product?.name}</Backlink>
|
||||||
<PageHeader title={header} />
|
<PageHeader title={header} />
|
||||||
|
@ -258,7 +252,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || formDisabled || !onSubmit}
|
disabled={isSaveDisabled}
|
||||||
labels={{
|
labels={{
|
||||||
confirm: intl.formatMessage(messages.saveVariant),
|
confirm: intl.formatMessage(messages.saveVariant),
|
||||||
delete: intl.formatMessage(messages.deleteVariant)
|
delete: intl.formatMessage(messages.deleteVariant)
|
||||||
|
|
|
@ -94,6 +94,7 @@ export interface ProductVariantCreateFormProps
|
||||||
children: (props: UseProductVariantCreateFormResult) => React.ReactNode;
|
children: (props: UseProductVariantCreateFormResult) => React.ReactNode;
|
||||||
product: ProductVariantCreateDataQuery["product"];
|
product: ProductVariantCreateDataQuery["product"];
|
||||||
onSubmit: (data: ProductVariantCreateData) => void;
|
onSubmit: (data: ProductVariantCreateData) => void;
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initial: ProductVariantCreateFormData = {
|
const initial: ProductVariantCreateFormData = {
|
||||||
|
@ -113,6 +114,7 @@ const initial: ProductVariantCreateFormData = {
|
||||||
function useProductVariantCreateForm(
|
function useProductVariantCreateForm(
|
||||||
product: ProductVariantCreateDataQuery["product"],
|
product: ProductVariantCreateDataQuery["product"],
|
||||||
onSubmit: (data: ProductVariantCreateData) => void,
|
onSubmit: (data: ProductVariantCreateData) => void,
|
||||||
|
disabled: boolean,
|
||||||
opts: UseProductVariantCreateFormOpts
|
opts: UseProductVariantCreateFormOpts
|
||||||
): UseProductVariantCreateFormResult {
|
): UseProductVariantCreateFormResult {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -126,7 +128,8 @@ function useProductVariantCreateForm(
|
||||||
handleChange,
|
handleChange,
|
||||||
hasChanged,
|
hasChanged,
|
||||||
data: formData,
|
data: formData,
|
||||||
formId
|
formId,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = form;
|
} = form;
|
||||||
|
|
||||||
const attributes = useFormset(attributeInput);
|
const attributes = useFormset(attributeInput);
|
||||||
|
@ -227,13 +230,18 @@ function useProductVariantCreateForm(
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
|
const formDisabled =
|
||||||
|
data.isPreorder &&
|
||||||
|
data.hasPreorderEndDate &&
|
||||||
|
!!form.errors.preorderEndDateTime;
|
||||||
|
|
||||||
|
const isSaveDisabled = disabled || formDisabled || !onSubmit;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data,
|
data,
|
||||||
disabled:
|
disabled,
|
||||||
data.isPreorder &&
|
|
||||||
data.hasPreorderEndDate &&
|
|
||||||
!!form.errors.preorderEndDateTime,
|
|
||||||
formErrors: form.errors,
|
formErrors: form.errors,
|
||||||
handlers: {
|
handlers: {
|
||||||
addStock: handleStockAdd,
|
addStock: handleStockAdd,
|
||||||
|
@ -250,7 +258,8 @@ function useProductVariantCreateForm(
|
||||||
selectAttributeReference: handleAttributeReferenceChange
|
selectAttributeReference: handleAttributeReferenceChange
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,9 +267,10 @@ const ProductVariantCreateForm: React.FC<ProductVariantCreateFormProps> = ({
|
||||||
children,
|
children,
|
||||||
product,
|
product,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
disabled,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
const props = useProductVariantCreateForm(product, onSubmit, rest);
|
const props = useProductVariantCreateForm(product, onSubmit, disabled, rest);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -218,16 +218,9 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
|
||||||
fetchReferenceProducts={fetchReferenceProducts}
|
fetchReferenceProducts={fetchReferenceProducts}
|
||||||
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
|
||||||
assignReferencesAttributeId={assignReferencesAttributeId}
|
assignReferencesAttributeId={assignReferencesAttributeId}
|
||||||
|
loading={loading}
|
||||||
>
|
>
|
||||||
{({
|
{({ change, data, formErrors, isSaveDisabled, handlers, submit }) => {
|
||||||
change,
|
|
||||||
data,
|
|
||||||
formErrors,
|
|
||||||
disabled: formDisabled,
|
|
||||||
handlers,
|
|
||||||
hasChanged,
|
|
||||||
submit
|
|
||||||
}) => {
|
|
||||||
const nonSelectionAttributes = data.attributes.filter(
|
const nonSelectionAttributes = data.attributes.filter(
|
||||||
byAttributeScope(VariantAttributeScope.NOT_VARIANT_SELECTION)
|
byAttributeScope(VariantAttributeScope.NOT_VARIANT_SELECTION)
|
||||||
);
|
);
|
||||||
|
@ -373,7 +366,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={loading || formDisabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
|
|
|
@ -130,12 +130,14 @@ export interface ProductVariantUpdateFormProps
|
||||||
extends UseProductVariantUpdateFormOpts {
|
extends UseProductVariantUpdateFormOpts {
|
||||||
children: (props: UseProductVariantUpdateFormResult) => React.ReactNode;
|
children: (props: UseProductVariantUpdateFormResult) => React.ReactNode;
|
||||||
variant: ProductVariantFragment;
|
variant: ProductVariantFragment;
|
||||||
|
loading: boolean;
|
||||||
onSubmit: (data: ProductVariantUpdateSubmitData) => SubmitPromise;
|
onSubmit: (data: ProductVariantUpdateSubmitData) => SubmitPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useProductVariantUpdateForm(
|
function useProductVariantUpdateForm(
|
||||||
variant: ProductVariantFragment,
|
variant: ProductVariantFragment,
|
||||||
onSubmit: (data: ProductVariantUpdateSubmitData) => SubmitPromise,
|
onSubmit: (data: ProductVariantUpdateSubmitData) => SubmitPromise,
|
||||||
|
loading: boolean,
|
||||||
opts: UseProductVariantUpdateFormOpts
|
opts: UseProductVariantUpdateFormOpts
|
||||||
): UseProductVariantUpdateFormResult {
|
): UseProductVariantUpdateFormResult {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -180,7 +182,8 @@ function useProductVariantUpdateForm(
|
||||||
data: formData,
|
data: formData,
|
||||||
setChanged,
|
setChanged,
|
||||||
hasChanged,
|
hasChanged,
|
||||||
formId
|
formId,
|
||||||
|
setIsSubmitDisabled
|
||||||
} = form;
|
} = form;
|
||||||
|
|
||||||
const { setExitDialogSubmitRef } = useExitFormDialog({
|
const { setExitDialogSubmitRef } = useExitFormDialog({
|
||||||
|
@ -332,6 +335,9 @@ function useProductVariantUpdateForm(
|
||||||
|
|
||||||
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
useEffect(() => setExitDialogSubmitRef(submit), [submit]);
|
||||||
|
|
||||||
|
const isSaveDisabled = loading || disabled || !hasChanged;
|
||||||
|
setIsSubmitDisabled(isSaveDisabled);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
change: handleChange,
|
change: handleChange,
|
||||||
data,
|
data,
|
||||||
|
@ -353,7 +359,8 @@ function useProductVariantUpdateForm(
|
||||||
selectAttributeReference: handleAttributeReferenceChange
|
selectAttributeReference: handleAttributeReferenceChange
|
||||||
},
|
},
|
||||||
hasChanged,
|
hasChanged,
|
||||||
submit
|
submit,
|
||||||
|
isSaveDisabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,9 +368,10 @@ const ProductVariantUpdateForm: React.FC<ProductVariantUpdateFormProps> = ({
|
||||||
children,
|
children,
|
||||||
variant,
|
variant,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
loading,
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
const props = useProductVariantUpdateForm(variant, onSubmit, rest);
|
const props = useProductVariantUpdateForm(variant, onSubmit, loading, rest);
|
||||||
|
|
||||||
return <form onSubmit={props.submit}>{children(props)}</form>;
|
return <form onSubmit={props.submit}>{children(props)}</form>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -122,10 +122,11 @@ export function createHandler(
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await productCreate(productVariables);
|
const result = await productCreate(productVariables);
|
||||||
|
|
||||||
let hasErrors = errors.length > 0;
|
let hasErrors = errors.length > 0;
|
||||||
|
|
||||||
const hasVariants = productType.hasVariants;
|
const hasVariants = productType?.hasVariants;
|
||||||
const productId = result.data.productCreate.product?.id;
|
const productId = result?.data?.productCreate?.product?.id;
|
||||||
|
|
||||||
if (!productId) {
|
if (!productId) {
|
||||||
return { errors };
|
return { errors };
|
||||||
|
|
|
@ -66,8 +66,13 @@ const ShippingZoneCreatePage: React.FC<ShippingZoneCreatePageProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit }) => (
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit }) => (
|
||||||
<>
|
<>
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
|
@ -105,7 +110,7 @@ const ShippingZoneCreatePage: React.FC<ShippingZoneCreatePageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
|
|
|
@ -124,8 +124,13 @@ const ShippingZoneDetailsPage: React.FC<ShippingZoneDetailsPageProps> = ({
|
||||||
} = useMetadataChangeTrigger();
|
} = useMetadataChangeTrigger();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form initial={initialForm} onSubmit={onSubmit} confirmLeave>
|
<Form
|
||||||
{({ change, data, hasChanged, submit, toggleValue }) => {
|
initial={initialForm}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
confirmLeave
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit, toggleValue }) => {
|
||||||
const handleWarehouseChange = createMultiAutocompleteSelectHandler(
|
const handleWarehouseChange = createMultiAutocompleteSelectHandler(
|
||||||
toggleValue,
|
toggleValue,
|
||||||
setWarehouseDisplayValues,
|
setWarehouseDisplayValues,
|
||||||
|
@ -215,7 +220,7 @@ const ShippingZoneDetailsPage: React.FC<ShippingZoneDetailsPageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { ChannelShippingData } from "@saleor/channels/utils";
|
||||||
import CardSpacer from "@saleor/components/CardSpacer";
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import Form from "@saleor/components/Form";
|
import Form, { FormDataWithOpts } from "@saleor/components/Form";
|
||||||
import { WithFormId } from "@saleor/components/Form/ExitFormDialogProvider";
|
import { WithFormId } from "@saleor/components/Form/ExitFormDialogProvider";
|
||||||
import Grid from "@saleor/components/Grid";
|
import Grid from "@saleor/components/Grid";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
@ -86,22 +86,30 @@ export const ShippingZoneRatesCreatePage: React.FC<ShippingZoneRatesCreatePagePr
|
||||||
type: null
|
type: null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkIfSaveIsDisabled = (
|
||||||
|
data: FormDataWithOpts<ShippingZoneRateCommonFormData>
|
||||||
|
) => {
|
||||||
|
const formDisabled = data.channelListings?.some(channel =>
|
||||||
|
validatePrice(channel.price)
|
||||||
|
);
|
||||||
|
|
||||||
|
return disabled || formDisabled || (!data.hasChanged && !hasChannelChanged);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
confirmLeave
|
confirmLeave
|
||||||
initial={initialForm}
|
initial={initialForm}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
formId={formId}
|
formId={formId}
|
||||||
|
checkIfSaveIsDisabled={checkIfSaveIsDisabled}
|
||||||
>
|
>
|
||||||
{({ change, data, hasChanged, submit, triggerChange, set }) => {
|
{({ change, data, isSaveDisabled, submit, triggerChange, set }) => {
|
||||||
const handleChannelsChange = createChannelsChangeHandler(
|
const handleChannelsChange = createChannelsChangeHandler(
|
||||||
shippingChannels,
|
shippingChannels,
|
||||||
onChannelsChange,
|
onChannelsChange,
|
||||||
triggerChange
|
triggerChange
|
||||||
);
|
);
|
||||||
const formDisabled = data.channelListings?.some(channel =>
|
|
||||||
validatePrice(channel.price)
|
|
||||||
);
|
|
||||||
const onDescriptionChange = (description: OutputData) => {
|
const onDescriptionChange = (description: OutputData) => {
|
||||||
set({ description });
|
set({ description });
|
||||||
triggerChange();
|
triggerChange();
|
||||||
|
@ -181,9 +189,7 @@ export const ShippingZoneRatesCreatePage: React.FC<ShippingZoneRatesCreatePagePr
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={
|
disabled={isSaveDisabled}
|
||||||
disabled || formDisabled || (!hasChanged && !hasChannelChanged)
|
|
||||||
}
|
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { ChannelShippingData } from "@saleor/channels/utils";
|
||||||
import CardSpacer from "@saleor/components/CardSpacer";
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import Form from "@saleor/components/Form";
|
import Form, { FormDataWithOpts } from "@saleor/components/Form";
|
||||||
import { WithFormId } from "@saleor/components/Form/ExitFormDialogProvider";
|
import { WithFormId } from "@saleor/components/Form/ExitFormDialogProvider";
|
||||||
import Grid from "@saleor/components/Grid";
|
import Grid from "@saleor/components/Grid";
|
||||||
import Metadata from "@saleor/components/Metadata/Metadata";
|
import Metadata from "@saleor/components/Metadata/Metadata";
|
||||||
|
@ -112,30 +112,38 @@ export const ShippingZoneRatesPage: React.FC<ShippingZoneRatesPageProps> = ({
|
||||||
makeChangeHandler: makeMetadataChangeHandler
|
makeChangeHandler: makeMetadataChangeHandler
|
||||||
} = useMetadataChangeTrigger();
|
} = useMetadataChangeTrigger();
|
||||||
|
|
||||||
|
const checkIfSaveIsDisabled = (
|
||||||
|
data: FormDataWithOpts<ShippingZoneRateUpdateFormData>
|
||||||
|
) => {
|
||||||
|
const formDisabled = data.channelListings?.some(channel =>
|
||||||
|
validatePrice(channel.price)
|
||||||
|
);
|
||||||
|
const formIsUnchanged =
|
||||||
|
!data.hasChanged && !hasChannelChanged && !havePostalCodesChanged;
|
||||||
|
|
||||||
|
return disabled || formDisabled || formIsUnchanged;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
confirmLeave
|
confirmLeave
|
||||||
initial={initialForm}
|
initial={initialForm}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
formId={formId}
|
formId={formId}
|
||||||
|
checkIfSaveIsDisabled={checkIfSaveIsDisabled}
|
||||||
>
|
>
|
||||||
{({ change, data, hasChanged, submit, set, triggerChange }) => {
|
{({ change, data, isSaveDisabled, submit, set, triggerChange }) => {
|
||||||
const handleChannelsChange = createChannelsChangeHandler(
|
const handleChannelsChange = createChannelsChangeHandler(
|
||||||
shippingChannels,
|
shippingChannels,
|
||||||
onChannelsChange,
|
onChannelsChange,
|
||||||
triggerChange
|
triggerChange
|
||||||
);
|
);
|
||||||
const formDisabled = data.channelListings?.some(channel =>
|
|
||||||
validatePrice(channel.price)
|
|
||||||
);
|
|
||||||
const onDescriptionChange = (description: OutputData) => {
|
const onDescriptionChange = (description: OutputData) => {
|
||||||
set({ description });
|
set({ description });
|
||||||
triggerChange();
|
triggerChange();
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeMetadata = makeMetadataChangeHandler(change);
|
const changeMetadata = makeMetadataChangeHandler(change);
|
||||||
const formIsUnchanged =
|
|
||||||
!hasChanged && !hasChannelChanged && !havePostalCodesChanged;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
|
@ -212,7 +220,7 @@ export const ShippingZoneRatesPage: React.FC<ShippingZoneRatesPageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || formDisabled || formIsUnchanged}
|
disabled={isSaveDisabled}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -134,8 +134,9 @@ const SiteSettingsPage: React.FC<SiteSettingsPageProps> = props => {
|
||||||
return submitFunc(data);
|
return submitFunc(data);
|
||||||
}}
|
}}
|
||||||
confirmLeave
|
confirmLeave
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{({ change, data, hasChanged, submit }) => {
|
{({ change, data, isSaveDisabled, submit }) => {
|
||||||
const countryChoices = mapCountriesToChoices(shop?.countries || []);
|
const countryChoices = mapCountriesToChoices(shop?.countries || []);
|
||||||
const handleCountryChange = createSingleAutocompleteSelectHandler(
|
const handleCountryChange = createSingleAutocompleteSelectHandler(
|
||||||
change,
|
change,
|
||||||
|
@ -201,7 +202,7 @@ const SiteSettingsPage: React.FC<SiteSettingsPageProps> = props => {
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -101,8 +101,13 @@ const StaffDetailsPage: React.FC<StaffDetailsPageProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ data: formData, change, hasChanged, submit, toggleValue }) => {
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ data: formData, change, isSaveDisabled, submit, toggleValue }) => {
|
||||||
const permissionGroupsChange = createMultiAutocompleteSelectHandler(
|
const permissionGroupsChange = createMultiAutocompleteSelectHandler(
|
||||||
toggleValue,
|
toggleValue,
|
||||||
setPermissionGroupsDisplayValues,
|
setPermissionGroupsDisplayValues,
|
||||||
|
@ -187,7 +192,7 @@ const StaffDetailsPage: React.FC<StaffDetailsPageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -46,8 +46,13 @@ const CountryListPage: React.FC<CountryListPageProps> = ({
|
||||||
showGross: maybe(() => shop.displayGrossPrices, false)
|
showGross: maybe(() => shop.displayGrossPrices, false)
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={onSubmit}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit }) => (
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit }) => (
|
||||||
<>
|
<>
|
||||||
<Container>
|
<Container>
|
||||||
<Backlink onClick={onBack}>
|
<Backlink onClick={onBack}>
|
||||||
|
@ -77,7 +82,7 @@ const CountryListPage: React.FC<CountryListPageProps> = ({
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
state={saveButtonBarState}
|
state={saveButtonBarState}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
|
@ -84,8 +84,13 @@ const WarehouseDetailsPage: React.FC<WarehouseDetailsPageProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form confirmLeave initial={initialForm} onSubmit={handleSubmit}>
|
<Form
|
||||||
{({ change, data, hasChanged, submit, set }) => {
|
confirmLeave
|
||||||
|
initial={initialForm}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{({ change, data, isSaveDisabled, submit, set }) => {
|
||||||
const countryChoices = mapCountriesToChoices(countries);
|
const countryChoices = mapCountriesToChoices(countries);
|
||||||
const handleCountryChange = createSingleAutocompleteSelectHandler(
|
const handleCountryChange = createSingleAutocompleteSelectHandler(
|
||||||
change,
|
change,
|
||||||
|
@ -134,7 +139,7 @@ const WarehouseDetailsPage: React.FC<WarehouseDetailsPageProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Savebar
|
<Savebar
|
||||||
disabled={disabled || !hasChanged}
|
disabled={isSaveDisabled}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
|
|
Loading…
Reference in a new issue