chayns-components
Version:
A set of beautiful React components for developing chayns® applications.
298 lines (295 loc) • 8.78 kB
JavaScript
/**
* @component
*/
import classNames from 'clsx';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { getTimeStringFromMinutes, getTimeStringMinutes } from '../../utils/dateTimeHelper';
import debounce from '../../utils/debounce';
import validateOpeningTimes from '../utils/validateOpeningTimes';
import Day from './Day';
import "./OpeningTimes.css";
import OpeningTimesHint, { HINT_POSITIONS } from './OpeningTimesHint';
import TimeSpan from './TimeSpan';
/**
* An input for opening times.
*/
class OpeningTimes extends Component {
constructor(props) {
super(props);
this.onAdd = this.onAdd.bind(this);
this.onRemove = this.onRemove.bind(this);
this.onChange = this.onChange.bind(this);
this.onDayActivation = this.onDayActivation.bind(this);
this.validateState = this.validateState.bind(this);
this.onValidateStateDebounce = debounce(this.onValidateState.bind(this), 1000);
const {
times
} = this.props;
for (let i = 0; i < times.length; i += 1) {
const current = times[i];
if (current && (current.disabled === null || current.disabled === undefined)) current.disabled = false;
}
for (let i = 0; i < OpeningTimes.weekdays.length; i += 1) {
if (times.findIndex(element => element.weekDay === i) < 0) {
times.push({
weekDay: i,
start: TimeSpan.defaultStart,
end: TimeSpan.defaultEnd,
disabled: true
});
}
}
this.state = {
times,
timesValid: validateOpeningTimes(times)
};
}
onAdd(weekDay) {
const {
onChange
} = this.props;
const newState = {
...this.state
};
const foundTimes = newState.times.filter(time => time.weekDay === weekDay);
let oldEnd = getTimeStringMinutes(foundTimes[0].end);
if (oldEnd === 0) {
oldEnd = 24 * 60;
}
let newStart = oldEnd + 60;
if (oldEnd < 18 * 60) {
newStart = 18 * 60;
}
if (newStart > 24 * 60) {
newStart = Math.max(24 * 60 - 1, oldEnd);
}
let newEnd = newStart + 2 * 60;
if (newEnd > 24 * 60) {
newEnd = 24 * 60;
}
newState.times.push({
weekDay,
start: getTimeStringFromMinutes(newStart),
end: getTimeStringFromMinutes(newEnd),
disabled: false
});
const openingTimesValid = validateOpeningTimes(newState.times);
this.setState(newState);
this.validateState(openingTimesValid);
if (onChange) onChange(newState.times, openingTimesValid);
}
onRemove(day, span) {
const {
onChange
} = this.props;
const newState = {
...this.state
};
const timesOfDay = newState.times.filter(time => time.weekDay === day).filter((time, index) => index !== span);
const otherTimes = newState.times.filter(time => time.weekDay !== day);
newState.times = [...timesOfDay, ...otherTimes];
if (onChange) {
const openingTimesValid = validateOpeningTimes(newState.times);
this.setState(newState);
this.validateState(openingTimesValid);
onChange(newState.times, openingTimesValid);
}
}
onChange(day, index, start, end) {
// eslint-disable-next-line no-nested-ternary
const {
times
} = this.state;
const {
onChange
} = this.props;
const newState = {
...this.state
};
if (onChange) {
const timesOfDay = newState.times.filter(time => time.weekDay === day);
timesOfDay[index].start = start;
timesOfDay[index].end = end;
const openingTimesValid = validateOpeningTimes(newState.times);
this.setState(newState);
this.validateState(openingTimesValid);
onChange(times, openingTimesValid);
}
}
onDayActivation(day, status) {
const {
onChange
} = this.props;
const newState = {
...this.state
};
const timesOfDay = newState.times.filter(time => time.weekDay === day);
const defaultTime = {
weekDay: day,
start: '08:00',
end: '17:00',
disabled: false
};
if (timesOfDay.length === 0) {
timesOfDay.push(defaultTime);
}
if (status) {
if (newState.times.length === newState.times.filter(time => time.disabled).length || newState.times.length === 0) {
if (newState.times.find(time => time.weekDay === day)) {
newState.times = newState.times.map(time => time.weekDay === day ? {
weekDay: time.weekDay,
start: time.start,
end: time.end,
disabled: !time.disabled
} : time);
} else newState.times.push(defaultTime);
}
// else newState.times = this.applyPreviousTimes(day, status);
let foundTimeForDay = false;
for (let i = 0; i < newState.times.length; i += 1) {
if (newState.times[i].weekDay === day) {
if (newState.times[i].disabled === true) {
newState.times[i].disabled = false;
}
foundTimeForDay = true;
}
}
if (!foundTimeForDay) newState.times.push(defaultTime);
} else {
for (let i = 0; i < timesOfDay.length; i += 1) {
const current = timesOfDay[i];
if (current.weekDay === day) current.disabled = true;
}
}
const openingTimesValid = validateOpeningTimes(newState.times);
this.setState(newState);
this.validateState(openingTimesValid);
if (onChange) onChange(newState.times, openingTimesValid);
}
onValidateState() {
const {
times
} = this.state;
const timesValid = validateOpeningTimes(times);
this.setState({
timesValid
});
}
validateState(valid) {
if (valid === void 0) {
valid = false;
}
if (valid) {
this.setState({
timesValid: valid
});
} else {
this.onValidateStateDebounce();
}
}
render() {
const {
className,
style,
forceMobile,
hintPosition,
hintText
} = this.props;
const {
times,
timesValid
} = this.state;
return /*#__PURE__*/React.createElement("div", {
className: classNames(className, 'cc__opening_times', forceMobile && 'cc__opening_times--force-mobile'),
style: style
}, !timesValid && hintPosition === OpeningTimes.hintPositions.TOP && /*#__PURE__*/React.createElement(OpeningTimesHint, {
content: hintText,
position: hintPosition
}), OpeningTimes.weekdays.map(day => /*#__PURE__*/React.createElement(Day
// eslint-disable-next-line react/no-array-index-key
, {
key: day.number,
weekday: day,
times: times.filter(t => t.weekDay === day.number),
onDayActivation: this.onDayActivation,
onAdd: this.onAdd,
onRemove: this.onRemove,
onChange: this.onChange
})), !timesValid && hintPosition === OpeningTimes.hintPositions.BOTTOM && /*#__PURE__*/React.createElement(OpeningTimesHint, {
content: hintText,
position: hintPosition
}));
}
}
OpeningTimes.hintPositions = HINT_POSITIONS;
OpeningTimes.weekdays = [{
name: 'Montag',
number: 1
}, {
name: 'Dienstag',
number: 2
}, {
name: 'Mittwoch',
number: 3
}, {
name: 'Donnerstag',
number: 4
}, {
name: 'Freitag',
number: 5
}, {
name: 'Samstag',
number: 6
}, {
name: 'Sonntag',
number: 0
}];
OpeningTimes.propTypes = {
/**
* An array of the timespans that are opening hours.
*/
times: PropTypes.arrayOf(PropTypes.shape({
weekDay: PropTypes.number.isRequired,
start: PropTypes.string.isRequired,
end: PropTypes.string.isRequired,
disabled: PropTypes.bool
})).isRequired,
/**
* Called after the user has changed the opening times. Receives the
* modified times as its first parameter.
*/
onChange: PropTypes.func,
/**
* A classname string that will be applied to the root container.
*/
className: PropTypes.string,
/**
* A React style object that will be applied to the root container.
*/
style: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
/**
* Wether to force a mobile view.
*/
forceMobile: PropTypes.bool,
/**
* The hint position. Possible values are `OpeningTimes.hintPositions.NONE`,
* `OpeningTimes.hintPositions.TOP` and `OpeningTimes.hintPositions.BOTTOM`.
*/
hintPosition: PropTypes.oneOf([OpeningTimes.hintPositions.NONE, OpeningTimes.hintPositions.TOP, OpeningTimes.hintPositions.BOTTOM]),
/**
* The text to be shown inside of the hint.
*/
hintText: PropTypes.string
};
OpeningTimes.defaultProps = {
onChange: null,
className: null,
style: null,
forceMobile: false,
hintPosition: OpeningTimes.hintPositions.TOP,
hintText: ''
};
OpeningTimes.displayName = 'OpeningTimes';
export default OpeningTimes;
//# sourceMappingURL=OpeningTimes.js.map