2019-09-10 11:28:56 +00:00
|
|
|
import React, { Component } from "react";
|
|
|
|
import PropTypes from "prop-types";
|
|
|
|
import styled from "styled-components";
|
|
|
|
import InputBlock from "../input-block";
|
|
|
|
import DropDown from "../drop-down";
|
2019-09-18 07:34:59 +00:00
|
|
|
import Calendar from "../calendar";
|
2019-09-11 06:28:46 +00:00
|
|
|
import moment from "moment";
|
2019-09-10 11:28:56 +00:00
|
|
|
import { handleAnyClick } from "../../utils/event";
|
|
|
|
import isEmpty from "lodash/isEmpty";
|
2019-10-02 08:07:39 +00:00
|
|
|
import Aside from "../layout/sub-components/aside";
|
2019-09-02 06:45:45 +00:00
|
|
|
|
2019-09-11 10:46:21 +00:00
|
|
|
const DateInputStyle = styled.div`
|
|
|
|
max-width: 110px;
|
|
|
|
width: 110px;
|
|
|
|
`;
|
2019-09-03 08:41:54 +00:00
|
|
|
|
2019-09-11 06:28:46 +00:00
|
|
|
const DropDownStyle = styled.div`
|
|
|
|
position: relative;
|
|
|
|
`;
|
|
|
|
|
2019-09-02 06:45:45 +00:00
|
|
|
class DatePicker extends Component {
|
2019-09-10 11:28:56 +00:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2019-09-02 12:46:37 +00:00
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
moment.locale(props.locale);
|
|
|
|
this.ref = React.createRef();
|
2019-09-03 08:41:54 +00:00
|
|
|
|
2019-09-20 06:00:11 +00:00
|
|
|
const { isOpen, selectedDate, hasError, minDate, maxDate } = this.props;
|
2019-09-11 10:46:21 +00:00
|
|
|
|
|
|
|
if (isOpen) {
|
2019-09-10 11:28:56 +00:00
|
|
|
handleAnyClick(true, this.handleClick);
|
2019-09-02 06:45:45 +00:00
|
|
|
}
|
|
|
|
|
2019-09-20 06:00:11 +00:00
|
|
|
let newState = {
|
2019-09-10 11:28:56 +00:00
|
|
|
isOpen,
|
|
|
|
selectedDate: moment(selectedDate).toDate(),
|
|
|
|
value: moment(selectedDate).format("L"),
|
2019-09-11 06:28:46 +00:00
|
|
|
mask: this.getMask,
|
2019-09-11 10:46:21 +00:00
|
|
|
hasError
|
2019-09-10 11:28:56 +00:00
|
|
|
};
|
2019-09-20 06:00:11 +00:00
|
|
|
|
|
|
|
if (this.isValidDate(selectedDate, maxDate, minDate, hasError)) {
|
|
|
|
newState = Object.assign({}, newState, {
|
|
|
|
hasError: true,
|
|
|
|
isOpen: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
this.state = newState;
|
2019-09-10 11:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
handleClick = e => {
|
|
|
|
this.state.isOpen &&
|
|
|
|
!this.ref.current.contains(e.target) &&
|
2019-09-11 10:46:21 +00:00
|
|
|
this.onClick(false);
|
2019-09-10 11:28:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
handleChange = e => {
|
2019-09-17 07:41:35 +00:00
|
|
|
const { value } = this.state;
|
2019-09-11 10:46:21 +00:00
|
|
|
|
|
|
|
const targetValue = e.target.value;
|
|
|
|
if (value != targetValue) {
|
|
|
|
let newState = { value: targetValue };
|
2019-09-10 11:28:56 +00:00
|
|
|
const format = moment.localeData().longDateFormat("L");
|
2019-09-11 10:46:21 +00:00
|
|
|
const momentDate = moment(targetValue, format);
|
2019-09-10 11:28:56 +00:00
|
|
|
const date = momentDate.toDate();
|
|
|
|
|
2019-09-10 13:00:34 +00:00
|
|
|
if (
|
|
|
|
!isNaN(date) &&
|
2019-09-18 10:23:03 +00:00
|
|
|
this.compareDate(date) &&
|
2019-09-11 10:46:21 +00:00
|
|
|
targetValue.indexOf("_") === -1
|
2019-09-10 13:00:34 +00:00
|
|
|
) {
|
|
|
|
//console.log("Mask complete");
|
2019-09-10 11:28:56 +00:00
|
|
|
this.props.onChange && this.props.onChange(date);
|
|
|
|
newState = Object.assign({}, newState, {
|
2019-09-11 06:28:46 +00:00
|
|
|
selectedDate: date,
|
|
|
|
hasError: false
|
|
|
|
});
|
2019-09-11 10:46:21 +00:00
|
|
|
} else if (targetValue.indexOf("_") !== -1 && targetValue.length !== 0) {
|
|
|
|
//hasWarning
|
2019-09-11 06:28:46 +00:00
|
|
|
newState = Object.assign({}, newState, {
|
|
|
|
hasError: true
|
2019-09-10 11:28:56 +00:00
|
|
|
});
|
2019-09-11 10:46:21 +00:00
|
|
|
} else {
|
|
|
|
newState = Object.assign({}, newState, {
|
|
|
|
hasError: true,
|
|
|
|
isOpen: false
|
|
|
|
});
|
2019-09-10 11:28:56 +00:00
|
|
|
}
|
|
|
|
this.setState(newState);
|
2019-09-02 12:46:37 +00:00
|
|
|
}
|
2019-09-10 11:28:56 +00:00
|
|
|
};
|
2019-09-02 12:46:37 +00:00
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
onChange = value => {
|
2019-09-11 10:46:21 +00:00
|
|
|
this.onClick(!this.state.isOpen);
|
2019-09-10 11:28:56 +00:00
|
|
|
const formatValue = moment(value).format("L");
|
|
|
|
this.props.onChange && this.props.onChange(value);
|
|
|
|
this.setState({ selectedDate: value, value: formatValue });
|
|
|
|
};
|
2019-09-02 06:45:45 +00:00
|
|
|
|
2019-09-11 10:46:21 +00:00
|
|
|
onClick = isOpen => {
|
|
|
|
if (!this.state.hasError) {
|
|
|
|
this.setState({ isOpen });
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-09-18 10:23:03 +00:00
|
|
|
compareDate = date => {
|
2019-09-10 11:28:56 +00:00
|
|
|
const { minDate, maxDate } = this.props;
|
2019-09-18 07:34:59 +00:00
|
|
|
if (date < minDate || date > maxDate) {
|
2019-09-10 11:28:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
getMask = () => {
|
|
|
|
let symbol = ".";
|
2019-09-10 13:00:34 +00:00
|
|
|
const localeMask = moment.localeData().longDateFormat("L");
|
|
|
|
const { locale } = this.props;
|
2019-09-10 11:28:56 +00:00
|
|
|
|
|
|
|
if (localeMask.indexOf("/") + 1) {
|
|
|
|
symbol = "/";
|
|
|
|
} else if (localeMask.indexOf(".") + 1) {
|
|
|
|
symbol = ".";
|
|
|
|
} else if (localeMask.indexOf("-") + 1) {
|
|
|
|
symbol = "-";
|
|
|
|
}
|
2019-09-06 10:52:04 +00:00
|
|
|
|
2019-09-10 13:00:34 +00:00
|
|
|
const mask = [
|
|
|
|
/\d/,
|
|
|
|
/\d/,
|
|
|
|
symbol,
|
|
|
|
/\d/,
|
|
|
|
/\d/,
|
|
|
|
symbol,
|
|
|
|
/\d/,
|
|
|
|
/\d/,
|
|
|
|
/\d/,
|
|
|
|
/\d/
|
|
|
|
];
|
2019-09-06 10:52:04 +00:00
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
if (localeMask[0] === "Y") {
|
2019-09-10 13:00:34 +00:00
|
|
|
mask.reverse();
|
2019-09-02 11:29:56 +00:00
|
|
|
}
|
2019-09-10 13:00:34 +00:00
|
|
|
if (locale === "ko" || locale === "lv") {
|
2019-09-10 11:28:56 +00:00
|
|
|
mask.push(symbol);
|
2019-09-02 11:29:56 +00:00
|
|
|
}
|
2019-09-10 11:28:56 +00:00
|
|
|
return mask;
|
|
|
|
};
|
|
|
|
|
2019-09-12 11:28:48 +00:00
|
|
|
compareDates = (date1, date2) => {
|
|
|
|
return moment(date1)
|
|
|
|
.startOf("day")
|
|
|
|
.diff(moment(date2).startOf("day"), "days");
|
|
|
|
};
|
|
|
|
|
2019-09-20 06:00:11 +00:00
|
|
|
isValidDate = (selectedDate, maxDate, minDate, hasError) => {
|
|
|
|
if (
|
|
|
|
(this.compareDates(selectedDate, maxDate) > 0 ||
|
|
|
|
this.compareDates(selectedDate, minDate) < 0) &&
|
|
|
|
!hasError
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
componentWillUnmount() {
|
|
|
|
handleAnyClick(false, this.handleClick);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate(prevProps, prevState) {
|
2019-09-11 06:28:46 +00:00
|
|
|
const { locale, isOpen, selectedDate, maxDate, minDate } = this.props;
|
2019-09-11 10:46:21 +00:00
|
|
|
const { hasError, value } = this.state;
|
2019-09-10 11:28:56 +00:00
|
|
|
let newState = {};
|
|
|
|
|
|
|
|
if (locale !== prevProps.locale) {
|
|
|
|
moment.locale(locale);
|
|
|
|
newState = {
|
|
|
|
mask: this.getMask(),
|
|
|
|
value: moment(selectedDate).format("L")
|
|
|
|
};
|
2019-09-02 12:46:37 +00:00
|
|
|
}
|
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
if (selectedDate !== prevProps.selectedDate) {
|
|
|
|
newState = Object.assign({}, newState, {
|
2019-09-12 11:28:48 +00:00
|
|
|
selectedDate,
|
|
|
|
value: moment(selectedDate).format("L")
|
2019-09-10 11:28:56 +00:00
|
|
|
});
|
2019-09-02 06:45:45 +00:00
|
|
|
}
|
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
if (this.state.isOpen !== prevState.isOpen) {
|
|
|
|
handleAnyClick(this.state.isOpen, this.handleClick);
|
2019-09-02 06:45:45 +00:00
|
|
|
}
|
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
if (isOpen !== prevProps.isOpen) {
|
|
|
|
newState = Object.assign({}, newState, {
|
|
|
|
isOpen
|
|
|
|
});
|
|
|
|
}
|
2019-09-06 08:54:19 +00:00
|
|
|
|
2019-09-11 10:46:21 +00:00
|
|
|
if (this.props.hasError !== prevProps.hasError) {
|
|
|
|
newState = Object.assign({}, newState, {
|
|
|
|
hasError: this.props.hasError,
|
|
|
|
isOpen: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const date = new Date(value);
|
|
|
|
if (
|
2019-09-12 11:28:48 +00:00
|
|
|
this.compareDates(selectedDate, maxDate) <= 0 &&
|
|
|
|
this.compareDates(selectedDate, minDate) >= 0 &&
|
2019-09-11 10:46:21 +00:00
|
|
|
hasError &&
|
2019-09-12 11:28:48 +00:00
|
|
|
this.compareDates(date, maxDate) <= 0 &&
|
|
|
|
this.compareDates(date, minDate) >= 0 &&
|
2019-09-11 10:46:21 +00:00
|
|
|
!this.props.hasError
|
|
|
|
) {
|
|
|
|
newState = Object.assign({}, newState, {
|
2019-09-12 11:28:48 +00:00
|
|
|
hasError: false,
|
|
|
|
selectedDate,
|
|
|
|
value: moment(selectedDate).format("L")
|
2019-09-11 10:46:21 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-09-20 06:00:11 +00:00
|
|
|
if (this.isValidDate(selectedDate, maxDate, minDate, hasError)) {
|
2019-09-11 10:46:21 +00:00
|
|
|
newState = Object.assign({}, newState, {
|
|
|
|
hasError: true,
|
|
|
|
isOpen: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
if (!isEmpty(newState)) {
|
|
|
|
this.setState(newState);
|
2019-09-02 06:45:45 +00:00
|
|
|
}
|
2019-09-10 11:28:56 +00:00
|
|
|
}
|
|
|
|
|
2019-10-02 08:07:39 +00:00
|
|
|
renderBody = () => {
|
2019-09-10 11:28:56 +00:00
|
|
|
const {
|
|
|
|
isDisabled,
|
|
|
|
minDate,
|
|
|
|
maxDate,
|
|
|
|
locale,
|
2019-10-02 08:07:39 +00:00
|
|
|
themeColor,
|
|
|
|
calendarSize
|
2019-09-10 11:28:56 +00:00
|
|
|
} = this.props;
|
2019-10-02 08:07:39 +00:00
|
|
|
const { selectedDate } = this.state;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Calendar
|
|
|
|
locale={locale}
|
|
|
|
themeColor={themeColor}
|
|
|
|
minDate={minDate}
|
|
|
|
maxDate={maxDate}
|
|
|
|
isDisabled={isDisabled}
|
|
|
|
openToDate={selectedDate}
|
|
|
|
selectedDate={selectedDate}
|
|
|
|
onChange={this.onChange}
|
|
|
|
size={calendarSize}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
2019-09-10 11:28:56 +00:00
|
|
|
|
2019-10-02 08:07:39 +00:00
|
|
|
render() {
|
|
|
|
const { isDisabled, isReadOnly, displayType } = this.props;
|
|
|
|
const { value, isOpen, mask, hasError } = this.state;
|
2019-09-10 11:28:56 +00:00
|
|
|
|
|
|
|
return (
|
|
|
|
<DateInputStyle ref={this.ref}>
|
|
|
|
<InputBlock
|
2019-09-11 10:46:21 +00:00
|
|
|
scale={true}
|
2019-09-10 11:28:56 +00:00
|
|
|
isDisabled={isDisabled}
|
|
|
|
isReadOnly={isReadOnly}
|
|
|
|
hasError={hasError}
|
2019-09-11 10:46:21 +00:00
|
|
|
onFocus={this.onClick.bind(this, true)}
|
2019-09-10 11:28:56 +00:00
|
|
|
iconName={"CalendarIcon"}
|
2019-09-11 10:46:21 +00:00
|
|
|
onIconClick={this.onClick.bind(this, !isOpen)}
|
2019-09-10 11:28:56 +00:00
|
|
|
value={value}
|
|
|
|
onChange={this.handleChange}
|
|
|
|
mask={mask}
|
|
|
|
keepCharPositions={true}
|
|
|
|
//guide={true}
|
|
|
|
//showMask={true}
|
|
|
|
/>
|
2019-10-02 10:40:14 +00:00
|
|
|
{isOpen ? (
|
|
|
|
displayType === "dropdown" ? (
|
|
|
|
<DropDownStyle>
|
|
|
|
<DropDown opened={isOpen}>{this.renderBody()}</DropDown>
|
|
|
|
</DropDownStyle>
|
|
|
|
) : (
|
|
|
|
<Aside visible={isOpen} scale={false}>
|
|
|
|
{this.renderBody()}
|
|
|
|
</Aside>
|
|
|
|
)
|
2019-10-02 10:19:38 +00:00
|
|
|
) : null}
|
2019-09-10 11:28:56 +00:00
|
|
|
</DateInputStyle>
|
|
|
|
);
|
|
|
|
}
|
2019-09-02 06:45:45 +00:00
|
|
|
}
|
|
|
|
|
2019-09-02 11:29:56 +00:00
|
|
|
DatePicker.propTypes = {
|
2019-09-10 11:28:56 +00:00
|
|
|
onChange: PropTypes.func,
|
|
|
|
themeColor: PropTypes.string,
|
|
|
|
selectedDate: PropTypes.instanceOf(Date),
|
|
|
|
openToDate: PropTypes.instanceOf(Date),
|
|
|
|
minDate: PropTypes.instanceOf(Date),
|
|
|
|
maxDate: PropTypes.instanceOf(Date),
|
|
|
|
locale: PropTypes.string,
|
|
|
|
isDisabled: PropTypes.bool,
|
|
|
|
isReadOnly: PropTypes.bool,
|
|
|
|
hasError: PropTypes.bool,
|
|
|
|
hasWarning: PropTypes.bool,
|
2019-10-02 08:07:39 +00:00
|
|
|
isOpen: PropTypes.bool,
|
|
|
|
displayType: PropTypes.oneOf(["dropdown", "aside"]),
|
|
|
|
calendarSize: PropTypes.oneOf(["base", "big"])
|
2019-09-10 11:28:56 +00:00
|
|
|
};
|
2019-09-02 11:29:56 +00:00
|
|
|
|
|
|
|
DatePicker.defaultProps = {
|
2019-09-10 11:28:56 +00:00
|
|
|
minDate: new Date("1970/01/01"),
|
2019-09-17 07:41:35 +00:00
|
|
|
maxDate: new Date(new Date().getFullYear() + 1, 1, 1),
|
2019-10-02 10:40:14 +00:00
|
|
|
selectedDate: moment(new Date()).toDate(),
|
|
|
|
displayType: "dropdown"
|
2019-09-10 11:28:56 +00:00
|
|
|
};
|
2019-09-02 11:29:56 +00:00
|
|
|
|
2019-09-10 11:28:56 +00:00
|
|
|
export default DatePicker;
|