Skip to content

Commit 625c260

Browse files
abhijeetsingh-22ibex088Udit-takkar
authored
fix: OOO days not correctly blocked (calcom#25259)
* fix: OOO check in buildSlotsWithDateRanges * added testcase --------- Co-authored-by: chauhan_s <somaychauhan98@gmail.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
1 parent 81224f3 commit 625c260

2 files changed

Lines changed: 58 additions & 3 deletions

File tree

packages/features/schedules/lib/slots.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,4 +840,60 @@ describe("Tests the date-range slot logic with showOptimizedSlots", () => {
840840

841841
vi.useRealTimers();
842842
});
843+
844+
it("should mark slots as away when OOO is on next day and availability extends past midnight", async () => {
845+
// This test reproduces the bug where:
846+
// - Day 1 has availability from 00:00 to 23:59
847+
// - Day 2 is marked as OOO
848+
// - Slots generated after midnight are not marked as away
849+
850+
vi.setSystemTime(dayjs.utc("2025-11-17T00:00:00Z").toDate());
851+
852+
const day1Start = dayjs.utc("2025-11-17T00:00:00Z");
853+
const day2End = dayjs.utc("2025-11-18T23:59:59Z");
854+
855+
// OOO data for Day 2 (2025-11-18)
856+
const datesOutOfOffice = {
857+
"2025-11-18": {
858+
fromUser: { id: 1, displayName: "Test User" },
859+
toUser: null,
860+
reason: "Out of office",
861+
emoji: "🏖️",
862+
},
863+
};
864+
865+
const slots = getSlots({
866+
inviteeDate: day1Start,
867+
frequency: 15,
868+
minimumBookingNotice: 0,
869+
eventLength: 15,
870+
dateRanges: [
871+
{
872+
start: day1Start,
873+
end: day2End,
874+
},
875+
],
876+
datesOutOfOffice,
877+
});
878+
879+
// Filter slots by day
880+
const day1Slots = slots.filter((slot) => slot.time.format("YYYY-MM-DD") === "2025-11-17");
881+
const day2Slots = slots.filter((slot) => slot.time.format("YYYY-MM-DD") === "2025-11-18");
882+
883+
// Day 1 slots should NOT be marked as away
884+
day1Slots.forEach((slot) => {
885+
expect(slot.away).toBeUndefined();
886+
});
887+
888+
expect(day2Slots.length).toBeGreaterThan(0);
889+
890+
// Day 2 slots should be marked as away
891+
day2Slots.forEach((slot) => {
892+
expect(slot.away).toBe(true);
893+
expect(slot.reason).toBe("Out of office");
894+
expect(slot.emoji).toBe("🏖️");
895+
});
896+
897+
vi.useRealTimers();
898+
});
843899
});

packages/features/schedules/lib/slots.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ function buildSlotsWithDateRanges({
122122
const slotBoundaries = new Map<number, true>();
123123

124124
orderedDateRanges.forEach((range) => {
125-
const dateYYYYMMDD = range.start.format("YYYY-MM-DD");
126125

127126
let slotStartTime = range.start.utc().isAfter(startTimeWithMinNotice)
128127
? range.start
@@ -182,8 +181,8 @@ function buildSlotsWithDateRanges({
182181
}
183182

184183
slotBoundaries.set(slotStartTime.valueOf(), true);
185-
186-
const dateOutOfOfficeExists = datesOutOfOffice?.[dateYYYYMMDD];
184+
const slotDateYYYYMMDD = slotStartTime.format("YYYY-MM-DD");
185+
const dateOutOfOfficeExists = datesOutOfOffice?.[slotDateYYYYMMDD];
187186
let slotData: {
188187
time: Dayjs;
189188
userIds?: number[];

0 commit comments

Comments
 (0)