further separates contexts within Form for performance reasons
This commit is contained in:
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import config from 'payload/config';
|
||||
import Button from '../Button';
|
||||
import useForm from '../../forms/Form/useForm';
|
||||
import { useForm } from '../../forms/Form/context';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import useForm from '../../forms/Form/useForm';
|
||||
import { useForm } from '../../forms/Form/context';
|
||||
import { useUser } from '../../data/User';
|
||||
import Button from '../Button';
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export default createContext({});
|
||||
@@ -1,3 +0,0 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export default createContext({});
|
||||
26
src/client/components/forms/Form/context.js
Normal file
26
src/client/components/forms/Form/context.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
const FormContext = createContext({});
|
||||
const FieldContext = createContext({});
|
||||
const SubmittedContext = createContext(false);
|
||||
const ProcessingContext = createContext(false);
|
||||
const ModifiedContext = createContext(false);
|
||||
|
||||
const useForm = () => useContext(FormContext);
|
||||
const useFormFields = () => useContext(FieldContext);
|
||||
const useFormSubmitted = () => useContext(SubmittedContext);
|
||||
const useFormProcessing = () => useContext(ProcessingContext);
|
||||
const useFormModified = () => useContext(ModifiedContext);
|
||||
|
||||
export {
|
||||
FormContext,
|
||||
FieldContext,
|
||||
SubmittedContext,
|
||||
ProcessingContext,
|
||||
ModifiedContext,
|
||||
useForm,
|
||||
useFormFields,
|
||||
useFormSubmitted,
|
||||
useFormProcessing,
|
||||
useFormModified,
|
||||
};
|
||||
@@ -1,13 +1,11 @@
|
||||
import React, {
|
||||
useReducer, useEffect, useRef,
|
||||
useReducer, useEffect, useRef, useState,
|
||||
} from 'react';
|
||||
import { objectToFormData } from 'object-to-formdata';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { unflatten } from 'flatley';
|
||||
import HiddenInput from '../field-types/HiddenInput';
|
||||
import FormContext from './FormContext';
|
||||
import FieldContext from './FieldContext';
|
||||
import { useLocale } from '../../utilities/Locale';
|
||||
import { useStatusList } from '../../elements/Status';
|
||||
import { requests } from '../../../api';
|
||||
@@ -16,6 +14,8 @@ import { useUser } from '../../data/User';
|
||||
import fieldReducer from './fieldReducer';
|
||||
import initContextState from './initContextState';
|
||||
|
||||
import { SubmittedContext, ProcessingContext, ModifiedContext, FormContext, FieldContext } from './context';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'form';
|
||||
@@ -43,7 +43,7 @@ const Form = (props) => {
|
||||
ajax,
|
||||
method,
|
||||
action,
|
||||
handleAjaxResponse,
|
||||
handleResponse,
|
||||
onSuccess,
|
||||
children,
|
||||
className,
|
||||
@@ -56,6 +56,10 @@ const Form = (props) => {
|
||||
const { replaceStatus, addStatus, clearStatus } = useStatusList();
|
||||
const { refreshCookie } = useUser();
|
||||
|
||||
const [modified, setModified] = useState(false);
|
||||
const [processing, setProcessing] = useState(false);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const contextRef = useRef({ ...initContextState });
|
||||
|
||||
const [fields, dispatchFields] = useReducer(fieldReducer, {});
|
||||
@@ -69,7 +73,7 @@ const Form = (props) => {
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
contextRef.current.setSubmitted(true);
|
||||
setSubmitted(true);
|
||||
|
||||
const isValid = contextRef.current.validateForm();
|
||||
|
||||
@@ -106,17 +110,17 @@ const Form = (props) => {
|
||||
});
|
||||
|
||||
const formData = contextRef.current.createFormData();
|
||||
contextRef.current.setProcessing(true);
|
||||
setProcessing(true);
|
||||
|
||||
// Make the API call from the action
|
||||
return requests[method.toLowerCase()](action, {
|
||||
body: formData,
|
||||
}).then((res) => {
|
||||
contextRef.current.setModified(false);
|
||||
if (typeof handleAjaxResponse === 'function') return handleAjaxResponse(res);
|
||||
setModified(false);
|
||||
if (typeof handleResponse === 'function') return handleResponse(res);
|
||||
|
||||
return res.json().then((json) => {
|
||||
contextRef.current.setProcessing(false);
|
||||
setProcessing(false);
|
||||
clearStatus();
|
||||
|
||||
if (res.status < 400) {
|
||||
@@ -144,9 +148,7 @@ const Form = (props) => {
|
||||
}
|
||||
|
||||
if (Array.isArray(json.errors)) {
|
||||
const [fieldErrors, nonFieldErrors] = json.errors.reduce(([fieldErrs, nonFieldErrs], err) => {
|
||||
return err.field && err.message ? [[...fieldErrs, err], nonFieldErrs] : [fieldErrs, [...nonFieldErrs, err]];
|
||||
}, [[], []]);
|
||||
const [fieldErrors, nonFieldErrors] = json.errors.reduce(([fieldErrs, nonFieldErrs], err) => (err.field && err.message ? [[...fieldErrs, err], nonFieldErrs] : [fieldErrs, [...nonFieldErrs, err]]), [[], []]);
|
||||
|
||||
fieldErrors.forEach((err) => {
|
||||
dispatchFields({
|
||||
@@ -193,17 +195,11 @@ const Form = (props) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
contextRef.current.getFields = () => {
|
||||
return contextRef.current.fields;
|
||||
};
|
||||
contextRef.current.getFields = () => contextRef.current.fields;
|
||||
|
||||
contextRef.current.getField = (path) => {
|
||||
return contextRef.current.fields[path];
|
||||
};
|
||||
contextRef.current.getField = (path) => contextRef.current.fields[path];
|
||||
|
||||
contextRef.current.getData = () => {
|
||||
return reduceFieldsToValues(contextRef.current.fields, true);
|
||||
};
|
||||
contextRef.current.getData = () => reduceFieldsToValues(contextRef.current.fields, true);
|
||||
|
||||
contextRef.current.getSiblingData = (path) => {
|
||||
let siblingFields = contextRef.current.fields;
|
||||
@@ -247,40 +243,26 @@ const Form = (props) => {
|
||||
return unflattenedData?.[name];
|
||||
};
|
||||
|
||||
contextRef.current.getUnflattenedValues = () => {
|
||||
return reduceFieldsToValues(contextRef.current.fields);
|
||||
};
|
||||
contextRef.current.getUnflattenedValues = () => reduceFieldsToValues(contextRef.current.fields);
|
||||
|
||||
contextRef.current.validateForm = () => {
|
||||
return !Object.values(contextRef.current.fields).some((field) => {
|
||||
return field.valid === false;
|
||||
});
|
||||
};
|
||||
contextRef.current.validateForm = () => !Object.values(contextRef.current.fields).some((field) => field.valid === false);
|
||||
|
||||
contextRef.current.createFormData = () => {
|
||||
const data = reduceFieldsToValues(contextRef.current.fields);
|
||||
return objectToFormData(data, { indices: true });
|
||||
};
|
||||
|
||||
contextRef.current.setModified = (modified) => {
|
||||
contextRef.current.modified = modified;
|
||||
};
|
||||
|
||||
contextRef.current.setSubmitted = (submitted) => {
|
||||
contextRef.current.submitted = submitted;
|
||||
};
|
||||
|
||||
contextRef.current.setProcessing = (processing) => {
|
||||
contextRef.current.processing = processing;
|
||||
};
|
||||
contextRef.current.setModified = setModified;
|
||||
contextRef.current.setProcessing = setProcessing;
|
||||
contextRef.current.setSubmitted = setSubmitted;
|
||||
|
||||
useThrottledEffect(() => {
|
||||
refreshCookie();
|
||||
}, 15000, [fields]);
|
||||
|
||||
useEffect(() => {
|
||||
contextRef.current.modified = false;
|
||||
}, [locale, contextRef.current.modified]);
|
||||
setModified(false);
|
||||
}, [locale]);
|
||||
|
||||
const classes = [
|
||||
className,
|
||||
@@ -301,13 +283,20 @@ const Form = (props) => {
|
||||
...contextRef.current,
|
||||
}}
|
||||
>
|
||||
<HiddenInput
|
||||
path="locale"
|
||||
defaultValue={locale}
|
||||
/>
|
||||
{children}
|
||||
<SubmittedContext.Provider value={submitted}>
|
||||
<ProcessingContext.Provider value={processing}>
|
||||
<ModifiedContext.Provider value={modified}>
|
||||
<HiddenInput
|
||||
path="locale"
|
||||
defaultValue={locale}
|
||||
/>
|
||||
{children}
|
||||
</ModifiedContext.Provider>
|
||||
</ProcessingContext.Provider>
|
||||
</SubmittedContext.Provider>
|
||||
</FieldContext.Provider>
|
||||
</FormContext.Provider>
|
||||
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -318,7 +307,7 @@ Form.defaultProps = {
|
||||
ajax: true,
|
||||
method: 'POST',
|
||||
action: '',
|
||||
handleAjaxResponse: null,
|
||||
handleResponse: null,
|
||||
onSuccess: null,
|
||||
className: '',
|
||||
disableSuccessStatus: false,
|
||||
@@ -331,7 +320,7 @@ Form.propTypes = {
|
||||
ajax: PropTypes.bool,
|
||||
method: PropTypes.oneOf(['post', 'POST', 'get', 'GET', 'put', 'PUT', 'delete', 'DELETE']),
|
||||
action: PropTypes.string,
|
||||
handleAjaxResponse: PropTypes.func,
|
||||
handleResponse: PropTypes.func,
|
||||
onSuccess: PropTypes.func,
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
export default {
|
||||
processing: false,
|
||||
modified: false,
|
||||
submitted: false,
|
||||
getFields: () => { },
|
||||
getField: () => { },
|
||||
getData: () => { },
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { useContext } from 'react';
|
||||
import FormContext from './FormContext';
|
||||
|
||||
export default () => useContext(FormContext);
|
||||
@@ -1,4 +0,0 @@
|
||||
import { useContext } from 'react';
|
||||
import FieldContext from './FieldContext';
|
||||
|
||||
export default () => useContext(FieldContext);
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import FormContext from '../Form/FormContext';
|
||||
import { useFormProcessing } from '../Form/context';
|
||||
import Button from '../../elements/Button';
|
||||
|
||||
import './index.scss';
|
||||
@@ -8,12 +8,13 @@ import './index.scss';
|
||||
const baseClass = 'form-submit';
|
||||
|
||||
const FormSubmit = ({ children }) => {
|
||||
const formContext = useContext(FormContext);
|
||||
const processing = useFormProcessing();
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={formContext.processing ? true : undefined}
|
||||
disabled={processing ? true : undefined}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import useFieldType from '../../useFieldType';
|
||||
@@ -6,19 +6,21 @@ import Label from '../../Label';
|
||||
import Button from '../../../elements/Button';
|
||||
import CopyToClipboard from '../../../elements/CopyToClipboard';
|
||||
import { text } from '../../../../../fields/validations';
|
||||
import useFormFields from '../../Form/useFormFields';
|
||||
import { useFormFields } from '../../Form/context';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const path = 'apiKey';
|
||||
const baseClass = 'api-key';
|
||||
const validate = val => text(val, { minLength: 24, maxLength: 48 });
|
||||
const validate = (val) => text(val, { minLength: 24, maxLength: 48 });
|
||||
|
||||
const APIKey = (props) => {
|
||||
const {
|
||||
initialData,
|
||||
} = props;
|
||||
|
||||
const [initialAPIKey, setInitialAPIKey] = useState(null);
|
||||
|
||||
const { getField } = useFormFields();
|
||||
|
||||
const apiKey = getField(path);
|
||||
@@ -36,7 +38,7 @@ const APIKey = (props) => {
|
||||
|
||||
const fieldType = useFieldType({
|
||||
path: 'apiKey',
|
||||
initialData: initialData || uuidv4(),
|
||||
initialData: initialData || initialAPIKey,
|
||||
validate,
|
||||
});
|
||||
|
||||
@@ -45,6 +47,10 @@ const APIKey = (props) => {
|
||||
setValue,
|
||||
} = fieldType;
|
||||
|
||||
useEffect(() => {
|
||||
setInitialAPIKey(uuidv4());
|
||||
}, []);
|
||||
|
||||
const classes = [
|
||||
'field-type',
|
||||
'api-key',
|
||||
@@ -52,7 +58,7 @@ const APIKey = (props) => {
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
return (
|
||||
<>
|
||||
<React.Fragment>
|
||||
<div className={classes}>
|
||||
<Label
|
||||
htmlFor={path}
|
||||
@@ -73,7 +79,7 @@ const APIKey = (props) => {
|
||||
>
|
||||
Generate new API Key
|
||||
</Button>
|
||||
</>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import Password from '../Password';
|
||||
import Checkbox from '../Checkbox';
|
||||
import Button from '../../../elements/Button';
|
||||
import ConfirmPassword from '../ConfirmPassword';
|
||||
import useFormFields from '../../Form/useFormFields';
|
||||
import { useFormFields } from '../../Form/context';
|
||||
import APIKey from './APIKey';
|
||||
|
||||
import './index.scss';
|
||||
@@ -81,7 +81,11 @@ Auth.defaultProps = {
|
||||
|
||||
Auth.propTypes = {
|
||||
fieldTypes: PropTypes.shape({}).isRequired,
|
||||
initialData: PropTypes.shape({}),
|
||||
initialData: PropTypes.shape({
|
||||
enableAPIKey: PropTypes.bool,
|
||||
apiKey: PropTypes.string,
|
||||
email: PropTypes.string,
|
||||
}),
|
||||
useAPIKey: PropTypes.bool,
|
||||
requirePassword: PropTypes.bool,
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useCallback } from 'react';
|
||||
import useFieldType from '../../useFieldType';
|
||||
import Label from '../../Label';
|
||||
import Error from '../../Error';
|
||||
import useFormFields from '../../Form/useFormFields';
|
||||
import { useFormFields } from '../../Form/context';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
import withCondition from '../../withCondition';
|
||||
import Button from '../../../elements/Button';
|
||||
import reducer from '../rowReducer';
|
||||
import useForm from '../../Form/useForm';
|
||||
import { useForm } from '../../Form/context';
|
||||
import DraggableSection from '../../DraggableSection';
|
||||
import { useRenderedFields } from '../../RenderFields';
|
||||
import Error from '../../Error';
|
||||
@@ -139,7 +139,7 @@ const Flexible = (props) => {
|
||||
</header>
|
||||
|
||||
<Droppable droppableId="flexible-drop">
|
||||
{provided => (
|
||||
{(provided) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
@@ -151,7 +151,7 @@ const Flexible = (props) => {
|
||||
blockType = dataToInitialize?.[i]?.blockType;
|
||||
}
|
||||
|
||||
const blockToRender = blocks.find(block => block.slug === blockType);
|
||||
const blockToRender = blocks.find((block) => block.slug === blockType);
|
||||
|
||||
if (blockToRender) {
|
||||
return (
|
||||
@@ -186,8 +186,7 @@ const Flexible = (props) => {
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
}
|
||||
})}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -28,9 +28,9 @@ const NumberField = (props) => {
|
||||
const path = pathFromProps || name;
|
||||
|
||||
const memoizedValidate = useCallback((value) => {
|
||||
const validationResult = validate(value, { min, max });
|
||||
const validationResult = validate(value, { min, max, required });
|
||||
return validationResult;
|
||||
}, [validate, max, min]);
|
||||
}, [validate, max, min, required]);
|
||||
|
||||
const {
|
||||
value,
|
||||
@@ -46,6 +46,12 @@ const NumberField = (props) => {
|
||||
enableDebouncedValue: true,
|
||||
});
|
||||
|
||||
const handleChange = useCallback((e) => {
|
||||
let val = parseInt(e.target.value, 10);
|
||||
if (Number.isNaN(val)) val = '';
|
||||
setValue(val);
|
||||
}, [setValue]);
|
||||
|
||||
const classes = [
|
||||
'field-type',
|
||||
'number',
|
||||
@@ -72,7 +78,7 @@ const NumberField = (props) => {
|
||||
/>
|
||||
<input
|
||||
value={value || ''}
|
||||
onChange={e => setValue(parseInt(e.target.value, 10))}
|
||||
onChange={handleChange}
|
||||
disabled={readOnly ? 'disabled' : undefined}
|
||||
placeholder={placeholder}
|
||||
type="number"
|
||||
|
||||
@@ -8,7 +8,7 @@ import Button from '../../../elements/Button';
|
||||
import DraggableSection from '../../DraggableSection';
|
||||
import reducer from '../rowReducer';
|
||||
import { useRenderedFields } from '../../RenderFields';
|
||||
import useForm from '../../Form/useForm';
|
||||
import { useForm } from '../../Form/context';
|
||||
import useFieldType from '../../useFieldType';
|
||||
import Error from '../../Error';
|
||||
import { repeater } from '../../../../../fields/validations';
|
||||
@@ -124,35 +124,32 @@ const Repeater = (props) => {
|
||||
/>
|
||||
</header>
|
||||
<Droppable droppableId="repeater-drop">
|
||||
{provided => (
|
||||
{(provided) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
>
|
||||
{rows.length > 0 && rows.map((row, i) => {
|
||||
return (
|
||||
<DraggableSection
|
||||
key={row.key}
|
||||
id={row.key}
|
||||
blockType="repeater"
|
||||
singularLabel={singularLabel}
|
||||
isOpen={row.open}
|
||||
rowCount={rows.length}
|
||||
rowIndex={i}
|
||||
addRow={() => addRow(i)}
|
||||
removeRow={() => removeRow(i)}
|
||||
moveRow={moveRow}
|
||||
parentPath={path}
|
||||
initialData={row.data}
|
||||
initNull={row.initNull}
|
||||
customComponentsPath={`${customComponentsPath}${name}.fields.`}
|
||||
fieldTypes={fieldTypes}
|
||||
fieldSchema={fields}
|
||||
permissions={permissions.fields}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
{rows.length > 0 && rows.map((row, i) => (
|
||||
<DraggableSection
|
||||
key={row.key}
|
||||
id={row.key}
|
||||
blockType="repeater"
|
||||
singularLabel={singularLabel}
|
||||
isOpen={row.open}
|
||||
rowCount={rows.length}
|
||||
rowIndex={i}
|
||||
addRow={() => addRow(i)}
|
||||
removeRow={() => removeRow(i)}
|
||||
moveRow={moveRow}
|
||||
parentPath={path}
|
||||
initialData={row.data}
|
||||
initNull={row.initNull}
|
||||
customComponentsPath={`${customComponentsPath}${name}.fields.`}
|
||||
fieldTypes={fieldTypes}
|
||||
fieldSchema={fields}
|
||||
permissions={permissions.fields}
|
||||
/>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
useContext, useCallback, useEffect, useState,
|
||||
useCallback, useEffect, useState,
|
||||
} from 'react';
|
||||
import FormContext from '../Form/FormContext';
|
||||
import { useFormProcessing, useFormSubmitted, useFormModified, useForm } from '../Form/context';
|
||||
import useDebounce from '../../../hooks/useDebounce';
|
||||
import useUnmountEffect from '../../../hooks/useUnmountEffect';
|
||||
|
||||
@@ -23,10 +23,13 @@ const useFieldType = (options) => {
|
||||
// If no initialData, use default value
|
||||
const initialData = data !== undefined ? data : defaultValue;
|
||||
|
||||
const formContext = useContext(FormContext);
|
||||
const formContext = useForm();
|
||||
const submitted = useFormSubmitted();
|
||||
const processing = useFormProcessing();
|
||||
const modified = useFormModified();
|
||||
|
||||
const {
|
||||
dispatchFields, submitted, processing, getField, setModified, modified,
|
||||
dispatchFields, getField, setModified,
|
||||
} = formContext;
|
||||
|
||||
const [internalValue, setInternalValue] = useState(initialData);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import useFormFields from '../Form/useFormFields';
|
||||
import { useFormFields } from '../Form/context';
|
||||
|
||||
const withCondition = (Field) => {
|
||||
const CheckForCondition = (props) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import NavigationPrompt from 'react-router-navigation-prompt';
|
||||
import useForm from '../../forms/Form/useForm';
|
||||
import { useForm } from '../../forms/Form/context';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
import Button from '../../elements/Button';
|
||||
|
||||
@@ -13,27 +13,25 @@ const LeaveWithoutSaving = () => {
|
||||
|
||||
return (
|
||||
<NavigationPrompt when={modified}>
|
||||
{({ onConfirm, onCancel }) => {
|
||||
return (
|
||||
<div className={modalSlug}>
|
||||
<MinimalTemplate>
|
||||
<h1>Leave without saving</h1>
|
||||
<p>Your changes have not been saved. If you leave now, you will lose your changes.</p>
|
||||
<Button
|
||||
onClick={onCancel}
|
||||
buttonStyle="secondary"
|
||||
>
|
||||
Stay on this page
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
>
|
||||
Leave anyway
|
||||
</Button>
|
||||
</MinimalTemplate>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
{({ onConfirm, onCancel }) => (
|
||||
<div className={modalSlug}>
|
||||
<MinimalTemplate>
|
||||
<h1>Leave without saving</h1>
|
||||
<p>Your changes have not been saved. If you leave now, you will lose your changes.</p>
|
||||
<Button
|
||||
onClick={onCancel}
|
||||
buttonStyle="secondary"
|
||||
>
|
||||
Stay on this page
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
>
|
||||
Leave anyway
|
||||
</Button>
|
||||
</MinimalTemplate>
|
||||
</div>
|
||||
)}
|
||||
</NavigationPrompt>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import useFormFields from '../components/forms/Form/useFormFields';
|
||||
import { useFormFields } from '../components/forms/Form/context';
|
||||
|
||||
const useTitle = (useAsTitle) => {
|
||||
const { getField } = useFormFields();
|
||||
|
||||
Reference in New Issue
Block a user