import { Component, ReactNode, ComponentType } from 'react'; import { connect } from 'react-redux'; import compose from 'recompose/compose'; import inflection from 'inflection'; import { reset } from 'redux-form'; import withTranslate from '../i18n/translate'; import { crudGetOne, crudUpdate, startUndoable as startUndoableAction, } from '../actions'; import { REDUX_FORM_NAME } from '../form'; import checkMinimumRequiredProps from './checkMinimumRequiredProps'; import { Translate, Record, Dispatch, Identifier } from '../types'; import { RedirectionSideEffect } from '../sideEffect'; interface ChildrenFuncParams { isLoading: boolean; defaultTitle: string; save: (data: Record, redirect: RedirectionSideEffect) => void; resource: string; basePath: string; record?: Record; redirect: RedirectionSideEffect; translate: Translate; version: number; } interface Props { basePath: string; children: (params: ChildrenFuncParams) => ReactNode; hasCreate?: boolean; hasEdit?: boolean; hasShow?: boolean; hasList?: boolean; id: Identifier; isLoading: boolean; resource: string; undoable?: boolean; } interface EnhancedProps { crudGetOne: Dispatch; dispatchCrudUpdate: Dispatch; record?: Record; resetForm: (form: string) => void; startUndoable: Dispatch; translate: Translate; version: number; } /** * Page component for the Edit view * * The `` component renders the page title and actions, * fetches the record from the data provider. * It is not responsible for rendering the actual form - * that's the job of its child component (usually ``), * to which it passes pass the `record` as prop. * * The `` component accepts the following props: * * - title * - actions * * Both expect an element for value. * * @example * // in src/posts.js * import React from 'react'; * import { Edit, SimpleForm, TextInput } from 'react-admin'; * * export const PostEdit = (props) => ( * * * * * * ); * * // in src/App.js * import React from 'react'; * import { Admin, Resource } from 'react-admin'; * * import { PostEdit } from './posts'; * * const App = () => ( * * * * ); * export default App; */ export class UnconnectedEditController extends Component< Props & EnhancedProps > { componentDidMount() { this.updateData(); } componentWillReceiveProps(nextProps: Props & EnhancedProps) { if ( this.props.id !== nextProps.id || nextProps.version !== this.props.version ) { this.props.resetForm(REDUX_FORM_NAME); this.updateData(nextProps.resource, nextProps.id); } } defaultRedirectRoute() { return 'list'; } updateData(resource = this.props.resource, id = this.props.id) { this.props.crudGetOne(resource, id, this.props.basePath); } save = (data, redirect) => { const { undoable = true, startUndoable, dispatchCrudUpdate, } = this.props; if (undoable) { startUndoable( crudUpdate( this.props.resource, this.props.id, data, this.props.record, this.props.basePath, redirect ) ); } else { dispatchCrudUpdate( this.props.resource, this.props.id, data, this.props.record, this.props.basePath, redirect ); } }; render() { const { basePath, children, id, isLoading, record, resource, translate, version, } = this.props; if (!children) { return null; } const resourceName = translate(`resources.${resource}.name`, { smart_count: 1, _: inflection.humanize(inflection.singularize(resource)), }); const defaultTitle = translate('ra.page.edit', { name: `${resourceName}`, id, record, }); return children({ isLoading, defaultTitle, save: this.save, resource, basePath, record, redirect: this.defaultRedirectRoute(), translate, version, }); } } function mapStateToProps(state, props) { return { id: props.id, record: state.admin.resources[props.resource] ? state.admin.resources[props.resource].data[props.id] : null, isLoading: state.admin.loading > 0, version: state.admin.ui.viewVersion, }; } const EditController = compose( checkMinimumRequiredProps('Edit', ['basePath', 'resource']), connect( mapStateToProps, { crudGetOne, dispatchCrudUpdate: crudUpdate, startUndoable: startUndoableAction, resetForm: reset, } ), withTranslate )(UnconnectedEditController); export default EditController as ComponentType;