import * as React from 'react'; import IReactComponentProps from '../../../common/structures/IReactComponentProps'; import classnames from 'classnames'; import { TableList } from '../TableList/TableList'; import CloseSmallSVG from '../../../svg/close--small.svg'; import isEqual from 'lodash.isequal'; import styles from '../TableList/TableList.sass'; import { PrimaryButton } from '../../buttons/PrimaryButton/PrimaryButton'; import { Button } from '../../buttons/Button/Button'; import { FunctionGeneric } from '../../../common/structures/Generics'; import { AddIcon } from '../../icons/Icons'; interface IProps extends IReactComponentProps { data?: any[]; header?: React.ReactNode; itemTemplate: any; labelSingular?: string; onBeforeRemove?: FunctionGeneric; onChange?: FunctionGeneric; onSubmit?: FunctionGeneric; repeatingContent: FunctionGeneric; submitDisabled?: boolean; submitLabel?: string; } interface IState { addingItem: boolean; initialData: any; unsavedData: any; } export default class TableListRepeater extends React.Component { static defaultProps: Partial = { labelSingular: 'Item', submitDisabled: false, submitLabel: 'Submit', }; constructor (props: IProps) { super(props); this.state = { addingItem: false, initialData: this.props.data ? [...this.props.data] : [], unsavedData: this.props.data ? [...this.props.data] : [], }; this.addItem = this.addItem.bind(this); } UNSAFE_componentWillReceiveProps (nextProps: IProps) { if (isEqual(nextProps.data, this.state.initialData)) { return; } if (nextProps.data) { this.setState({ initialData: [...nextProps.data], unsavedData: [...nextProps.data], }); } } onChange (unsavedData: any) { if (typeof this.props.onChange === 'function') { this.props.onChange(unsavedData); } } async addItem () { let newItem; if (typeof this.props.itemTemplate === 'function') { this.setState({ addingItem: true, }); try { newItem = await this.props.itemTemplate(); } catch (e) { this.setState({ addingItem: false, }); return; } } else { newItem = this.props.itemTemplate; } const unsavedData = this.state.unsavedData.concat([newItem]); this.onChange(unsavedData); this.setState({ addingItem: false, unsavedData, }); } async removeItem (index: number) { const unsavedData = this.state.unsavedData.slice(); if (this.props.onBeforeRemove) { const shouldDelete = await this.props.onBeforeRemove(unsavedData[index], index); if (!shouldDelete) { return; } } unsavedData.splice(index, 1); this.onChange(unsavedData); this.setState({ unsavedData, }); } updateItemFactory (index: number) { return (item: any) => { const unsavedData = this.state.unsavedData.slice(); unsavedData[index] = item; this.onChange(unsavedData); this.setState({ unsavedData, }); }; } renderHeader () { if (!this.props.header) { return; } return (
  • {this.props.header}
  • ); } renderSubmit () { if (!this.props.onSubmit) { return; } return (
    this.props.onSubmit && this.props.onSubmit(this.state.unsavedData)} disabled={isEqual(this.props.data, this.state.unsavedData) || this.props.submitDisabled} > {this.props.submitLabel}
    ); } render () { return (
    {this.renderHeader()} {this.state.unsavedData.map((item: any, index: number) => (
  • {this.props.repeatingContent.call(this, Object.assign({}, item), index, this.updateItemFactory(index))}
    this.removeItem(index)}>
  • ))}
    {this.renderSubmit()}
    ); } }