Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TimePicker] Update time state on new defaultTime prop. #3095

Merged
merged 1 commit into from
Feb 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,33 @@ import TimePicker from 'material-ui/lib/time-picker/time-picker';

export default class TimePickerExampleComplex extends React.Component {

constructor(props) {
super(props);
this.state = {value24: null, value12: null};
}

handleChangeTimePicker12 = (err, time) => {
this.refs.picker12hr.setTime(time);
handleChangeTimePicker24 = (e, date) => {
this.setState({value24: date});
};

handleChangeTimePicker24 = (err, time) => {
this.refs.picker24hr.setTime(time);
handleChangeTimePicker12 = (e, date) => {
this.setState({value12: date});
};

render() {
return (
<div>
<TimePicker
ref="picker12hr"
format="ampm"
hintText="12hr Format"
onChange={this.handleChangeTimePicker24}
value={this.state.value12}
onChange={this.handleChangeTimePicker12}
/>
<TimePicker
ref="picker24hr"
format="24hr"
hintText="24hr Format"
onChange={this.handleChangeTimePicker12}
value={this.state.value24}
onChange={this.handleChangeTimePicker24}
/>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions src/time-picker/clock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ const Clock = React.createClass({
getInitialState() {
return {
muiTheme: this.context.muiTheme || getMuiTheme(),
selectedTime: this.props.initialTime,
selectedTime: this.props.initialTime || new Date(),
mode: 'hour',
};
},

componentWillReceiveProps(nextProps, nextContext) {
this.setState({
muiTheme: nextContext.muiTheme || this.state.muiTheme,
selectedTime: nextProps.initialTime,
selectedTime: nextProps.initialTime || new Date(),
});
},

Expand Down
79 changes: 47 additions & 32 deletions src/time-picker/time-picker.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react';
import warning from 'warning';
import DateTime from '../utils/date-time.js';
import TimePickerDialog from './time-picker-dialog';
import TextField from '../text-field';
import getMuiTheme from '../styles/getMuiTheme';
Expand Down Expand Up @@ -76,6 +78,11 @@ const TimePicker = React.createClass({
* Override the inline-styles of TimePicker's TextField element.
*/
textFieldStyle: React.PropTypes.object,

/**
* Sets the time for the Time Picker programmatically.
*/
value: React.PropTypes.object,
},

contextTypes: {
Expand All @@ -94,47 +101,41 @@ const TimePicker = React.createClass({

getInitialState() {
return {
time: this.props.defaultTime || emptyTime,
time: this._isControlled() ? this._getControlledTime() : this.props.defaultTime,
dialogTime: new Date(),
muiTheme: this.context.muiTheme || getMuiTheme(),
};
},

formatTime(date) {
let hours = date.getHours();
let mins = date.getMinutes().toString();

if (this.props.format === 'ampm') {
const isAM = hours < 12;
hours = hours % 12;
const additional = isAM ? ' am' : ' pm';
hours = (hours || 12).toString();

if (mins.length < 2 ) mins = `0${mins}`;

if (this.props.pedantic) {
// Treat midday/midnight specially http://www.nist.gov/pml/div688/times.cfm
if (hours === '12' && mins === '00') {
return additional === ' pm' ? '12 noon' : '12 midnight';
}
}

return hours + (mins === '00' ? '' : `:${mins}`) + additional;
componentWillReceiveProps(nextProps, nextContext) {
const newState = this.state;
if (nextContext.muiTheme) {
newState.muiTheme = nextContext.muiTheme;
}

hours = hours.toString();

if (hours.length < 2) hours = `0${hours}`;
if (mins.length < 2) mins = `0${mins}`;

return `${hours}:${mins}`;
newState.time = this._getControlledTime(nextProps);
this.setState(newState);
},


/**
* Deprecated.
* returns timepicker value.
**/
getTime() {
warning(false, `getTime() method is deprecated. Use the defaultTime property
instead. Or use the TimePicker as a controlled component with the value
property.`);
return this.state.time;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, what about displaying a warning when people use this method? People won't read the comment 😁.

},

/**
* Deprecated
* sets timepicker value.
**/
setTime(time) {
warning(false, `setTime() method is deprecated. Use the defaultTime property
instead. Or use the TimePicker as a controlled component with the value
property.`);
this.setState({time: time ? time : emptyTime});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using something like warning(false, 'setTime is deprecated... '); ?

},

Expand All @@ -147,14 +148,15 @@ const TimePicker = React.createClass({

openDialog() {
this.setState({
dialogTime: this.getTime(),
dialogTime: this.state.time,
});

this.refs.dialogWindow.show();
},

_handleDialogAccept(t) {
this.setTime(t);
this.setState({
time: t,
});
if (this.props.onChange) this.props.onChange(null, t);
},

Expand All @@ -171,6 +173,18 @@ const TimePicker = React.createClass({
if (this.props.onTouchTap) this.props.onTouchTap(e);
},

_isControlled() {
return this.props.value !== null;
},

_getControlledTime(props = this.props) {
let result = null;
if (DateTime.isDateObject(props.value)) {
result = props.value;
}
return result;
},

render() {
const {
autoOk,
Expand All @@ -181,6 +195,7 @@ const TimePicker = React.createClass({
onDismiss,
style,
textFieldStyle,
pedantic,
...other,
} = this.props;

Expand All @@ -197,7 +212,7 @@ const TimePicker = React.createClass({
{...other}
style={textFieldStyle}
ref="input"
value={time === emptyTime ? null : this.formatTime(time)}
value={time === emptyTime ? null : DateTime.formatTime(time, format, pedantic)}
onFocus={this._handleInputFocus}
onTouchTap={this._handleInputTouchTap}
/>
Expand Down
58 changes: 58 additions & 0 deletions src/utils/date-time.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ export default {
return newDate;
},

addHours(d, hours) {
const newDate = this.clone(d);
newDate.setHours(d.getHours() + hours);
return newDate;
},

addMinutes(d, minutes) {
const newDate = this.clone(d);
newDate.setMinutes(d.getMinutes() + minutes);
return newDate;
},

addSeconds(d, seconds) {
const newDate = this.clone(d);
newDate.setSeconds(d.getMinutes() + seconds);
return newDate;
},

clone(d) {
return new Date(d.getTime());
},
Expand Down Expand Up @@ -123,6 +141,46 @@ export default {
return `${m}/${d}/${y}`;
},

/**
* formatTime, extracted from date-picker/date-picker.
*
* @param date [Date] A Date object.
* @param format [String] One of 'ampm', '24hr', defaults to 'ampm'.
* @param pedantic [Boolean] Check time-picker/time-picker.jsx file.
*
* @return String A string representing the formatted time.
*/
formatTime(date, format = 'ampm', pedantic = false) {
if (!date) return '';
let hours = date.getHours();
let mins = date.getMinutes().toString();

if (format === 'ampm') {
const isAM = hours < 12;
hours = hours % 12;
const additional = isAM ? ' am' : ' pm';
hours = (hours || 12).toString();

if (mins.length < 2 ) mins = `0${mins}`;

if (pedantic) {
// Treat midday/midnight specially http://www.nist.gov/pml/div688/times.cfm
if (hours === '12' && mins === '00') {
return additional === ' pm' ? '12 noon' : '12 midnight';
}
}

return hours + (mins === '00' ? '' : `:${mins}`) + additional;
}

hours = hours.toString();

if (hours.length < 2) hours = `0${hours}`;
if (mins.length < 2) mins = `0${mins}`;

return `${hours}:${mins}`;
},

isEqualDate(d1, d2) {
return d1 && d2 &&
(d1.getFullYear() === d2.getFullYear()) &&
Expand Down
53 changes: 53 additions & 0 deletions test/time-picker/time-picker-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import TextField from 'text-field';
import TimePicker from 'time-picker/time-picker';
import DateTime from 'utils/date-time';
import TestUtils from 'react-addons-test-utils';

describe('TimePicker', () => {

it('has to give value prop precedence over defaultTime', () => {
const initialTime = new Date(1448967059892); // Tue, 01 Dec 2015 10:50:59 GMT
const valueTime = DateTime.addHours(initialTime, 2);

const render = TestUtils.renderIntoDocument(
<TimePicker value={valueTime} format="ampm" locale="en-US"
initialTime={initialTime}
/>
);

const timeTextField = TestUtils.findRenderedComponentWithType(render, TextField);

expect(timeTextField.props.value, DateTime.formatTime(valueTime));
});

it('takes defaulTime prop to set first value when value prop is missing', () => {
const initialTime = new Date(1448967059892); // Tue, 01 Dec 2015 10:50:59 GMT

const render = TestUtils.renderIntoDocument(
<TimePicker format="ampm" locale="en-US"
defaultTime={initialTime}
/>
);

const timeTextField = TestUtils.findRenderedComponentWithType(render, TextField);

expect(timeTextField.props.value, DateTime.formatTime(initialTime));
});

it('shows value prop if defaultTime is missing', () => {
const initialTime = null;
const valueTime = new Date(1448967059892); // Tue, 01 Dec 2015 10:50:59 GM

const render = TestUtils.renderIntoDocument(
<TimePicker value={valueTime} format="ampm" locale="en-US"
defaultTime={initialTime}
/>
);

const timeTextField = TestUtils.findRenderedComponentWithType(render, TextField);

expect(timeTextField.props.value, DateTime.formatTime(valueTime));
});

});