Skip to content

Commit 9598816

Browse files
Merge pull request #2120 from creative-commoners/pulls/3/convert-more
ENH Convert more admin components to functional
2 parents cbc9f5e + c3721e6 commit 9598816

File tree

22 files changed

+2001
-352
lines changed

22 files changed

+2001
-352
lines changed

client/dist/js/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/src/bundles/bundle.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ import 'expose-loader?exposes=ListGroup!components/ListGroup/ListGroup';
4848
import 'expose-loader?exposes=ListGroupItem!components/ListGroup/ListGroupItem';
4949
import 'expose-loader?exposes=Loading!components/Loading/Loading';
5050
import 'expose-loader?exposes=CircularLoading!components/Loading/CircularLoading';
51+
import 'expose-loader?exposes=InputField!components/InputField/InputField';
5152
import 'expose-loader?exposes=TextField!components/TextField/TextField';
52-
import 'expose-loader?exposes=LiteralField!components/LiteralField/LiteralField';
53+
import 'expose-loader?exposes=LegacyInputField!legacy/ReactComponents/LegacyInputField';
54+
import 'expose-loader?exposes=LegacyTextField!legacy/ReactComponents/LegacyTextField';
55+
import 'expose-loader?exposes=LegacyDateField!legacy/ReactComponents/LegacyDateField';
56+
import 'expose-loader?exposes=LegacyDatetimeField!legacy/ReactComponents/LegacyDatetimeField';
5357
import 'expose-loader?exposes=Toolbar!components/Toolbar/Toolbar';
5458
import 'expose-loader?exposes=Breadcrumb!components/Breadcrumb/Breadcrumb';
5559
import 'expose-loader?exposes=ResizeAware!components/ResizeAware/ResizeAware';
Lines changed: 135 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,144 @@
11
import fieldHolder from 'components/FieldHolder/FieldHolder';
2-
import moment from 'moment';
2+
import momentLib from 'moment';
33
import modernizr from 'modernizr';
44
import i18n from 'i18n';
55
import PropTypes from 'prop-types';
6-
import { Component as TextField } from '../TextField/TextField';
6+
import { getInputProps as getInputFieldProps, render } from '../InputField/InputField';
77

88
const localFormat = 'L';
99

10-
class DateField extends TextField {
11-
render() {
12-
return super.render();
13-
}
14-
15-
moment(...args) {
16-
moment.locale(this.getLang());
17-
return moment(...args);
18-
}
19-
20-
getLang() {
21-
const lang = this.asHTML5() ? this.props.isoLang : this.props.lang;
22-
23-
return lang || moment().locale();
24-
}
25-
26-
/**
27-
* If this field is to be rendered as a HTML5 date input
28-
*
29-
* @return {Boolean }
30-
*/
31-
asHTML5() {
32-
return this.props.data.html5 && this.hasNativeSupport();
33-
}
10+
/**
11+
* Check if this field has native html5 date support
12+
*
13+
* @return {Boolean}
14+
*/
15+
const hasNativeSupport = (props) => props.modernizr.inputtypes.date;
16+
17+
/**
18+
* If this field is to be rendered as a HTML5 date input
19+
*
20+
* @return {Boolean }
21+
*/
22+
const asHTML5 = (props, hasNativeSupportFn = hasNativeSupport) => (
23+
props.data.html5 && hasNativeSupportFn(props)
24+
);
25+
26+
const getLang = (props, hasNativeSupportFn = hasNativeSupport) => {
27+
const lang = asHTML5(props, hasNativeSupportFn) ? props.isoLang : props.lang;
28+
return lang || momentLib().locale();
29+
};
3430

35-
/**
36-
* Check if this field has native html5 date support
37-
*
38-
* @return {Boolean}
39-
*/
40-
hasNativeSupport() {
41-
return this.props.modernizr.inputtypes.date;
42-
}
31+
const moment = (props, hasNativeSupportFn = hasNativeSupport, ...momentArgs) => {
32+
momentLib.locale(getLang(props, hasNativeSupportFn));
33+
return momentLib(...momentArgs);
34+
};
4335

44-
getInputProps() {
45-
const placeholder = i18n.inject(
46-
i18n._t('Admin.FormatExample', 'Example: {format}'),
47-
{ format: this.moment().endOf('month').format(localFormat) }
48-
);
49-
50-
const value = this.asHTML5()
51-
? this.props.value
52-
: this.getLocalisedValue();
53-
const type = this.asHTML5() ? 'date' : 'text';
54-
const props = {
55-
...super.getInputProps(),
56-
type,
57-
// `parse()` of redux-form `Field` should be used for parsing the
58-
// localised input value to iso format to pass to redux store but `Field`
59-
// is not accessible in this context.
60-
value,
61-
placeholder,
62-
};
63-
64-
return props;
65-
}
36+
const triggerChange = (props, event, value) => {
37+
props.onChange(event, { id: props.id, value });
38+
};
6639

67-
getLocalisedValue() {
68-
return this.convertToLocalised(this.props.value);
69-
}
40+
const convertToIso = (props, localDate) => {
41+
let isoDate = '';
7042

71-
isMultiline() {
72-
return false;
43+
if (localDate) {
44+
// Input value can be in local format 'L' or ISO format
45+
const dateObject = moment(props, hasNativeSupport, localDate, [localFormat, 'YYYY-MM-DD']);
46+
if (dateObject.isValid()) {
47+
isoDate = dateObject.format('YYYY-MM-DD');
48+
}
7349
}
7450

75-
/**
76-
* Handles changes to the text field's value.
77-
*
78-
* @param {Event} event
79-
*/
80-
handleChange(event) {
81-
const enteredValue = event.target.value;
82-
let isoValue = '';
83-
84-
// When browser support input=date the date value is already in iso format and html5 is enabled
85-
if (this.asHTML5()) {
86-
isoValue = enteredValue;
87-
} else {
88-
isoValue = this.convertToIso(enteredValue);
89-
}
51+
return isoDate;
52+
};
9053

91-
if (typeof this.props.onChange === 'function') {
92-
this.triggerChange(event, isoValue);
54+
const convertToLocalised = (props, isoDate) => {
55+
let localDate = '';
56+
if (isoDate) {
57+
const dateObject = moment(props, hasNativeSupport, isoDate);
58+
if (dateObject.isValid()) {
59+
localDate = dateObject.format(localFormat);
9360
}
9461
}
62+
return localDate;
63+
};
9564

96-
triggerChange(event, value) {
97-
this.props.onChange(event, { id: this.props.id, value });
65+
const getLocalisedValue = (props, convertToLocalisedFn = convertToLocalised) => (
66+
convertToLocalisedFn(props, props.value)
67+
);
68+
69+
const isMultiline = () => false;
70+
71+
/**
72+
* Handles changes to the text field's value.
73+
*
74+
* @param {Event} event
75+
*/
76+
const handleChange = (
77+
props,
78+
event,
79+
asHTML5Fn = asHTML5,
80+
convertToIsoFn = convertToIso,
81+
triggerChangeFn = triggerChange
82+
) => {
83+
const enteredValue = event.target.value;
84+
let isoValue = '';
85+
86+
// When browser support input=date the date value is already in iso format and html5 is enabled
87+
if (asHTML5Fn(props)) {
88+
isoValue = enteredValue;
89+
} else {
90+
isoValue = convertToIsoFn(props, enteredValue);
9891
}
9992

100-
convertToIso(localDate) {
101-
let isoDate = '';
102-
103-
if (localDate) {
104-
// Input value can be in local format 'L' or ISO format
105-
const dateObject = this.moment(localDate, [localFormat, 'YYYY-MM-DD']);
106-
if (dateObject.isValid()) {
107-
isoDate = dateObject.format('YYYY-MM-DD');
108-
}
109-
}
110-
111-
return isoDate;
93+
if (typeof props.onChange === 'function') {
94+
triggerChangeFn(props, event, isoValue);
11295
}
96+
};
11397

114-
convertToLocalised(isoDate) {
115-
let localDate = '';
116-
if (isoDate) {
117-
const dateObject = this.moment(isoDate);
118-
if (dateObject.isValid()) {
119-
localDate = dateObject.format(localFormat);
120-
}
121-
}
122-
return localDate;
123-
}
124-
}
98+
const getInputProps = (props, asHTML5Fn = asHTML5, getLocalisedValueFn = getLocalisedValue) => {
99+
const resolvedHandleChange = (nextProps, event) => (
100+
handleChange(nextProps, event, asHTML5Fn, convertToIso, triggerChange)
101+
);
102+
const placeholder = i18n.inject(
103+
i18n._t('Admin.FormatExample', 'Example: {format}'),
104+
{ format: moment(props, hasNativeSupport).endOf('month').format(localFormat) }
105+
);
106+
107+
const value = asHTML5Fn(props)
108+
? props.value
109+
: getLocalisedValueFn(props);
110+
const type = asHTML5Fn(props) ? 'date' : 'text';
111+
const inputProps = getInputFieldProps(props, resolvedHandleChange);
112+
return {
113+
...inputProps,
114+
type,
115+
// `parse()` of redux-form `Field` should be used for parsing the
116+
// localised input value to iso format to pass to redux store but `Field`
117+
// is not accessible in this context.
118+
value,
119+
placeholder,
120+
};
121+
};
122+
123+
const DateField = (_props) => {
124+
const defaultProps = {
125+
attributes: {},
126+
className: '',
127+
data: {},
128+
extraClass: '',
129+
modernizr,
130+
type: 'text',
131+
value: '',
132+
};
133+
134+
const props = {
135+
...defaultProps,
136+
..._props,
137+
};
138+
139+
const inputProps = getInputProps(props);
140+
return render(props, inputProps);
141+
};
125142

126143
DateField.propTypes = {
127144
lang: PropTypes.string,
@@ -132,11 +149,21 @@ DateField.propTypes = {
132149
}),
133150
};
134151

135-
DateField.defaultProps = {
136-
modernizr,
137-
data: {},
138-
};
139-
140152
export { DateField as Component };
141153

142154
export default fieldHolder(DateField);
155+
156+
// Exported for use other form fields which can override or reuse this logic
157+
export {
158+
getInputProps,
159+
isMultiline,
160+
hasNativeSupport,
161+
asHTML5,
162+
getLang,
163+
triggerChange,
164+
convertToLocalised,
165+
convertToIso,
166+
moment,
167+
getLocalisedValue,
168+
handleChange,
169+
};

0 commit comments

Comments
 (0)