setup on-call schedule calendar view

This commit is contained in:
deityhub
2021-08-24 17:40:31 +01:00
parent 0aba3db766
commit 4bb4faafd4
5 changed files with 395 additions and 0 deletions

View File

@@ -46,6 +46,7 @@
"react": "^17.0.2",
"react-ace": "^9.4.1",
"react-beautiful-dnd": "^13.1.0",
"react-big-calendar": "^0.35.0",
"react-breadcrumbs-dynamic": "^1.2.1",
"react-click-outside": "github:tj/react-click-outside",
"react-color": "^2.19.3",
@@ -2736,6 +2737,26 @@
"node": ">= 8"
}
},
"node_modules/@popperjs/core": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.3.tgz",
"integrity": "sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@restart/hooks": {
"version": "0.3.27",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.27.tgz",
"integrity": "sha512-s984xV/EapUIfkjlf8wz9weP2O9TNKR96C68FfMEy2bE69+H4cNv3RD4Mf97lW7Htt7PjZrYTjSC8f3SB9VCXw==",
"dependencies": {
"dequal": "^2.0.2"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@rollup/plugin-babel": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz",
@@ -3333,6 +3354,11 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
},
"node_modules/@types/warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
},
"node_modules/@types/webpack": {
"version": "4.41.30",
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.30.tgz",
@@ -7924,6 +7950,14 @@
"integrity": "sha1-UYZnt2kUYKXn4KNBvnbrfOgJAYQ=",
"dev": true
},
"node_modules/dequal": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
"engines": {
"node": ">=6"
}
},
"node_modules/des.js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
@@ -20807,6 +20841,47 @@
"react-dom": "^16.8.5 || ^17.0.0"
}
},
"node_modules/react-big-calendar": {
"version": "0.35.0",
"resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.35.0.tgz",
"integrity": "sha512-2jjPhfKRM6ka3pdzdqqYUPLEgoeyyP5ICPhgUZBitozM3nskz7B3tNaLpqNgTWCaAc7KJbe2TJiqCcCbHiZtRA==",
"dependencies": {
"@babel/runtime": "^7.1.5",
"clsx": "^1.0.4",
"date-arithmetic": "^4.1.0",
"dom-helpers": "^5.1.0",
"invariant": "^2.2.4",
"lodash": "^4.17.11",
"lodash-es": "^4.17.11",
"memoize-one": "^5.1.1",
"prop-types": "^15.7.2",
"react-overlays": "^4.1.1",
"uncontrollable": "^7.0.0"
},
"peerDependencies": {
"react": "^16.6.1 || ^17",
"react-dom": "^16.6.1 || ^17"
}
},
"node_modules/react-big-calendar/node_modules/csstype": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
},
"node_modules/react-big-calendar/node_modules/date-arithmetic": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
},
"node_modules/react-big-calendar/node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/react-breadcrumbs-dynamic": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/react-breadcrumbs-dynamic/-/react-breadcrumbs-dynamic-1.2.1.tgz",
@@ -21200,6 +21275,47 @@
"react": ">=16"
}
},
"node_modules/react-overlays": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz",
"integrity": "sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==",
"dependencies": {
"@babel/runtime": "^7.12.1",
"@popperjs/core": "^2.5.3",
"@restart/hooks": "^0.3.25",
"@types/warning": "^3.0.0",
"dom-helpers": "^5.2.0",
"prop-types": "^15.7.2",
"uncontrollable": "^7.0.0",
"warning": "^4.0.3"
},
"peerDependencies": {
"react": ">=16.3.0",
"react-dom": ">=16.3.0"
}
},
"node_modules/react-overlays/node_modules/csstype": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
},
"node_modules/react-overlays/node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/react-overlays/node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/react-phone-input-2": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/react-phone-input-2/-/react-phone-input-2-2.14.0.tgz",
@@ -29753,6 +29869,19 @@
}
}
},
"@popperjs/core": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.3.tgz",
"integrity": "sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ=="
},
"@restart/hooks": {
"version": "0.3.27",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.27.tgz",
"integrity": "sha512-s984xV/EapUIfkjlf8wz9weP2O9TNKR96C68FfMEy2bE69+H4cNv3RD4Mf97lW7Htt7PjZrYTjSC8f3SB9VCXw==",
"requires": {
"dequal": "^2.0.2"
}
},
"@rollup/plugin-babel": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz",
@@ -30223,6 +30352,11 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
},
"@types/warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
},
"@types/webpack": {
"version": "4.41.30",
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.30.tgz",
@@ -33871,6 +34005,11 @@
"integrity": "sha1-UYZnt2kUYKXn4KNBvnbrfOgJAYQ=",
"dev": true
},
"dequal": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug=="
},
"des.js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
@@ -43796,6 +43935,45 @@
"use-memo-one": "^1.1.1"
}
},
"react-big-calendar": {
"version": "0.35.0",
"resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.35.0.tgz",
"integrity": "sha512-2jjPhfKRM6ka3pdzdqqYUPLEgoeyyP5ICPhgUZBitozM3nskz7B3tNaLpqNgTWCaAc7KJbe2TJiqCcCbHiZtRA==",
"requires": {
"@babel/runtime": "^7.1.5",
"clsx": "^1.0.4",
"date-arithmetic": "^4.1.0",
"dom-helpers": "^5.1.0",
"invariant": "^2.2.4",
"lodash": "^4.17.11",
"lodash-es": "^4.17.11",
"memoize-one": "^5.1.1",
"prop-types": "^15.7.2",
"react-overlays": "^4.1.1",
"uncontrollable": "^7.0.0"
},
"dependencies": {
"csstype": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
},
"date-arithmetic": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
},
"dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"requires": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
}
}
},
"react-breadcrumbs-dynamic": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/react-breadcrumbs-dynamic/-/react-breadcrumbs-dynamic-1.2.1.tgz",
@@ -44093,6 +44271,45 @@
"vfile": "^4.0.0"
}
},
"react-overlays": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz",
"integrity": "sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==",
"requires": {
"@babel/runtime": "^7.12.1",
"@popperjs/core": "^2.5.3",
"@restart/hooks": "^0.3.25",
"@types/warning": "^3.0.0",
"dom-helpers": "^5.2.0",
"prop-types": "^15.7.2",
"uncontrollable": "^7.0.0",
"warning": "^4.0.3"
},
"dependencies": {
"csstype": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
},
"dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"requires": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"requires": {
"loose-envify": "^1.0.0"
}
}
}
},
"react-phone-input-2": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/react-phone-input-2/-/react-phone-input-2-2.14.0.tgz",

View File

@@ -40,6 +40,7 @@
"react": "^17.0.2",
"react-ace": "^9.4.1",
"react-beautiful-dnd": "^13.1.0",
"react-big-calendar": "^0.35.0",
"react-breadcrumbs-dynamic": "^1.2.1",
"react-click-outside": "github:tj/react-click-outside",
"react-color": "^2.19.3",

View File

@@ -16,6 +16,7 @@ import { setUserId, setUserProperties, identify, logEvent } from './analytics';
import { SHOULD_LOG_ANALYTICS } from './config';
import Dashboard from './components/Dashboard';
import { LoadingState } from './components/basic/Loader';
import 'react-big-calendar/lib/sass/styles.scss';
if (!isServer) {
history.listen(location => {

View File

@@ -0,0 +1,172 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Calendar, momentLocalizer } from 'react-big-calendar';
import moment from 'moment';
function ScheduleCalender({ escalations }) {
const [dayOffset, setDayOffset] = useState(47);
const [defaultDate, setDefaultDate] = useState(new Date());
const teamSchedules = [];
escalations.forEach(escalation => {
if (escalation.activeTeam) {
if (escalation.activeTeam.teamMembers.length) {
teamSchedules.push(...escalation.activeTeam.teamMembers);
}
}
if (escalation.nextActiveTeam) {
if (escalation.nextActiveTeam.teamMembers.length) {
teamSchedules.push(...escalation.nextActiveTeam.teamMembers);
}
}
});
const extendedSchedule = [];
teamSchedules.forEach(schedule => {
for (let i = 0; i <= dayOffset; i++) {
const currentStart = new Date(schedule.startTime);
const currentEnd = new Date(schedule.endTime);
const scheduleData = {
title: `${schedule.user?.name ||
schedule.user
?.email} is on-call schedule during this period`,
start: new Date(
currentStart.setDate(currentStart.getDate() + i)
),
end: new Date(currentEnd.setDate(currentEnd.getDate() + i)),
id: schedule._id + i,
};
extendedSchedule.push(scheduleData);
}
});
// Setup the localizer by providing the moment (or globalize) Object
// to the correct localizer.
const localizer = momentLocalizer(moment); // or globalizeLocalizer
const handleNavigate = (date, view, action) => {
setDefaultDate(date);
if (view === 'month') {
setDayOffset(prevState => {
if (action && action === 'PREV') {
return prevState - 47;
}
if (action && action === 'TODAY') {
return 47;
}
return prevState + 47;
});
}
if (view === 'week') {
setDayOffset(prevState => {
if (action && action === 'PREV') {
return prevState - 7;
}
if (action && action === 'TODAY') {
return 7;
}
return prevState + 7;
});
}
if (view === 'day') {
setDayOffset(prevState => {
if (action && action === 'PREV') {
return prevState - 1;
}
if (action && action === 'TODAY') {
return 1;
}
return prevState + 1;
});
}
if (view === 'agenda') {
setDayOffset(prevState => {
if (action && action === 'PREV') {
return prevState - 30;
}
if (action && action === 'TODAY') {
return 30;
}
return prevState + 30;
});
}
};
const handleView = view => {
setDefaultDate(new Date());
if (view === 'month') setDayOffset(47);
if (view === 'week') setDayOffset(7);
if (view === 'day') setDayOffset(1);
if (view === 'agenda') setDayOffset(30);
};
return (
<div className="Box-root Margin-bottom--12">
<div className="bs-ContentSection Card-root Card-shadow--medium">
<div className="Box-root">
<div className="ContentHeader Box-root Box-background--white Box-divider--surface-bottom-1 Flex-flex Flex-direction--column Padding-horizontal--20 Padding-vertical--16">
<div className="Box-root Flex-flex Flex-direction--row Flex-justifyContent--spaceBetween">
<div className="ContentHeader-center Box-root Flex-flex Flex-direction--column Flex-justifyContent--center">
<span className="Text-color--inherit Text-display--inline Text-fontSize--16 Text-fontWeight--medium Text-lineHeight--24 Text-typeface--base Text-wrap--wrap">
<span> Call Schedule Calender</span>
</span>
<p>
Calender to show team member that is on-call
</p>
</div>
<div className="ContentHeader-end Box-root Flex-flex Flex-alignItems--center Margin-left--16">
<div className="Box-root"></div>
</div>
</div>
</div>
<div className="bs-ContentSection-content Box-root">
<div
className="bs-ContentSection-content Box-root Box-background--offset Box-divider--surface-bottom-1 Padding-horizontal--8 Padding-vertical--2"
style={{
backgroundColor: '#f7f7f7',
}}
>
<div>
<Calendar
date={defaultDate}
getNow={() => new Date()}
localizer={localizer}
events={extendedSchedule}
startAccessor="start"
endAccessor="end"
style={{ height: 500 }}
views={['month', 'week', 'day', 'agenda']}
showMultiDayTimes={true}
onView={view => handleView(view)}
onNavigate={(date, view, action) =>
handleNavigate(date, view, action)
}
/>
</div>
</div>
</div>
<div className="bs-ContentSection-footer bs-ContentSection-content Box-root Box-background--white Flex-flex Flex-alignItems--center Flex-justifyContent--spaceBetween Padding-horizontal--20 Padding-vertical--12">
<div className="bs-Tail-copy">
<div
className="Box-root Flex-flex Flex-alignItems--stretch Flex-direction--row Flex-justifyContent--flexStart"
style={{ marginTop: '10px' }}
></div>
</div>
<div></div>
</div>
</div>
</div>
</div>
);
}
ScheduleCalender.displayName = 'ScheduleCalender';
ScheduleCalender.propTypes = {
escalations: PropTypes.array,
};
export default ScheduleCalender;

View File

@@ -14,6 +14,7 @@ import { getEscalation } from '../actions/schedule';
import { teamLoading } from '../actions/team';
import BreadCrumbItem from '../components/breadCrumb/BreadCrumbItem';
import getParentRoute from '../utils/getParentRoute';
import ScheduleCalender from '../components/schedule/ScheduleCalender';
class Schedule extends Component {
constructor(props) {
super(props);
@@ -106,6 +107,9 @@ class Schedule extends Component {
<span>
<div>
<div>
<ScheduleCalender
escalations={escalations}
/>
<RenameScheduleBox />
<MonitorBox
schedule={schedule}