chayns-components
Version:
A set of beautiful React components for developing chayns® applications.
520 lines (518 loc) • 16.6 kB
JavaScript
var _window$chayns;
import classNames from 'clsx';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { isServer } from '../../utils/isServer';
import Groups from './content/Groups';
import Navigator from './content/Navigator';
import User from './content/User';
const WEEK_WIDTH = 50;
let focusWeek;
let isDesktop = isServer() ? false : window.innerWidth > 450;
export default class ProgressCalendar extends Component {
static dateInterval(dateStart, dateEnd) {
const startDate = dateStart.getDate() < 10 ? `0${dateStart.getDate()}` : dateStart.getDate();
const startMonth = dateStart.getMonth() + 1 < 10 ? `0${dateStart.getMonth() + 1}` : dateStart.getMonth() + 1;
const endDate = dateEnd.getDate() < 10 ? `0${dateEnd.getDate()}` : dateEnd.getDate();
const endMonth = dateEnd.getMonth() + 1 < 10 ? `0${dateEnd.getMonth() + 1}` : dateEnd.getMonth() + 1;
return `${startDate}.${startMonth} - ${endDate}.${endMonth}.${dateEnd.getFullYear()}`;
}
static getWeek(currentStart) {
let monday;
let sunday;
if (currentStart.getDay() === 0) {
monday = new Date(currentStart.getFullYear(), currentStart.getMonth(), currentStart.getDate() - 6);
sunday = new Date(currentStart.getFullYear(), currentStart.getMonth(), currentStart.getDate(), 23, 59);
} else {
monday = new Date(currentStart.getFullYear(), currentStart.getMonth(), currentStart.getDate() - (currentStart.getDay() - 1));
sunday = new Date(currentStart.getFullYear(), currentStart.getMonth(), currentStart.getDate() + (7 - currentStart.getDay()), 23, 59);
}
return [monday, sunday];
}
static sortEntries(entries) {
if (entries) {
const temp = entries;
for (let j = 1; j < temp.length; j += 1) {
const entry = temp[j];
let i = j - 1;
while (i >= 0 && entry.startTime < temp[i].startTime) {
temp[i + 1] = temp[i];
i -= 1;
}
temp[i + 1] = entry;
}
return temp;
}
return null;
}
static realDay(day) {
if (day.getDay() === 0) {
return 6;
}
return day.getDay() - 1;
}
constructor() {
super();
this.state = {
week: 0,
focusGroup: null
};
this.onNavigateLeft = this.onNavigateLeft.bind(this);
this.onNavigateRight = this.onNavigateRight.bind(this);
this.onClick = this.onClick.bind(this);
this.groupOnClick = this.groupOnClick.bind(this);
this.handleTouchMove = this.handleTouchMove.bind(this);
this.handleTouchStart = this.handleTouchStart.bind(this);
this.handleTouchEnd = this.handleTouchEnd.bind(this);
if (!isServer()) {
window.addEventListener('orientationchange', () => {
isDesktop = window.screen.availWidth > 450;
this.forceUpdate();
});
}
}
componentDidMount() {
this.setState({
contentWidth: this.content.clientWidth
});
this.entries = this.getEntries();
}
shouldComponentUpdate(nextProps) {
const {
focus,
data,
columns,
groups,
startTime,
endTime
} = this.props;
// eslint-disable-next-line guard-for-in,no-restricted-syntax
for (const i in nextProps.data) {
if (nextProps.data.length !== data.length) {
this.entries = this.getEntries(nextProps.data, nextProps.startTime, nextProps.endTime);
return true;
}
if (nextProps.data[i].entries.length !== data[i].entries.length) {
this.entries = this.getEntries(nextProps.data, nextProps.startTime, nextProps.endTime);
return true;
}
}
if (nextProps.columns.length !== columns.length || nextProps.groups.length !== groups.length || nextProps.startTime.getTime() !== startTime.getTime() || nextProps.endTime.getTime() !== endTime.getTime()) {
this.entries = this.getEntries(nextProps.data, nextProps.startTime, nextProps.endTime);
return true;
}
if (nextProps.focus !== focus) {
return true;
}
return true;
}
componentDidUpdate() {
const {
contentWidth
} = this.state;
if (contentWidth !== this.content.clientWidth) {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({
contentWidth: this.content.clientWidth
});
}
}
handleTouchStart(event) {
this.swipeX = event.touches[0].clientX;
}
handleTouchMove(event) {
this.moveSwipeX = event.touches[0].clientX;
}
handleTouchEnd(leftHidden, rightHidden) {
if (this.swipeX && this.moveSwipeX) {
if (this.moveSwipeX >= this.swipeX + 60) {
if (!leftHidden) {
this.onNavigateLeft();
}
this.swipeX = null;
this.moveSwipeX = null;
// this.move=null;
} else if (this.moveSwipeX <= this.swipeX - 60) {
if (!rightHidden) {
this.onNavigateRight();
}
this.swipeX = null;
this.moveSwipeX = null;
}
}
}
onNavigateLeft() {
const {
onNavigateLeft
} = this.props;
const {
week
} = this.state;
onNavigateLeft(this.weeks[focusWeek + (week - 1)]);
this.setState({
week: week - 1
});
}
onNavigateRight() {
const {
onNavigateRight
} = this.props;
const {
week
} = this.state;
const factor = isDesktop ? 2 : 1;
const retval = this.weeks[focusWeek + (week + factor)] ? this.weeks[focusWeek + (week + factor)] : [];
onNavigateRight(retval);
this.setState({
week: week + 1
});
}
onClick(event, entry) {
const {
onClick,
week
} = this.state;
onClick({
event,
selected: entry
});
const dateTime = entry.date.getTime();
const weekEnd = this.weeks[focusWeek + week][1];
let buffer = 0;
if (weekEnd < dateTime) {
buffer = 1;
}
// eslint-disable-next-line no-restricted-syntax
for (const i in this.weeks) {
if (this.weeks[i][0] <= entry.date.getTime() && this.weeks[i][1] >= entry.date.getTime()) {
focusWeek = i - buffer;
break;
}
}
this.setState({
focusGroup: null,
week: 0
});
}
getWeeks(startTime, endTime) {
const {
focus
} = this.props;
const retval = [];
let currentStart = startTime;
while (currentStart.getTime() < endTime.getTime()) {
const [monday, sunday] = ProgressCalendar.getWeek(currentStart);
const mondayTS = monday.getTime();
const sundayTS = sunday.getTime();
if (focus.getTime() >= mondayTS && focus.getTime() <= sundayTS) {
focusWeek = retval.length;
}
retval.push([mondayTS, sundayTS]);
currentStart = new Date(currentStart.getFullYear(), currentStart.getMonth(), currentStart.getDate() + 7);
}
this.weeks = retval;
return retval;
}
getNavigatorDays(weekStart, weekEnd) {
const {
focus,
columns
} = this.props;
const temp = [];
let i = 0;
const date = new Date(weekStart);
const [nextWeekStart, nextWeekEnd] = ProgressCalendar.getWeek(new Date(date.getFullYear(), date.getMonth(), date.getDate() + 7));
const weekDay = ProgressCalendar.realDay(focus);
for (i; i < (isDesktop ? 2 : 1); i += 1) {
const days = [];
let j = 0;
// eslint-disable-next-line no-restricted-syntax
for (j in columns.names) {
if (i === 0) {
days.push({
name: columns.names[j],
date: new Date(weekStart.getFullYear(), weekStart.getMonth(), weekStart.getDate() + parseInt(j, 10))
});
} else if (i === 1) {
days.push({
name: columns.names[j],
date: new Date(nextWeekStart.getFullYear(), nextWeekStart.getMonth(), nextWeekStart.getDate() + parseInt(j, 10))
});
}
}
temp.push(days);
}
if (focus.getTime() >= weekStart && focus.getTime() <= weekEnd) {
temp[0][weekDay].selected = true;
} else if (temp[1] && focus.getTime() >= nextWeekStart.getTime() && focus.getTime() <= nextWeekEnd.getTime()) {
temp[1][weekDay].selected = true;
}
return temp;
}
getEntries(dataParameter, startTimeParameter, endTimeParameter) {
const {
groups,
data: dataProp,
endTime: endTimeProp,
startTime: startTimeProp
} = this.props;
const data = dataParameter || dataProp;
const startTime = startTimeParameter || startTimeProp;
const endTime = endTimeParameter || endTimeProp;
if (!startTime || !endTime) {
return [];
}
const convertedEntries = [];
const weeks = this.getWeeks(startTime, endTime);
let i;
// eslint-disable-next-line
for (i in data) {
const entries = ProgressCalendar.sortEntries(data[i].entries);
const userEntries = [];
let kIndex = 0;
let j;
if (entries) {
// eslint-disable-next-line
for (j in weeks) {
let m = 0;
const weekEntries = [];
for (m; m < 7; m += 1) {
let retval = {};
let k;
// eslint-disable-next-line no-shadow
let startTime = new Date(weeks[j][0] + m * 24 * 60 * 60 * 1000);
// eslint-disable-next-line no-shadow
let endTime = new Date(startTime.getTime() + (23 * 60 * 60 * 1000 + 59 * 60 * 1000));
startTime = startTime.getTime();
endTime = endTime.getTime();
for (k = kIndex; k < entries.length; k += 1) {
/**
* Only possible for entries, which are not longer than a day
*/
if (entries[k].startTime >= startTime && entries[k].endTime <= endTime) {
let l;
if (groups.length > 0) {
let isGrouped = false;
// eslint-disable-next-line no-restricted-syntax
for (l in groups) {
if (entries[k].groupId === groups[l].id) {
retval = entries[k];
retval.color = groups[l].color;
isGrouped = true;
break;
}
}
if (!isGrouped) {
retval = entries[k];
}
} else {
retval = entries[k];
}
retval.date = new Date(startTime);
retval.user = {
id: data[i].id,
name: data[i].name
};
kIndex = k + 1;
} else if (entries[k].endTime > endTime) {
break;
}
}
weekEntries.push(retval.user ? retval : {
date: new Date(startTime),
user: {
id: data[i].id,
name: data[i].name
}
});
}
userEntries.push(weekEntries);
}
}
convertedEntries.push({
entries: userEntries,
userId: data[i].id
});
}
return convertedEntries;
}
groupOnClick(event, group) {
const {
focusGroup
} = this.state;
if (focusGroup === group.id) {
this.setState({
focusGroup: null
});
} else {
this.setState({
focusGroup: group.id
});
}
}
renderUser() {
const {
data
} = this.props;
if (this.content && data) {
return /*#__PURE__*/React.createElement("div", {
className: "calendar__content_groups",
style: {
width: '35%',
paddingRight: '5px'
}
}, data.map(user => /*#__PURE__*/React.createElement("div", {
className: "calendar__user ellipsis",
key: user.id
}, user.name)));
}
return '';
}
renderEntries() {
const {
contentWidth,
week,
focusGroup
} = this.state;
/**
* TODO: PROBLEM WITH REF. REF GOT OLD WIDTH
*/
const {
focus,
groups
} = this.props;
const wrapperWidth = this.weeks ? this.weeks.length * WEEK_WIDTH * (isDesktop ? 1 : 2) : 0;
const weekWidth = this.content ? contentWidth / 2 * (isDesktop ? 1 : 2) : 0;
const content = this.content ? this.entries.map(entries => /*#__PURE__*/React.createElement(User, {
entries: entries.entries,
groups: groups,
key: entries.userId,
onClick: this.onClick,
focus: focus,
groupFocus: focusGroup,
weekWidth: weekWidth
})) : '';
return (
/*#__PURE__*/
// eslint-disable-next-line no-return-assign
React.createElement("div", {
className: "calendar__content_weeks",
ref: ref => {
this.content = ref;
}
}, /*#__PURE__*/React.createElement("div", {
className: "calendar__content_wrapper",
style: {
width: `${wrapperWidth}%`,
transform: `translateX(${-1 * (focusWeek + week) * weekWidth}px)`
}
}, content))
);
}
render() {
const {
week,
focusGroup
} = this.state;
const {
className,
style,
startTime,
endTime,
groups
} = this.props;
let navText = '';
let [weekStart, weekEnd] = [new Date(), new Date()];
let days;
if (this.weeks) {
[weekStart, weekEnd] = this.weeks[focusWeek + week];
weekStart = new Date(weekStart);
weekEnd = new Date(weekEnd);
if (isDesktop) {
const start = weekStart;
const end = new Date(start.getFullYear(), start.getMonth(), start.getDate() + 13);
navText = `${ProgressCalendar.dateInterval(start, end)}`;
} else {
const start = weekStart;
const end = new Date(start.getFullYear(), start.getMonth(), start.getDate() + 6);
navText = `${ProgressCalendar.dateInterval(start, end)}`;
}
days = this.getNavigatorDays(weekStart, weekEnd);
}
const leftHidden = weekStart.getTime() <= startTime;
const rightHidden = isDesktop ? new Date(weekEnd.getFullYear(), weekEnd.getMonth(), weekEnd.getDate() + 7).getTime() >= endTime : weekEnd.getTime() >= endTime;
return /*#__PURE__*/React.createElement("div", {
className: classNames('calendar', className),
style: style
}, /*#__PURE__*/React.createElement("div", {
className: "calendar_header",
onTouchMove: this.handleTouchMove,
onTouchStart: this.handleTouchStart,
onTouchEnd: () => this.handleTouchEnd(leftHidden, rightHidden)
}, /*#__PURE__*/React.createElement(Navigator, {
text: navText,
onClick: {
left: this.onNavigateLeft,
right: this.onNavigateRight,
day: this.onClick
},
hidden: {
left: leftHidden,
right: rightHidden
},
days: days
})), /*#__PURE__*/React.createElement("div", {
className: "calendar__content",
onTouchMove: this.handleTouchMove,
onTouchStart: this.handleTouchStart,
onTouchEnd: () => this.handleTouchEnd(leftHidden, rightHidden)
}, this.renderUser(), this.renderEntries()), /*#__PURE__*/React.createElement(Groups, {
groups: groups,
onClick: this.groupOnClick,
focus: focusGroup
}));
}
}
ProgressCalendar.propTypes = {
data: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number,
name: PropTypes.string,
entries: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number,
groupId: PropTypes.number,
startTime: PropTypes.number,
endTime: PropTypes.number
}))
})),
columns: PropTypes.arrayOf(PropTypes.shape({
names: PropTypes.arrayOf(PropTypes.string),
highlightedColor: PropTypes.string
})),
groups: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.number,
name: PropTypes.string,
color: PropTypes.string
})),
onNavigateLeft: PropTypes.func,
onNavigateRight: PropTypes.func,
focus: PropTypes.objectOf(Date),
startTime: PropTypes.objectOf(Date).isRequired,
endTime: PropTypes.objectOf(Date).isRequired,
className: PropTypes.string,
style: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))
};
ProgressCalendar.defaultProps = {
data: null,
columns: {
names: ['Mo.', 'Di.', 'Mi.', 'Do.', 'Fr.', 'Sa.', 'So.'],
highlightedColor: isServer() ? undefined : (_window$chayns = window.chayns) === null || _window$chayns === void 0 ? void 0 : _window$chayns.env.site.color
},
groups: [],
focus: new Date(),
onNavigateRight: () => {},
onNavigateLeft: () => {},
className: null,
style: null
};
ProgressCalendar.displayName = 'GridCalendar';
//# sourceMappingURL=GridCalendar.js.map