Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | 3x 3x 3x 9x 9x 63x 366x 9x 3x 3x 3x 3x 3x 52x 52x 52x 3x 14x 14x 14x 14x 5x 5x 5x 14x 3x 52x 13x 13x 13x 13x 14x 11x 11x 11x 10x 9x 13x | import { isSameDay, toMinutes } from '@repo/utils/date';
import { MeetingRoomBookedItem } from '@/hooks/useRoom';
export const BASE_HOURS = [
'08',
'09',
'10',
'11',
'12',
'13',
'14',
'15',
'16',
'17',
];
export const BASE_MINUTES = ['00', '15', '30', '45'];
export interface PickerItem {
value: string;
label: string;
}
export const generateHackData = (
baseArray: string[],
repeatCount = 5,
): PickerItem[] => {
const data: PickerItem[] = [];
for (let i = 0; i < repeatCount; i++) {
baseArray.forEach(item => {
data.push({
value: `${item}-${i}`,
label: item,
});
});
}
return data;
};
export const HOURS_DATA = generateHackData(BASE_HOURS);
export const MINUTES_DATA = generateHackData(BASE_MINUTES, 10);
export const ITEM_HEIGHT = 60;
export const PICKER_HEIGHT = 280;
export const minutesToTime = (mins: number): string => {
const h = Math.floor(mins / 60);
const m = mins % 60;
return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
};
export const getDefaultTimes = (date?: Date) => {
const today = new Date();
const isToday =
date &&
date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
let startMins = 480;
if (isToday) {
const totalMinutes = today.getHours() * 60 + today.getMinutes();
const nextHalfHourMinutes = Math.ceil(totalMinutes / 30) * 30;
startMins = Math.max(480, Math.min(1050, nextHalfHourMinutes));
}
return {
start: minutesToTime(startMins),
end: minutesToTime(Math.min(startMins + 30, 1065)),
};
};
export interface BookedRange {
start: number;
end: number;
}
/**
* Approved bookings for the selected room on the selected day, expressed as
* minutes from local midnight — the unit the time pickers work in.
*
* `start`/`end` are ISO 8601 UTC. Both the day comparison and the minute
* conversion happen in device local time so a booking never lands on the wrong
* day when the local day and the UTC day disagree.
*/
export const getBookedRanges = (
bookings: MeetingRoomBookedItem[] | undefined,
selectedDate: Date | string | undefined,
room: string | undefined,
): BookedRange[] => {
if (!bookings || !selectedDate || !room) return [];
const day = new Date(selectedDate);
Iif (Number.isNaN(day.getTime())) return [];
const ranges: BookedRange[] = [];
for (const booking of bookings) {
if (booking.status !== 'approved' || booking.data.room !== room) continue;
const start = new Date(booking.data.start);
const end = new Date(booking.data.end);
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) continue;
if (!isSameDay(start, day)) continue;
ranges.push({ start: toMinutes(start), end: toMinutes(end) });
}
return ranges;
};
|