Reuse single data entry in multi
This commit is contained in:
parent
aafb81a17b
commit
f67323fc16
@ -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);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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,15 +82,18 @@ class MultiDataEntry extends Component<MultiDataEntryProps> {
|
|||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
:'\u00A0'
|
:'\u00A0'
|
||||||
: values.map((item, i) => (
|
: <>
|
||||||
|
{values.map((val, i) => (
|
||||||
<div className="input-group" key={i}>
|
<div className="input-group" key={i}>
|
||||||
<input className="form-control" type="text"
|
<TextDataEntryInput
|
||||||
key={`${props.slug}-${i}`} name={`${props.slug}-${i}`}
|
slug={`${props.slug}-${i}`}
|
||||||
data-index={i}
|
value={val}
|
||||||
value={item || ''}
|
|
||||||
placeholder={props.placeholder}
|
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
onChange={this.edit}
|
onChange={(key, val) => this.edit(i, 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.remove}
|
||||||
@ -90,14 +101,26 @@ class MultiDataEntry extends Component<MultiDataEntryProps> {
|
|||||||
data-index={i} className="btn btn-outline-dark">✕</button>
|
data-index={i} className="btn btn-outline-dark">✕</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))
|
))}
|
||||||
|
<div className="input-group">
|
||||||
|
<TextDataEntryInput
|
||||||
|
slug='new'
|
||||||
|
value={this.state.newValue}
|
||||||
|
disabled={props.disabled}
|
||||||
|
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.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>;
|
</Fragment>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user