add rotation form positionning

This commit is contained in:
Maxim 2022-08-23 16:36:20 +03:00
parent 9858054841
commit 751ee980e0
8 changed files with 97 additions and 22 deletions

View file

@ -3,6 +3,8 @@ import React, { FC, PropsWithChildren } from 'react';
import cn from 'classnames/bind';
import ReactModal from 'react-modal';
ReactModal.setAppElement('#reactRoot');
import styles from './Modal.module.css';
export interface ModalProps {

View file

@ -62,8 +62,9 @@
.empty {
height: 28px;
background: #5f505633;
/* background: #5f505633;
border: 1px dashed #5c474d;
color: rgba(209, 14, 92, 0.5);
color: rgba(209, 14, 92, 0.5); */
margin: 0 2px;
}

View file

@ -2,6 +2,11 @@
display: block;
}
.draggable {
top: 0;
transition: transform 500ms ease;
}
.header {
width: 100%;
display: flex;

View file

@ -31,6 +31,7 @@ import { makeRequest } from 'network';
import { getDateTime, getUTCString } from 'pages/schedule/Schedule.helpers';
import { SelectOption } from 'state/types';
import { useStore } from 'state/useStore';
import { getCoords, waitForElement } from 'utils/DOM';
import { useDebouncedCallback } from 'utils/hooks';
import { RotationCreateData } from './RotationForm.types';
@ -57,8 +58,6 @@ const RotationForm: FC<RotationFormProps> = observer((props) => {
const { onHide, onCreate, startMoment, currentTimezone, scheduleId, onUpdate, onDelete, layerPriority, shiftId } =
props;
const [isOpen, setIsOpen] = useState<boolean>(true);
const [repeatEveryValue, setRepeatEveryValue] = useState<number>(1);
const [repeatEveryPeriod, setRepeatEveryPeriod] = useState<number>(0);
const [selectedDays, setSelectedDays] = useState<string[]>([]);
@ -70,6 +69,24 @@ const RotationForm: FC<RotationFormProps> = observer((props) => {
dateTime(startOfDay.add(1, 'month').format('YYYY-MM-DD HH:mm:ss'))
);
const store = useStore();
const shift = store.scheduleStore.shifts[shiftId];
const [offsetTop, setOffsetTop] = useState<number>(0);
useEffect(() => {
waitForElement(`#layer${shiftId === 'new' ? layerPriority : shift?.priority_level}`).then((elm) => {
const modal = document.querySelector(`.${cx('draggable')}`) as HTMLDivElement;
const coords = getCoords(elm);
// setOffsetTop(Math.max(coords.top + elm.offsetHeight, 0));
setOffsetTop(coords.top - modal?.offsetHeight - 70);
});
}, []);
const [userGroups, setUserGroups] = useState([[]]);
const getUser = (pk: User['pk']) => {
@ -85,10 +102,6 @@ const RotationForm: FC<RotationFormProps> = observer((props) => {
});
}, []);
const store = useStore();
const shift = store.scheduleStore.shifts[shiftId];
useEffect(() => {
if (shiftId !== 'new') {
store.scheduleStore.updateOncallShift(shiftId);
@ -137,7 +150,7 @@ const RotationForm: FC<RotationFormProps> = observer((props) => {
const handleChange = useDebouncedCallback(() => {
store.scheduleStore.updateRotationPreview(scheduleId, shiftId, getFromString(startMoment), false, params);
}, 1000);
}, 500);
useEffect(handleChange, [params]);
@ -172,11 +185,11 @@ const RotationForm: FC<RotationFormProps> = observer((props) => {
return (
<Modal
isOpen={isOpen}
isOpen
width="430px"
onDismiss={onHide}
contentElement={(props, children) => (
<Draggable handle=".drag-handler" positionOffset={{ x: 0, y: 0 }}>
<Draggable handle=".drag-handler" defaultClassName={cx('draggable')} positionOffset={{ x: 0, y: offsetTop }}>
<div {...props}>{children}</div>
</Draggable>
)}

View file

@ -27,6 +27,7 @@ import { Timezone } from 'models/timezone/timezone.types';
import { User } from 'models/user/user.types';
import { getDateTime, getUTCString } from 'pages/schedule/Schedule.helpers';
import { useStore } from 'state/useStore';
import { getCoords, waitForElement } from 'utils/DOM';
import { useDebouncedCallback } from 'utils/hooks';
import { RotationCreateData } from './RotationForm.types';
@ -53,6 +54,18 @@ const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
const store = useStore();
const [offsetTop, setOffsetTop] = useState<number>(0);
useEffect(() => {
waitForElement('#overrides-list').then((elm) => {
const modal = document.querySelector(`.${cx('draggable')}`) as HTMLDivElement;
const coords = getCoords(elm);
setOffsetTop(coords.top - modal?.offsetHeight - 10);
});
}, []);
const [shiftStart, setShiftStart] = useState<DateTime>(dateTime(startOfDay.format('YYYY-MM-DD HH:mm:ss')));
const [shiftEnd, setShiftEnd] = useState<DateTime>(
dateTime(startOfDay.add(12, 'hours').format('YYYY-MM-DD HH:mm:ss'))
@ -117,16 +130,17 @@ const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
const handleChange = useDebouncedCallback(() => {
store.scheduleStore.updateRotationPreview(scheduleId, shiftId, getFromString(startMoment), true, params);
}, 1000);
}, 500);
useEffect(handleChange, [params]);
return (
<Modal
isOpen
width="430px"
onDismiss={onHide}
contentElement={(props, children) => (
<Draggable handle=".drag-handler" positionOffset={{ x: 0, y: 0 }}>
<Draggable handle=".drag-handler" defaultClassName={cx('draggable')} positionOffset={{ x: 0, y: offsetTop }}>
<div {...props}>{children}</div>
</Draggable>
)}

View file

@ -87,10 +87,11 @@ class Rotations extends Component<RotationsProps, RotationsState> {
{layers && layers.length ? (
layers.map((layer, layerIndex) => (
<div key={layer.priority}>
<div className={cx('layer')}>
<div id={`layer${layer.priority}`} className={cx('layer')}>
<div className={cx('layer-title')}>
<HorizontalGroup spacing="sm" justify="center">
Layer {layer.priority} <Icon name="info-circle" />
<span>Layer {layer.priority}</span>
<Icon name="info-circle" />
</HorizontalGroup>
</div>
<div className={cx('rotations')}>
@ -119,10 +120,11 @@ class Rotations extends Component<RotationsProps, RotationsState> {
))
) : (
<div>
<div className={cx('layer')}>
<div id={`layer1`} className={cx('layer')}>
<div className={cx('layer-title')}>
<HorizontalGroup spacing="sm" justify="center">
Layer 1 <Icon name="info-circle" />
<span>Layer 1</span>
<Icon name="info-circle" />
</HorizontalGroup>
</div>
<div className={cx('header-plus-content')}>
@ -151,7 +153,7 @@ class Rotations extends Component<RotationsProps, RotationsState> {
this.handleAddLayer(nextPriority);
}}
>
Add rotations layer +
+ Add rotations layer
</div>
</div>
</div>

View file

@ -55,7 +55,7 @@ class ScheduleOverrides extends Component<ScheduleOverridesProps, ScheduleOverri
return (
<>
<div className={cx('root')}>
<div id="overrides-list" className={cx('root')}>
<div className={cx('header')}>
<HorizontalGroup justify="space-between">
<div className={cx('title')}>Overrides</div>
@ -93,9 +93,9 @@ class ScheduleOverrides extends Component<ScheduleOverridesProps, ScheduleOverri
)}
</div>
</div>
<div className={cx('add-rotations-layer')} onClick={this.handleAddOverride}>
Add override +
</div>
{/* <div className={cx('add-rotations-layer')} onClick={this.handleAddOverride}>
+ Add override
</div>*/}
</div>
{shiftIdToShowOverrideForm && (
<ScheduleOverrideForm

View file

@ -0,0 +1,38 @@
export const waitForElement = (selector: string) => {
return new Promise((resolve) => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver((mutations) => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
});
};
export const getCoords = (elem) => {
// crossbrowser version
var box = elem.getBoundingClientRect();
var body = document.body;
var docEl = document.documentElement;
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
var clientTop = docEl.clientTop || body.clientTop || 0;
var clientLeft = docEl.clientLeft || body.clientLeft || 0;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return { top: Math.round(top), left: Math.round(left) };
};