Reuse single data entry in multi

This commit is contained in:
Maciej Ziarkowski 2020-01-06 16:21:44 +00:00
parent aafb81a17b
commit f67323fc16
3 changed files with 99 additions and 53 deletions

View File

@ -0,0 +1,30 @@
import React from 'react';
export interface TextDataEntryInputProps {
slug: string;
maxLength?: number;
disabled?: boolean;
placeholder?: string;
valueTransform?: (val: string) => string;
onChange?: (key: string, val: any) => void;
}
export const TextDataEntryInput: React.FC<TextDataEntryInputProps & {value?: string}> = props => {
return (
<input className="form-control" type="text"
id={props.slug}
name={props.slug}
value={props.value || ''}
maxLength={props.maxLength}
disabled={props.disabled}
placeholder={props.placeholder}
onChange={e => {
const transform = props.valueTransform || (x => x);
const val = e.target.value === '' ?
null :
transform(e.target.value);
props.onChange(props.slug, val);
}}
/>
);
};

View File

@ -2,6 +2,7 @@ import React, { Fragment } from 'react';
import { CopyProps } from '../data-containers/category-view-props'; import { CopyProps } from '../data-containers/category-view-props';
import { TextDataEntryInput, TextDataEntryInputProps } from './data-entry-input';
import { DataTitleCopyable } from './data-title'; import { DataTitleCopyable } from './data-title';
interface BaseDataEntryProps { interface BaseDataEntryProps {
@ -14,14 +15,11 @@ interface BaseDataEntryProps {
onChange?: (key: string, value: any) => void; onChange?: (key: string, value: any) => void;
} }
interface DataEntryProps extends BaseDataEntryProps { interface DataEntryProps extends BaseDataEntryProps, TextDataEntryInputProps {
value?: string; value?: string;
maxLength?: number;
placeholder?: string;
valueTransform?: (string) => string;
} }
const DataEntry: React.FunctionComponent<DataEntryProps> = (props) => { const DataEntry: React.FC<DataEntryProps> = (props) => {
return ( return (
<Fragment> <Fragment>
<DataTitleCopyable <DataTitleCopyable
@ -31,20 +29,15 @@ const DataEntry: React.FunctionComponent<DataEntryProps> = (props) => {
disabled={props.disabled || props.value == undefined || props.value == ''} disabled={props.disabled || props.value == undefined || props.value == ''}
copy={props.copy} copy={props.copy}
/> />
<input className="form-control" type="text" <TextDataEntryInput
id={props.slug} slug={props.slug}
name={props.slug} value={props.value}
value={props.value || ''} onChange={props.onChange}
maxLength={props.maxLength}
disabled={props.mode === 'view' || props.disabled} disabled={props.mode === 'view' || props.disabled}
maxLength={props.maxLength}
placeholder={props.placeholder} placeholder={props.placeholder}
onChange={e => { valueTransform={props.valueTransform}
const transform = props.valueTransform || (x => x);
const val = e.target.value === '' ?
null :
transform(e.target.value);
props.onChange(props.slug, val);
}}
/> />
</Fragment> </Fragment>
); );

View File

@ -3,49 +3,57 @@ import React, { Component, Fragment } from 'react';
import { sanitiseURL } from '../../helpers'; import { sanitiseURL } from '../../helpers';
import { BaseDataEntryProps } from './data-entry'; import { BaseDataEntryProps } from './data-entry';
import { TextDataEntryInput, TextDataEntryInputProps } from './data-entry-input';
import { DataTitleCopyable } from './data-title'; import { DataTitleCopyable } from './data-title';
interface MultiDataEntryProps extends BaseDataEntryProps { interface MultiDataEntryProps extends BaseDataEntryProps, TextDataEntryInputProps {
value: string[]; value: string[];
placeholder: string;
} }
class MultiDataEntry extends Component<MultiDataEntryProps> { interface MultiDataEntryState {
newValue: string;
}
class MultiDataEntry extends Component<MultiDataEntryProps, MultiDataEntryState> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {
newValue: ''
};
this.setNewValue = this.setNewValue.bind(this);
this.edit = this.edit.bind(this); this.edit = this.edit.bind(this);
this.add = this.add.bind(this); this.addNew = this.addNew.bind(this);
this.remove = this.remove.bind(this); this.remove = this.remove.bind(this);
this.getValues = this.getValues.bind(this); this.getValues = this.getValues.bind(this);
} }
getValues() { getValues() {
return (this.props.value && this.props.value.length)? this.props.value : [null]; return this.props.value == undefined ? [] : this.props.value;
} }
edit(event) { setNewValue(value: string) {
const editIndex = +event.target.dataset.index; this.setState({newValue: value});
const editItem = event.target.value; }
const oldValues = this.getValues();
const values = oldValues.map((item, i) => { edit(index: number, value: string) {
return i === editIndex ? editItem : item; let values = this.getValues();
}); values.splice(index, 1, value);
this.props.onChange(this.props.slug, values); this.props.onChange(this.props.slug, values);
} }
addNew(event) {
add(event) {
event.preventDefault(); event.preventDefault();
const values = this.getValues().concat(''); const values = this.getValues().concat(this.state.newValue);
this.setState({newValue: ''});
this.props.onChange(this.props.slug, values); this.props.onChange(this.props.slug, values);
} }
remove(event){ remove(event){
const removeIndex = +event.target.dataset.index; const removeIndex = +event.target.dataset.index;
const values = this.getValues().filter((_, i) => { const values = this.getValues();
return i !== removeIndex; values.splice(removeIndex, 1);
});
this.props.onChange(this.props.slug, values); this.props.onChange(this.props.slug, values);
} }
@ -74,30 +82,45 @@ class MultiDataEntry extends Component<MultiDataEntryProps> {
} }
</ul> </ul>
:'\u00A0' :'\u00A0'
: values.map((item, i) => ( : <>
<div className="input-group" key={i}> {values.map((val, i) => (
<input className="form-control" type="text" <div className="input-group" key={i}>
key={`${props.slug}-${i}`} name={`${props.slug}-${i}`} <TextDataEntryInput
data-index={i} slug={`${props.slug}-${i}`}
value={item || ''} value={val}
placeholder={props.placeholder} disabled={props.disabled}
onChange={(key, val) => this.edit(i, val)}
maxLength={props.maxLength}
placeholder={props.placeholder}
valueTransform={props.valueTransform}
/>
<div className="input-group-append">
<button type="button" onClick={this.remove}
title="Remove"
data-index={i} className="btn btn-outline-dark"></button>
</div>
</div>
))}
<div className="input-group">
<TextDataEntryInput
slug='new'
value={this.state.newValue}
disabled={props.disabled} disabled={props.disabled}
onChange={this.edit} onChange={(key, val) => this.setNewValue(val)}
maxLength={props.maxLength}
placeholder={props.placeholder}
valueTransform={props.valueTransform}
/> />
<div className="input-group-append"> <div className="input-group-append">
<button type="button" onClick={this.remove} <button type="button" onClick={this.addNew}
title="Remove" title="Add to list"
data-index={i} className="btn btn-outline-dark"></button> className="btn btn-outline-dark">Add to list</button>
</div> </div>
</div> </div>
)) </>
} }
<button
type="button"
title="Add"
onClick={this.add}
disabled={props.mode === 'view'}
className="btn btn-outline-dark">+</button>
</Fragment>; </Fragment>;
} }
} }