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

View File

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