@toolpad/core
Version:
Dashboard framework powered by Material UI.
262 lines (261 loc) • 8.8 kB
JavaScript
'use client';
var _CircularProgress;
import * as React from 'react';
import PropTypes from 'prop-types';
import Alert from '@mui/material/Alert';
import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
import invariant from 'invariant';
import { useNotifications } from "../useNotifications/index.js";
import { CrudContext } from "../shared/context.js";
import { useLocaleText } from "../AppProvider/LocalizationProvider.js";
import { CrudForm } from "./CrudForm.js";
import { DataSourceCache } from "./cache.js";
import { useCachedDataSource } from "./useCachedDataSource.js";
import { CRUD_DEFAULT_LOCALE_TEXT } from "./localeText.js";
import { jsx as _jsx } from "react/jsx-runtime";
function EditForm(props) {
const {
dataSource,
initialValues,
onSubmit,
onSubmitSuccess,
localeText
} = props;
const {
fields,
validate
} = dataSource;
const notifications = useNotifications();
const [formState, setFormState] = React.useState({
values: {
...Object.fromEntries(fields.filter(({
field
}) => field !== 'id').map(({
field,
type
}) => [field, type === 'boolean' ? initialValues[field] ?? false : initialValues[field]])),
...initialValues
},
errors: {}
});
const formValues = formState.values;
const formErrors = formState.errors;
const setFormValues = React.useCallback(newFormValues => {
setFormState(previousState => ({
...previousState,
values: newFormValues
}));
}, []);
const setFormErrors = React.useCallback(newFormErrors => {
setFormState(previousState => ({
...previousState,
errors: newFormErrors
}));
}, []);
const handleFormFieldChange = React.useCallback((name, value) => {
const validateField = async values => {
if (validate) {
const {
issues
} = await validate(values);
setFormErrors({
...formErrors,
[name]: issues?.find(issue => issue.path?.[0] === name)?.message
});
}
};
const newFormValues = {
...formValues,
[name]: value
};
setFormValues(newFormValues);
validateField(newFormValues);
}, [formErrors, formValues, setFormErrors, setFormValues, validate]);
const handleFormReset = React.useCallback(() => {
setFormValues(initialValues);
}, [initialValues, setFormValues]);
const handleFormSubmit = React.useCallback(async () => {
if (validate) {
const {
issues
} = await validate(formValues);
if (issues && issues.length > 0) {
setFormErrors(Object.fromEntries(issues.map(issue => [issue.path?.[0], issue.message])));
throw new Error('Form validation failed');
}
}
setFormErrors({});
try {
await onSubmit(formValues);
notifications.show(localeText.editSuccessMessage, {
severity: 'success',
autoHideDuration: 3000
});
if (onSubmitSuccess) {
await onSubmitSuccess(formValues);
}
} catch (editError) {
notifications.show(`${localeText.editErrorMessage} ${editError.message}`, {
severity: 'error',
autoHideDuration: 3000
});
throw editError;
}
}, [formValues, localeText.editErrorMessage, localeText.editSuccessMessage, notifications, onSubmit, onSubmitSuccess, setFormErrors, validate]);
return /*#__PURE__*/_jsx(CrudForm, {
dataSource: dataSource,
formState: formState,
onFieldChange: handleFormFieldChange,
onSubmit: handleFormSubmit,
onReset: handleFormReset,
submitButtonLabel: localeText.editLabel
});
}
process.env.NODE_ENV !== "production" ? EditForm.propTypes /* remove-proptypes */ = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
dataSource: PropTypes.object.isRequired,
initialValues: PropTypes.object.isRequired,
localeText: PropTypes.object.isRequired,
onSubmit: PropTypes.func.isRequired,
onSubmitSuccess: PropTypes.func
} : void 0;
/**
*
* Demos:
*
* - [CRUD](https://mui.com/toolpad/core/react-crud/)
*
* API:
*
* - [Edit API](https://mui.com/toolpad/core/api/edit)
*/
function Edit(props) {
const {
id,
onSubmitSuccess,
dataSourceCache,
localeText: propsLocaleText
} = props;
const globalLocaleText = useLocaleText();
const crudContext = React.useContext(CrudContext);
const dataSource = props.dataSource ?? crudContext.dataSource;
invariant(dataSource, 'No data source found.');
const cache = React.useMemo(() => {
const manualCache = dataSourceCache ?? crudContext.dataSourceCache;
return typeof manualCache !== 'undefined' ? manualCache : new DataSourceCache();
}, [crudContext.dataSourceCache, dataSourceCache]);
const cachedDataSource = useCachedDataSource(dataSource, cache);
const {
fields,
validate,
...methods
} = cachedDataSource;
const {
getOne,
updateOne
} = methods;
const [data, setData] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(false);
const [error, setError] = React.useState(null);
const loadData = React.useCallback(async () => {
setError(null);
setIsLoading(true);
try {
const showData = await getOne(id);
setData(showData);
} catch (showDataError) {
setError(showDataError);
}
setIsLoading(false);
}, [getOne, id]);
React.useEffect(() => {
loadData();
}, [loadData]);
const handleSubmit = React.useCallback(async formValues => {
const updatedData = await updateOne(id, formValues);
setData(updatedData);
}, [id, updateOne]);
const renderEdit = React.useMemo(() => {
if (isLoading) {
return /*#__PURE__*/_jsx(Box, {
sx: {
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
m: 1
},
children: _CircularProgress || (_CircularProgress = /*#__PURE__*/_jsx(CircularProgress, {}))
});
}
if (error) {
return /*#__PURE__*/_jsx(Box, {
sx: {
flexGrow: 1
},
children: /*#__PURE__*/_jsx(Alert, {
severity: "error",
children: error.message
})
});
}
const localeText = {
...CRUD_DEFAULT_LOCALE_TEXT,
...globalLocaleText,
...propsLocaleText
};
return data ? /*#__PURE__*/_jsx(EditForm, {
dataSource: dataSource,
initialValues: data,
onSubmit: handleSubmit,
onSubmitSuccess: onSubmitSuccess,
localeText: localeText
}) : null;
}, [data, dataSource, error, globalLocaleText, handleSubmit, isLoading, onSubmitSuccess, propsLocaleText]);
return /*#__PURE__*/_jsx(Box, {
sx: {
display: 'flex',
flex: 1
},
children: renderEdit
});
}
process.env.NODE_ENV !== "production" ? Edit.propTypes /* remove-proptypes */ = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
/**
* Server-side [data source](https://mui.com/toolpad/core/react-crud/#data-sources).
*/
dataSource: PropTypes.object,
/**
* [Cache](https://mui.com/toolpad/core/react-crud/#data-caching) for the data source.
*/
dataSourceCache: PropTypes.shape({
cache: PropTypes.object.isRequired,
clear: PropTypes.func.isRequired,
get: PropTypes.func.isRequired,
set: PropTypes.func.isRequired,
ttl: PropTypes.number.isRequired
}),
/**
* @ignore
*/
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
/**
* Locale text for the component.
*/
localeText: PropTypes.object,
/**
* Callback fired when the form is successfully submitted.
*/
onSubmitSuccess: PropTypes.func
} : void 0;
export { Edit };