schedule changes
This commit is contained in:
parent
c7bc0248f4
commit
0018fb1973
9 changed files with 86 additions and 66 deletions
|
|
@ -6,19 +6,21 @@ import styles from './ScheduleBorderedAvatar.module.scss';
|
|||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
interface ScheduleBorderedAvatarProps {
|
||||
colors: string[];
|
||||
width: number;
|
||||
height: number;
|
||||
renderAvatar: () => JSX.Element;
|
||||
renderIcon: () => JSX.Element;
|
||||
}
|
||||
|
||||
export default function ScheduleBorderedAvatar({
|
||||
colors,
|
||||
renderAvatar,
|
||||
renderIcon,
|
||||
width,
|
||||
height,
|
||||
}: {
|
||||
colors: string[];
|
||||
width: number;
|
||||
height: number;
|
||||
renderAvatar: () => JSX.Element;
|
||||
renderIcon: () => JSX.Element;
|
||||
}) {
|
||||
}: ScheduleBorderedAvatarProps) {
|
||||
return <div className={cx('root')}>{colors?.length ? renderSVG() : renderAvatarIcon()}</div>;
|
||||
|
||||
function renderAvatarIcon() {
|
||||
|
|
@ -50,16 +52,16 @@ export default function ScheduleBorderedAvatar({
|
|||
}
|
||||
|
||||
const stepAngle = (2 * Math.PI) / colors.length;
|
||||
const radius = 100;
|
||||
const RADIUS = 100;
|
||||
|
||||
let lastX = 0;
|
||||
let lastY = -radius;
|
||||
let lastY = -RADIUS;
|
||||
|
||||
return colorSchemeList.map((_color, colorIndex) => {
|
||||
const angle = (colorIndex + 1) * stepAngle;
|
||||
const x = radius * Math.sin(angle);
|
||||
const y = -radius * Math.cos(angle);
|
||||
const d = `M ${lastX.toFixed(3)},${lastY.toFixed(3)} A 100,100 0 0,1 ${x.toFixed(3)},${y.toFixed(3)}`;
|
||||
const x = RADIUS * Math.sin(angle);
|
||||
const y = -RADIUS * Math.cos(angle);
|
||||
const d = `M ${lastX.toFixed(3)},${lastY.toFixed(3)} A ${RADIUS},${RADIUS} 0 0,1 ${x.toFixed(3)},${y.toFixed(3)}`;
|
||||
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ interface RotationsProps extends WithStoreProps {
|
|||
startMoment: dayjs.Dayjs;
|
||||
currentTimezone: Timezone;
|
||||
shiftIdToShowRotationForm?: Shift['id'] | 'new';
|
||||
scheduleId: Schedule['id'];
|
||||
onShowRotationForm: (shiftId: Shift['id'] | 'new') => void;
|
||||
onClick: (id: Shift['id'] | 'new') => void;
|
||||
onCreate: () => void;
|
||||
|
|
@ -50,9 +51,8 @@ class Rotations extends Component<RotationsProps, RotationsState> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { startMoment, currentTimezone, onCreate, onUpdate, onDelete, store, shiftIdToShowRotationForm } = this.props;
|
||||
const { scheduleId, startMoment, currentTimezone, onCreate, onUpdate, onDelete, store, shiftIdToShowRotationForm } = this.props;
|
||||
const { layerPriority, shiftMomentToShowRotationForm } = this.state;
|
||||
const { scheduleId } = store.scheduleStore;
|
||||
|
||||
const base = 7 * 24 * 60; // in minutes
|
||||
const diff = dayjs().tz(currentTimezone).diff(startMoment, 'minutes');
|
||||
|
|
@ -239,8 +239,6 @@ class Rotations extends Component<RotationsProps, RotationsState> {
|
|||
};
|
||||
|
||||
hideRotationForm = () => {
|
||||
const { store } = this.props;
|
||||
|
||||
this.setState(
|
||||
{
|
||||
layerPriority: undefined,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
|||
|
||||
import TimelineMarks from 'components/TimelineMarks/TimelineMarks';
|
||||
import Rotation from 'containers/Rotation/Rotation';
|
||||
import { getColor, getFromString, getOverrideColor } from 'models/schedule/schedule.helpers';
|
||||
import { getColor, getFromString, getLayersFromStore, getOverrideColor, getOverridesFromStore, getShiftsFromStore } from 'models/schedule/schedule.helpers';
|
||||
import { Event, Layer, Schedule, Shift } from 'models/schedule/schedule.types';
|
||||
import { Timezone } from 'models/timezone/timezone.types';
|
||||
import { WithStoreProps } from 'state/types';
|
||||
|
|
@ -24,6 +24,7 @@ const cx = cn.bind(styles);
|
|||
interface ScheduleFinalProps extends WithStoreProps {
|
||||
startMoment: dayjs.Dayjs;
|
||||
currentTimezone: Timezone;
|
||||
scheduleId: Schedule['id'];
|
||||
hideHeader?: boolean;
|
||||
onClick: (shiftId: Shift['id']) => void;
|
||||
}
|
||||
|
|
@ -39,28 +40,19 @@ class ScheduleFinal extends Component<ScheduleFinalProps, ScheduleOverridesState
|
|||
};
|
||||
|
||||
render() {
|
||||
const { startMoment, currentTimezone, store, hideHeader } = this.props;
|
||||
const { scheduleId } = store.scheduleStore;
|
||||
const { startMoment, currentTimezone, store, hideHeader, scheduleId } = this.props;
|
||||
|
||||
const base = 7 * 24 * 60; // in minutes
|
||||
const diff = dayjs().tz(currentTimezone).diff(startMoment, 'minutes');
|
||||
|
||||
const currentTimeX = diff / base;
|
||||
|
||||
const shifts = store.scheduleStore.finalPreview
|
||||
? store.scheduleStore.finalPreview
|
||||
: (store.scheduleStore.events[scheduleId]?.['final']?.[getFromString(startMoment)] as Array<{
|
||||
shiftId: string;
|
||||
events: Event[];
|
||||
}>);
|
||||
const shifts = getShiftsFromStore(store, scheduleId, startMoment, false);
|
||||
|
||||
const layers = store.scheduleStore.rotationPreview
|
||||
? store.scheduleStore.rotationPreview
|
||||
: (store.scheduleStore.events[scheduleId]?.['rotation']?.[getFromString(startMoment)] as Layer[]);
|
||||
const layers = getLayersFromStore(store, scheduleId, startMoment);
|
||||
|
||||
const overrides = getOverridesFromStore(store, scheduleId, startMoment, true);
|
||||
|
||||
const overrides = store.scheduleStore.overridePreview
|
||||
? store.scheduleStore.overridePreview
|
||||
: store.scheduleStore.events[scheduleId]?.['override']?.[getFromString(startMoment)];
|
||||
const currentTimeHidden = currentTimeX < 0 || currentTimeX > 1;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import TimelineMarks from 'components/TimelineMarks/TimelineMarks';
|
|||
import Rotation from 'containers/Rotation/Rotation';
|
||||
import { RotationCreateData } from 'containers/RotationForm/RotationForm.types';
|
||||
import ScheduleOverrideForm from 'containers/RotationForm/ScheduleOverrideForm';
|
||||
import { getFromString, getOverrideColor } from 'models/schedule/schedule.helpers';
|
||||
import { getFromString, getOverrideColor, getShiftsFromStore } from 'models/schedule/schedule.helpers';
|
||||
import { Event, Schedule, Shift } from 'models/schedule/schedule.types';
|
||||
import { Timezone } from 'models/timezone/timezone.types';
|
||||
import { WithStoreProps } from 'state/types';
|
||||
|
|
@ -26,6 +26,7 @@ const cx = cn.bind(styles);
|
|||
interface ScheduleOverridesProps extends WithStoreProps {
|
||||
startMoment: dayjs.Dayjs;
|
||||
currentTimezone: Timezone;
|
||||
scheduleId: Schedule['id'];
|
||||
shiftIdToShowRotationForm?: Shift['id'] | 'new';
|
||||
onShowRotationForm: (shiftId: Shift['id'] | 'new') => void;
|
||||
onCreate: () => void;
|
||||
|
|
@ -44,18 +45,11 @@ class ScheduleOverrides extends Component<ScheduleOverridesProps, ScheduleOverri
|
|||
};
|
||||
|
||||
render() {
|
||||
const { startMoment, currentTimezone, onCreate, onUpdate, onDelete, store, shiftIdToShowRotationForm } =
|
||||
const { startMoment, currentTimezone, onCreate, onUpdate, onDelete, store, shiftIdToShowRotationForm, scheduleId } =
|
||||
this.props;
|
||||
const { shiftMomentToShowOverrideForm } = this.state;
|
||||
const { scheduleId } = store.scheduleStore;
|
||||
|
||||
const shifts = store.scheduleStore.overridePreview
|
||||
? store.scheduleStore.overridePreview
|
||||
: (store.scheduleStore.events[scheduleId]?.['override']?.[getFromString(startMoment)] as Array<{
|
||||
shiftId: string;
|
||||
events: Event[];
|
||||
isPreview?: boolean;
|
||||
}>);
|
||||
const shifts = getShiftsFromStore(store, scheduleId, startMoment, true);
|
||||
|
||||
const base = 7 * 24 * 60; // in minutes
|
||||
const diff = dayjs().tz(currentTimezone).diff(startMoment, 'minutes');
|
||||
|
|
|
|||
|
|
@ -12,8 +12,15 @@ import ScheduleUserDetails from 'components/ScheduleUserDetails/ScheduleUserDeta
|
|||
import Text from 'components/Text/Text';
|
||||
import { findColor } from 'containers/Rotations/Rotations.helpers';
|
||||
import { IsOncallIcon } from 'icons';
|
||||
import { getColor, getFromString, getOverrideColor } from 'models/schedule/schedule.helpers';
|
||||
import { Event, Layer } from 'models/schedule/schedule.types';
|
||||
import {
|
||||
getColor,
|
||||
getFromString,
|
||||
getLayersFromStore,
|
||||
getOverrideColor,
|
||||
getOverridesFromStore,
|
||||
getShiftsFromStore,
|
||||
} from 'models/schedule/schedule.helpers';
|
||||
import { Event, Layer, Schedule } from 'models/schedule/schedule.types';
|
||||
import { Timezone } from 'models/timezone/timezone.types';
|
||||
import { User } from 'models/user/user.types';
|
||||
import { getStartOfWeek } from 'pages/schedule/Schedule.helpers';
|
||||
|
|
@ -130,7 +137,7 @@ const UsersTimezones: FC<UsersTimezonesProps> = (props) => {
|
|||
interface UserAvatarsProps {
|
||||
users: User[];
|
||||
currentMoment: dayjs.Dayjs;
|
||||
scheduleId: string;
|
||||
scheduleId: Schedule['id'];
|
||||
onTzChange: (timezone: Timezone) => void;
|
||||
onCallNow: Array<Partial<User>>;
|
||||
}
|
||||
|
|
@ -195,7 +202,7 @@ interface AvatarGroupProps {
|
|||
xPos: number;
|
||||
currentMoment: dayjs.Dayjs;
|
||||
utcOffset: number;
|
||||
scheduleId: string;
|
||||
scheduleId: Schedule['id'];
|
||||
onSetActiveUtcOffset: (utcOffset: number | undefined) => void;
|
||||
activeUtcOffset: number;
|
||||
onTzChange: (timezone: Timezone) => void;
|
||||
|
|
@ -308,17 +315,11 @@ const AvatarGroup = (props: AvatarGroupProps) => {
|
|||
function getColorSchemeMappingForUsers(store: RootStore, scheduleId: string): { [userId: string]: Set<string> } {
|
||||
const startMoment = getStartOfWeek(store.currentTimezone);
|
||||
|
||||
const shifts: Array<{ shiftId: string; events: Event[] }> = false
|
||||
? store.scheduleStore.finalPreview
|
||||
: (store.scheduleStore.events[scheduleId]?.['final']?.[getFromString(startMoment)] as any);
|
||||
const shifts = getShiftsFromStore(store, scheduleId, startMoment, false);
|
||||
|
||||
const layers = store.scheduleStore.rotationPreview
|
||||
? store.scheduleStore.rotationPreview
|
||||
: (store.scheduleStore.events[scheduleId]?.['rotation']?.[getFromString(startMoment)] as Layer[]);
|
||||
const layers = getLayersFromStore(store, scheduleId, startMoment);
|
||||
|
||||
const overrides = store.scheduleStore.overridePreview
|
||||
? store.scheduleStore.overridePreview
|
||||
: store.scheduleStore.events[scheduleId]?.['override']?.[getFromString(startMoment)];
|
||||
const overrides = getOverridesFromStore(store, scheduleId, startMoment, false);
|
||||
|
||||
const usersColorSchemeHash: { [userId: string]: Set<string> } = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import dayjs from 'dayjs';
|
||||
import { RootStore } from 'state';
|
||||
|
||||
import { Event, Layer, ScheduleType, Shift } from './schedule.types';
|
||||
import { Event, Layer, Schedule, ScheduleType, Shift } from './schedule.types';
|
||||
|
||||
export const getFromString = (moment: dayjs.Dayjs) => {
|
||||
return moment.format('YYYY-MM-DD');
|
||||
|
|
@ -57,6 +58,43 @@ export const splitToShiftsAndFillGaps = (events: Event[]) => {
|
|||
return shifts;
|
||||
};
|
||||
|
||||
export const getShiftsFromStore = (
|
||||
store: RootStore,
|
||||
scheduleId: Schedule['id'],
|
||||
startMoment: dayjs.Dayjs,
|
||||
isOverridePreview: boolean,
|
||||
): Array<{ shiftId: string; events: Event[], isPreview?: boolean; }> => {
|
||||
const source = isOverridePreview ? store.scheduleStore.overridePreview : store.scheduleStore.finalPreview;
|
||||
return source
|
||||
? store.scheduleStore.finalPreview
|
||||
: (store.scheduleStore.events[scheduleId]?.['final']?.[getFromString(startMoment)] as any);
|
||||
};
|
||||
|
||||
export const getLayersFromStore = (store: RootStore, scheduleId: Schedule['id'], startMoment: dayjs.Dayjs): Layer[] => {
|
||||
return store.scheduleStore.rotationPreview
|
||||
? store.scheduleStore.rotationPreview
|
||||
: (store.scheduleStore.events[scheduleId]?.['rotation']?.[getFromString(startMoment)] as Layer[]);
|
||||
};
|
||||
|
||||
export const getOverridesFromStore = (
|
||||
store: RootStore,
|
||||
scheduleId: Schedule['id'],
|
||||
startMoment: dayjs.Dayjs,
|
||||
isOverridePreview: boolean
|
||||
):
|
||||
| Layer[]
|
||||
| {
|
||||
shiftId: string;
|
||||
events: Event[];
|
||||
isPreview?: boolean;
|
||||
}[] => {
|
||||
|
||||
const source = isOverridePreview ? store.scheduleStore.overridePreview : store.scheduleStore.rotationPreview;
|
||||
return source
|
||||
? store.scheduleStore.rotationPreview
|
||||
: (store.scheduleStore.events[scheduleId]?.['rotation']?.[getFromString(startMoment)] as Layer[]);
|
||||
};
|
||||
|
||||
export const splitToLayers = (
|
||||
shifts: Array<{ shiftId: Shift['id']; priority: Shift['priority_level']; events: Event[] }>
|
||||
) => {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export class ScheduleStore extends BaseStore {
|
|||
byDayOptions: SelectOption[];
|
||||
|
||||
@observable
|
||||
scheduleId: string;
|
||||
scheduleId: Schedule['id'];
|
||||
|
||||
constructor(rootStore: RootStore) {
|
||||
super(rootStore);
|
||||
|
|
|
|||
|
|
@ -86,8 +86,6 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
this.updateEvents(),
|
||||
]);
|
||||
|
||||
store.scheduleStore.scheduleId = id;
|
||||
|
||||
this.setState({ isLoading: false });
|
||||
}
|
||||
|
||||
|
|
@ -95,19 +93,16 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
const { store } = this.props;
|
||||
|
||||
store.scheduleStore.clearPreview();
|
||||
store.scheduleStore.scheduleId = undefined
|
||||
}
|
||||
|
||||
render() {
|
||||
const { query: { id: scheduleId }, store } = this.props;
|
||||
const { isLoading, startMoment, shiftIdToShowRotationForm, shiftIdToShowOverridesForm } = this.state;
|
||||
const { startMoment, shiftIdToShowRotationForm, shiftIdToShowOverridesForm } = this.state;
|
||||
const { scheduleStore, currentTimezone } = store;
|
||||
|
||||
const users = store.userStore.getSearchResult().results;
|
||||
const schedule = scheduleStore.items[scheduleId];
|
||||
|
||||
if (isLoading) {return <LoadingPlaceholder text="Loading..." />}
|
||||
|
||||
return (
|
||||
<div className={cx('root')}>
|
||||
<VerticalGroup spacing="lg">
|
||||
|
|
@ -173,6 +168,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
currentTimezone={currentTimezone}
|
||||
startMoment={startMoment}
|
||||
onClick={this.handleShowForm}
|
||||
scheduleId={scheduleId}
|
||||
/>
|
||||
<Rotations
|
||||
currentTimezone={currentTimezone}
|
||||
|
|
@ -182,6 +178,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
onDelete={this.handleDeleteRotation}
|
||||
shiftIdToShowRotationForm={shiftIdToShowRotationForm}
|
||||
onShowRotationForm={this.handleShowRotationForm}
|
||||
scheduleId={scheduleId}
|
||||
/>
|
||||
<ScheduleOverrides
|
||||
currentTimezone={currentTimezone}
|
||||
|
|
@ -191,6 +188,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
onDelete={this.handleDeleteOverride}
|
||||
shiftIdToShowRotationForm={shiftIdToShowOverridesForm}
|
||||
onShowRotationForm={this.handleShowOverridesForm}
|
||||
scheduleId={scheduleId}
|
||||
/>
|
||||
</div>
|
||||
</VerticalGroup>
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
const { store } = this.props;
|
||||
const { expandedSchedulesKeys, scheduleIdToDelete, scheduleIdToEdit, scheduleIdToExport } = this.state;
|
||||
const { filters } = this.state;
|
||||
const { scheduleStore, userStore } = store;
|
||||
const { scheduleStore } = store;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
|
|
@ -306,9 +306,6 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
};
|
||||
|
||||
handleChangeFilters = (filters: SchedulesFiltersType) => {
|
||||
const { store } = this.props;
|
||||
const { scheduleStore } = store;
|
||||
|
||||
this.setState({ filters }, () => {
|
||||
const { filters, expandedSchedulesKeys } = this.state;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue