All files / apps/roomBooking/src/screens/ChooseTime utils.ts

97.72% Statements 43/44
95.83% Branches 23/24
100% Functions 5/5
100% Lines 38/38

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;
};