Skip to content

Commit 82da372

Browse files
committed
feat(web): implement allday event horizontal duration scaling
1 parent 782007f commit 82da372

File tree

6 files changed

+144
-18
lines changed

6 files changed

+144
-18
lines changed

packages/web/src/views/Calendar/components/Draft/grid/hooks/useGridMouseMove.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const useGridMouseMove = () => {
1515
(e: MouseEvent) => {
1616
if (!isDrafting) return;
1717

18-
if (isResizing && !draft?.isAllDay) {
18+
if (isResizing) {
1919
resize(e);
2020
} else if (isDragging) {
2121
e.preventDefault();

packages/web/src/views/Calendar/components/Draft/grid/hooks/useGridMouseUp.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const useGridMouseUp = () => {
2525
hasMoved = resizeStatus?.hasMoved || dragStatus?.hasMoved || false;
2626
shouldSubmit = !draft?.isOpen;
2727
} else if (category === Categories_Event.ALLDAY) {
28-
hasMoved = dragStatus?.hasMoved || false;
28+
hasMoved = dragStatus?.hasMoved || resizeStatus?.hasMoved || false;
2929
shouldSubmit = hasMoved;
3030
}
3131

@@ -40,6 +40,10 @@ export const useGridMouseUp = () => {
4040
const handleAllDayRowMouseUp = useCallback(() => {
4141
if (!draft) return;
4242

43+
if (isResizing) {
44+
stopResizing();
45+
}
46+
4347
if (isDragging) {
4448
stopDragging();
4549
}
@@ -56,7 +60,16 @@ export const useGridMouseUp = () => {
5660
if (shouldSubmit) {
5761
submit(draft);
5862
}
59-
}, [draft, isDragging, getNextAction, stopDragging, openForm, submit]);
63+
}, [
64+
draft,
65+
isDragging,
66+
isResizing,
67+
getNextAction,
68+
stopDragging,
69+
stopResizing,
70+
openForm,
71+
submit,
72+
]);
6073

6174
const handleMainGridMouseUp = useCallback(() => {
6275
if (!draft || !isDrafting) return;

packages/web/src/views/Calendar/components/Draft/hooks/actions/useDraftActions.ts

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -439,16 +439,21 @@ export const useDraftActions = (
439439
(currTime: dayjs.Dayjs) => {
440440
if (!draft || !dateBeingChanged) return false;
441441

442-
const _currTime = currTime.format();
442+
const _currTime = draft.isAllDay
443+
? currTime.format(YEAR_MONTH_DAY_FORMAT)
444+
: currTime.format();
443445
const noChange = draft[dateBeingChanged] === _currTime;
444446

445447
if (noChange) return false;
446448

447-
const diffDay = currTime.day() !== dayjs(draft.startDate).day();
448-
if (diffDay) return false;
449+
// For timed events, restrict to same day
450+
if (!draft.isAllDay) {
451+
const diffDay = currTime.day() !== dayjs(draft.startDate).day();
452+
if (diffDay) return false;
449453

450-
const sameStart = currTime.format() === draft.startDate;
451-
if (sameStart) return false;
454+
const sameStart = currTime.format() === draft.startDate;
455+
if (sameStart) return false;
456+
}
452457

453458
return true;
454459
},
@@ -481,10 +486,23 @@ export const useDraftActions = (
481486
} else if (comparisonKeyword === "before") {
482487
if (currTime.isBefore(opposite)) {
483488
setDateBeingChanged(oppositeKey);
484-
startDate = dayjs(startDate)
485-
.subtract(GRID_TIME_STEP, "minutes")
486-
.format();
487-
endDate = dayjs(startDate).add(GRID_TIME_STEP, "minutes").format();
489+
if (draft?.isAllDay) {
490+
// For all-day events, move by day
491+
startDate = dayjs(startDate)
492+
.subtract(1, "day")
493+
.format(YEAR_MONTH_DAY_FORMAT);
494+
endDate = dayjs(startDate)
495+
.add(1, "day")
496+
.format(YEAR_MONTH_DAY_FORMAT);
497+
} else {
498+
// For timed events, move by time step
499+
startDate = dayjs(startDate)
500+
.subtract(GRID_TIME_STEP, "minutes")
501+
.format();
502+
endDate = dayjs(startDate)
503+
.add(GRID_TIME_STEP, "minutes")
504+
.format();
505+
}
488506

489507
justFlipped = true;
490508
}
@@ -510,9 +528,11 @@ export const useDraftActions = (
510528
if (!isResizing) return;
511529

512530
const x = getX(e, isSidebarOpen);
531+
// For all-day events, use a fixed Y coordinate since they don't use Y positioning
532+
const y = draft?.isAllDay ? 0 : e.clientY;
513533
const currTime = dateCalcs.getDateByXY(
514534
x,
515-
e.clientY,
535+
y,
516536
weekProps.component.startOfView,
517537
);
518538

@@ -524,10 +544,23 @@ export const useDraftActions = (
524544
const dateChanged = justFlipped ? oppositeKey : dateBeingChanged;
525545

526546
const origTime = dayjs(dateChanged ? draft?.[dateChanged] : null);
527-
const diffMin = currTime.diff(origTime, "minute");
528-
const updatedTime = origTime.add(diffMin, "minutes").format();
529547

530-
const hasMoved = diffMin !== 0;
548+
let updatedTime: string;
549+
let hasMoved: boolean;
550+
551+
if (draft?.isAllDay) {
552+
// For all-day events, work with day differences
553+
const diffDays = currTime.diff(origTime, "day");
554+
updatedTime = origTime
555+
.add(diffDays, "days")
556+
.format(YEAR_MONTH_DAY_FORMAT);
557+
hasMoved = diffDays !== 0;
558+
} else {
559+
// For timed events, work with minute differences
560+
const diffMin = currTime.diff(origTime, "minute");
561+
updatedTime = origTime.add(diffMin, "minutes").format();
562+
hasMoved = diffMin !== 0;
563+
}
531564

532565
if (!resizeStatus?.hasMoved && hasMoved) {
533566
setResizeStatus({ hasMoved: true });

packages/web/src/views/Calendar/components/Event/styled.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,29 @@ export const StyledEventScaler = styled.div.attrs<ScalerProps>((props) => {
135135
${(props) => props.showResizeCursor && `cursor: row-resize`};
136136
${({ zIndex }) => zIndex && `z-index: ${zIndex}`}
137137
`;
138+
139+
export interface HorizontalScalerProps {
140+
showResizeCursor: boolean;
141+
left?: string;
142+
right?: string;
143+
zIndex?: number;
144+
}
145+
146+
export const StyledEventHorizontalScaler = styled.div.attrs<HorizontalScalerProps>(
147+
(props) => {
148+
return {
149+
left: props.left,
150+
right: props.right,
151+
};
152+
},
153+
)<HorizontalScalerProps>`
154+
position: absolute;
155+
width: 4.5px;
156+
height: 100%;
157+
opacity: 0;
158+
top: 0;
159+
left: ${(props) => props.left};
160+
right: ${(props) => props.right};
161+
${(props) => props.showResizeCursor && `cursor: col-resize`};
162+
${({ zIndex }) => zIndex && `z-index: ${zIndex}`}
163+
`;

packages/web/src/views/Calendar/components/Grid/AllDayRow/AllDayEvent.tsx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import dayjs from "dayjs";
22
import React, { MouseEvent, memo } from "react";
33
import { Priorities } from "@core/constants/core.constants";
4-
import { DATA_EVENT_ELEMENT_ID } from "@web/common/constants/web.constants";
4+
import {
5+
DATA_EVENT_ELEMENT_ID,
6+
ZIndex,
7+
} from "@web/common/constants/web.constants";
58
import { Schema_GridEvent } from "@web/common/types/web.event.types";
69
import { isOptimisticEvent } from "@web/common/utils/event.util";
710
import { getEventPosition } from "@web/common/utils/position.util";
@@ -11,7 +14,7 @@ import { SpaceCharacter } from "@web/components/SpaceCharacter";
1114
import { Text } from "@web/components/Text";
1215
import { Measurements_Grid } from "@web/views/Calendar/hooks/grid/useGridLayout";
1316
import { WeekProps } from "@web/views/Calendar/hooks/useWeek";
14-
import { StyledEvent } from "../../Event/styled";
17+
import { StyledEvent, StyledEventHorizontalScaler } from "../../Event/styled";
1518

1619
interface Props {
1720
event: Schema_GridEvent;
@@ -20,6 +23,11 @@ interface Props {
2023
startOfView: WeekProps["component"]["startOfView"];
2124
endOfView: WeekProps["component"]["endOfView"];
2225
onMouseDown: (e: MouseEvent, event: Schema_GridEvent) => void;
26+
onScalerMouseDown?: (
27+
event: Schema_GridEvent,
28+
e: MouseEvent,
29+
dateToChange: "startDate" | "endDate",
30+
) => void;
2331
}
2432

2533
const AllDayEvent = ({
@@ -29,6 +37,7 @@ const AllDayEvent = ({
2937
startOfView,
3038
endOfView,
3139
onMouseDown,
40+
onScalerMouseDown,
3241
}: Props) => {
3342
const position = getEventPosition(
3443
event,
@@ -73,6 +82,29 @@ const AllDayEvent = ({
7382
<SpaceCharacter />
7483
</Text>
7584
</Flex>
85+
{onScalerMouseDown && (
86+
<>
87+
<StyledEventHorizontalScaler
88+
showResizeCursor={!isPlaceholder && !isOptimistic}
89+
onMouseDown={(e) => {
90+
e.stopPropagation();
91+
onScalerMouseDown(event, e, "startDate");
92+
}}
93+
left="-0.25px"
94+
zIndex={ZIndex.LAYER_4}
95+
/>
96+
97+
<StyledEventHorizontalScaler
98+
right="-0.25px"
99+
showResizeCursor={!isPlaceholder && !isOptimistic}
100+
onMouseDown={(e) => {
101+
e.stopPropagation();
102+
onScalerMouseDown(event, e, "endDate");
103+
}}
104+
zIndex={ZIndex.LAYER_4}
105+
/>
106+
</>
107+
)}
76108
</StyledEvent>
77109
);
78110
};

packages/web/src/views/Calendar/components/Grid/AllDayRow/AllDayEvents.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ export const AllDayEvents = ({
5858
handleDrag,
5959
);
6060

61+
const resizeAllDayEvent = (
62+
event: Schema_GridEvent,
63+
dateToChange: "startDate" | "endDate",
64+
) => {
65+
dispatch(
66+
draftSlice.actions.startResizing({
67+
category: Categories_Event.ALLDAY,
68+
event,
69+
dateToChange,
70+
}),
71+
);
72+
};
73+
6174
const renderEvents = () => {
6275
if (
6376
isProcessing &&
@@ -81,6 +94,15 @@ export const AllDayEvents = ({
8194
}
8295
onMouseDown(e, event);
8396
}}
97+
onScalerMouseDown={(
98+
event,
99+
e,
100+
dateToChange: "startDate" | "endDate",
101+
) => {
102+
e.stopPropagation();
103+
e.preventDefault();
104+
resizeAllDayEvent(event, dateToChange);
105+
}}
84106
/>
85107
);
86108
});

0 commit comments

Comments
 (0)