Skip to content

Commit 3079fac

Browse files
authored
🧪 Feat: move overlap to dedicated dir and add tests (#246)
* 🧪 Feat: move overlap to dedicated dir and add tests * ♻️ Refactor: Remove deprecated overlap tests and streamline event adjustment logic
1 parent 9294b3b commit 3079fac

File tree

5 files changed

+239
-297
lines changed

5 files changed

+239
-297
lines changed
Lines changed: 1 addition & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import {
2-
adjustOverlappingEvents,
3-
assembleGridEvent,
4-
isEventInRange,
5-
} from "./event.util";
1+
import { isEventInRange } from "./event.util";
62

73
describe("isEventInRange", () => {
84
it("returns true if event is in range", () => {
@@ -22,198 +18,3 @@ describe("isEventInRange", () => {
2218
expect(isEventInRange(event, dates)).toBe(false);
2319
});
2420
});
25-
26-
describe("adjustOverlappingEvents", () => {
27-
// Helper function that constructs a date string from hour:minute input.
28-
// Makes date time strings easier to read
29-
const time = (time: string) => `2025-01-27T${time}:00+03:00`;
30-
31-
it("Sorts events by start time", () => {
32-
const eventA = assembleGridEvent({
33-
_id: "A",
34-
startDate: time("07:30"),
35-
endDate: time("08:00"),
36-
});
37-
const eventB = assembleGridEvent({
38-
_id: "B",
39-
startDate: time("07:15"),
40-
endDate: time("07:45"),
41-
});
42-
43-
const adjustedEvents = adjustOverlappingEvents([eventA, eventB]);
44-
45-
expect(adjustedEvents[0].startDate).toBe(eventB.startDate);
46-
expect(adjustedEvents[1].startDate).toBe(eventA.startDate);
47-
});
48-
49-
it("Returns the same array if no events overlap", () => {
50-
const eventA = assembleGridEvent({
51-
_id: "A",
52-
startDate: time("07:30"),
53-
endDate: time("08:00"),
54-
});
55-
const eventB = assembleGridEvent({
56-
_id: "B",
57-
startDate: time("08:00"),
58-
endDate: time("08:30"),
59-
});
60-
61-
const adjustedEvents = adjustOverlappingEvents([eventA, eventB]);
62-
63-
expect(adjustedEvents).toEqual([eventA, eventB]);
64-
});
65-
66-
it("Adjusts events that overlap", () => {
67-
const eventA = assembleGridEvent({
68-
_id: "A",
69-
startDate: time("07:30"),
70-
endDate: time("08:00"),
71-
});
72-
const eventB = assembleGridEvent({
73-
_id: "B",
74-
startDate: time("07:45"),
75-
endDate: time("08:15"),
76-
});
77-
78-
const adjustedEvents = adjustOverlappingEvents([eventA, eventB]);
79-
80-
expect(adjustedEvents[0].position.isOverlapping).toBe(true);
81-
expect(adjustedEvents[0].position.horizontalOrder).toBe(1);
82-
expect(adjustedEvents[1].position.isOverlapping).toBe(true);
83-
expect(adjustedEvents[1].position.horizontalOrder).toBe(2);
84-
});
85-
86-
it("Does not modify events that do not overlap", () => {
87-
const eventA = assembleGridEvent({
88-
_id: "A",
89-
startDate: time("07:30"),
90-
endDate: time("08:00"),
91-
});
92-
const eventB = assembleGridEvent({
93-
_id: "B",
94-
startDate: time("07:45"),
95-
endDate: time("08:15"),
96-
});
97-
const nonOverlappingEventC = assembleGridEvent({
98-
_id: "C",
99-
startDate: time("09:45"),
100-
endDate: time("10:15"),
101-
});
102-
103-
const adjustedEvents = adjustOverlappingEvents([
104-
eventA,
105-
eventB,
106-
nonOverlappingEventC,
107-
]);
108-
109-
expect(adjustedEvents[0].position.isOverlapping).toBe(true);
110-
expect(adjustedEvents[0].position.horizontalOrder).toBe(1);
111-
expect(adjustedEvents[1].position.isOverlapping).toBe(true);
112-
expect(adjustedEvents[1].position.horizontalOrder).toBe(2);
113-
// Non-overlapping event should not be modified
114-
expect(adjustedEvents[2]).toStrictEqual(nonOverlappingEventC);
115-
});
116-
117-
it("Adjusts events that indirectly overlap", () => {
118-
const eventA = assembleGridEvent({
119-
_id: "A",
120-
startDate: time("07:30"),
121-
endDate: time("08:00"),
122-
});
123-
const eventB = assembleGridEvent({
124-
_id: "B",
125-
startDate: time("07:45"),
126-
endDate: time("08:15"),
127-
});
128-
const eventC = assembleGridEvent({
129-
_id: "C",
130-
// `eventC` starts when `eventA` ends, does not directly overlap, but should still be adjusted because it indirectly overlaps due to `eventB`
131-
startDate: time("08:00"),
132-
endDate: time("08:30"),
133-
});
134-
135-
const adjustedEvents = adjustOverlappingEvents([eventA, eventB, eventC]);
136-
137-
expect(adjustedEvents[0].position.isOverlapping).toBe(true);
138-
expect(adjustedEvents[0].position.horizontalOrder).toBe(1);
139-
expect(adjustedEvents[1].position.isOverlapping).toBe(true);
140-
expect(adjustedEvents[1].position.horizontalOrder).toBe(2);
141-
expect(adjustedEvents[2].position.isOverlapping).toBe(true);
142-
expect(adjustedEvents[2].position.horizontalOrder).toBe(3);
143-
});
144-
145-
it("Adjusts events that overlap in 2 distinct groups", () => {
146-
// Group 1
147-
const eventA = assembleGridEvent({
148-
_id: "A",
149-
startDate: time("07:30"),
150-
endDate: time("08:00"),
151-
});
152-
const eventB = assembleGridEvent({
153-
_id: "B",
154-
startDate: time("07:45"),
155-
endDate: time("08:15"),
156-
});
157-
const eventC = assembleGridEvent({
158-
_id: "C",
159-
startDate: time("08:00"),
160-
endDate: time("08:30"),
161-
});
162-
163-
// Group 2
164-
const eventD = assembleGridEvent({
165-
_id: "D",
166-
startDate: time("10:00"),
167-
endDate: time("11:00"),
168-
});
169-
const eventE = assembleGridEvent({
170-
_id: "E",
171-
startDate: time("10:30"),
172-
endDate: time("11:30"),
173-
});
174-
175-
const adjustedEvents = adjustOverlappingEvents([
176-
eventA,
177-
eventB,
178-
eventC,
179-
eventD,
180-
eventE,
181-
]);
182-
183-
// Group 1
184-
expect(adjustedEvents[0].position.isOverlapping).toBe(true);
185-
expect(adjustedEvents[0].position.horizontalOrder).toBe(1);
186-
expect(adjustedEvents[1].position.isOverlapping).toBe(true);
187-
expect(adjustedEvents[1].position.horizontalOrder).toBe(2);
188-
expect(adjustedEvents[2].position.isOverlapping).toBe(true);
189-
expect(adjustedEvents[2].position.horizontalOrder).toBe(3);
190-
191-
// Group 2
192-
expect(adjustedEvents[3].position.isOverlapping).toBe(true);
193-
expect(adjustedEvents[3].position.horizontalOrder).toBe(1);
194-
expect(adjustedEvents[4].position.isOverlapping).toBe(true);
195-
expect(adjustedEvents[4].position.horizontalOrder).toBe(2);
196-
});
197-
198-
it("Orders alphabetically if start and end times are the same", () => {
199-
const eventA = assembleGridEvent({
200-
_id: "A",
201-
title: "A",
202-
startDate: time("07:30"),
203-
endDate: time("08:00"),
204-
});
205-
const eventB = assembleGridEvent({
206-
_id: "B",
207-
title: "B",
208-
startDate: time("07:30"),
209-
endDate: time("08:00"),
210-
});
211-
212-
const adjustedEvents = adjustOverlappingEvents([eventA, eventB]);
213-
214-
expect(adjustedEvents[0].title).toBe("A");
215-
expect(adjustedEvents[0].position.horizontalOrder).toBe(1);
216-
expect(adjustedEvents[1].title).toBe("B");
217-
expect(adjustedEvents[1].position.horizontalOrder).toBe(2);
218-
});
219-
});

packages/web/src/common/utils/event.util.ts

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -26,101 +26,6 @@ dayjs.extend(isSameOrAfter);
2626
dayjs.extend(isSameOrBefore);
2727
dayjs.extend(isBetween);
2828

29-
export const adjustOverlappingEvents = (
30-
events: Schema_GridEvent[]
31-
): Schema_GridEvent[] => {
32-
// Deep copy events
33-
let adjustedEvents = events.map((event) => ({
34-
...event,
35-
position: { ...event.position },
36-
}));
37-
38-
// Sort by start time first
39-
adjustedEvents.sort((a, b) => dayjs(a.startDate).diff(dayjs(b.startDate)));
40-
41-
const processedEvents = new Set<string>();
42-
43-
// Helper function to find all overlapping events recursively
44-
const findAllOverlappingEvents = (
45-
baseEvent: Schema_GridEvent,
46-
accumulatedEvents = new Set<Schema_GridEvent>()
47-
): Set<Schema_GridEvent> => {
48-
const directOverlaps = adjustedEvents.filter(
49-
(otherEvent) =>
50-
otherEvent !== baseEvent && // Skip itself
51-
!accumulatedEvents.has(otherEvent) && // Skip if already processed
52-
dayjs(baseEvent.startDate).isBefore(dayjs(otherEvent.endDate)) &&
53-
dayjs(baseEvent.endDate).isAfter(dayjs(otherEvent.startDate))
54-
);
55-
56-
directOverlaps.forEach((event) => {
57-
accumulatedEvents.add(event);
58-
// Recursively find overlaps for each overlapping event
59-
findAllOverlappingEvents(event, accumulatedEvents);
60-
});
61-
62-
return accumulatedEvents;
63-
};
64-
65-
for (let i = 0; i < adjustedEvents.length; i++) {
66-
const targetEvent = adjustedEvents[i];
67-
68-
// Skip if already processed
69-
if (processedEvents.has(targetEvent._id)) {
70-
continue;
71-
}
72-
73-
// Find all overlapping events recursively
74-
const overlappingEventsSet = findAllOverlappingEvents(
75-
targetEvent,
76-
new Set([targetEvent])
77-
);
78-
const eventGroup = Array.from(overlappingEventsSet);
79-
80-
if (eventGroup.length > 1) {
81-
// If there are any overlaps, calculate width multiplier
82-
let multiplier = 1 / eventGroup.length;
83-
// Round to 2 decimal places (in case we have way too many decimal places from the division)
84-
multiplier = Math.round(multiplier * 100) / 100;
85-
86-
// Set adjustments for all events in the group
87-
eventGroup.forEach((event, i) => {
88-
event.position.isOverlapping = true;
89-
event.position.widthMultiplier *= multiplier;
90-
event.position.horizontalOrder = i + 1;
91-
processedEvents.add(event._id);
92-
});
93-
94-
// If exact start and end times match, sort alphabetically by title
95-
if (
96-
eventGroup.every(
97-
(event) =>
98-
dayjs(event.startDate).isSame(targetEvent.startDate) &&
99-
dayjs(event.endDate).isSame(targetEvent.endDate)
100-
)
101-
) {
102-
eventGroup.sort((a, b) => {
103-
if (!a.title || !b.title) {
104-
return 0;
105-
}
106-
107-
return a.title.localeCompare(b.title);
108-
});
109-
}
110-
}
111-
}
112-
113-
return adjustedEvents;
114-
};
115-
116-
export const adjustEvents = (
117-
events: Schema_GridEvent[]
118-
): Schema_GridEvent[] => {
119-
const adjustedEvents = adjustOverlappingEvents(events);
120-
121-
return adjustedEvents;
122-
};
123-
12429
export const assembleBaseEvent = (
12530
userId: string,
12631
event: Partial<Schema_Event>

0 commit comments

Comments
 (0)