1

I have a function that takes an array of objects, where each object contains a 'day' key (representing the day of the week) and an 'freeSlots' key (representing an array of available time slots as strings in 'h:mm a' format). The function aims to find and return the nearest valid free time slot from the current date and time. If no nearest slot is available for the current week, it should return "wait for next week." However, when searching for the nearest slot on Tuesday, the function is returning an unexpected result.

function findNearestFreeSlot(slotsArray) {
    const currentDate = moment();
    let nearestDayDiff = Infinity;
    let nearestSlot = null;

    for (const daySlots of slotsArray) {
        const { day, freeSlots } = daySlots;

        for (const slot of freeSlots) {
            const slotDateTime = moment(slot, 'h:mm a').day(day);

            // Check if the slot is on or after the current date
            if (slotDateTime.isSameOrAfter(currentDate)) {
                const diffDays = Math.abs(currentDate.diff(slotDateTime, 'days'));

                if (diffDays < nearestDayDiff || (diffDays === nearestDayDiff && slotDateTime.isBefore(nearestSlot))) {
                    nearestDayDiff = diffDays;
                    nearestSlot = slotDateTime;
                }
            }
        }
    }

    return nearestSlot ? nearestSlot.format('ddd, h:mm a') : "wait for next week";
}

I have used this array for testing the above function

const freeSlotsArray = [
    {
        day: 'wed',
        freeSlots: ['12:00 pm', '1:00 pm', '1:30 pm', '2:30 pm', '3:00 pm', '3:30 pm', '4:30 pm', '5:00 pm', '6:30 pm', '7:00 pm']
    },
    {
        day: 'sat',
        freeSlots: ['7:00 am', '7:30 am', '8:00 am', '9:00 am', '10:00 am', '10:30 am', '11:30 am', '12:00 pm', '12:30 pm']
    },
    {
        day: 'thu',
        freeSlots: ['12:00 pm', '1:00 pm', '1:30 pm', '2:30 pm', '4:00 pm', '5:30 pm', '6:30 pm', '7:00 pm']
    },
    {
        day: 'mon',
        freeSlots: ['4:00 pm', '4:30 pm', '6:00 pm', '6:30 pm', '7:30 pm', '8:00 pm', '8:30 pm', '9:30 pm']
    },
];


const nearestFreeSlot = findNearestFreeSlot(freeSlotsArray);
console.log(nearestFreeSlot);

When searching for the nearest slot on Tuesday, the expected output should be "Wed, 12:00 pm" instead of "Wed, 4:30 pm".

Aimal Khan
  • 13
  • 3

1 Answers1

0

The problem is that you pass a wrong parameter to .day(), pass it a number ranging from 0 to 6 (or the full name of the day, but I'm not sure how well this alternative works).

Below I put a more compact function and your correct one.

const fakeDay = 2; // 2 is Tuesday, change it for simulate a day sun: 0, mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6

function findNearestFreeSlot(slotsArray) {
  const currentDate = moment().day(fakeDay);
  let nearestDayDiff = Infinity;
  let nearestSlot = null;

  const indexDays = { sun: 0, mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6 }; // Add this index number: day

  for (const daySlots of slotsArray) {
    const { day, freeSlots } = daySlots;

    for (const slot of freeSlots) {
      const slotDateTime = moment(slot, 'h:mm a').day(indexDays[day]); // <---- use the index

      // Check if the slot is on or after the current date
      if (slotDateTime.isSameOrAfter(currentDate)) {
        const diffDays = Math.abs(currentDate.diff(slotDateTime, 'days'));

        if (diffDays < nearestDayDiff || (diffDays === nearestDayDiff && slotDateTime.isBefore(nearestSlot))) {
          nearestDayDiff = diffDays;
          nearestSlot = slotDateTime;
        }
      }
    }
  }

  return nearestSlot ? nearestSlot.format('ddd, h:mm a') : "wait for next week";
}


function findNearestFreeSlotMyTry(slotsArray) {
  const currentDate = moment().day(fakeDay);

  const indexDays = { sun: 0, mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6 };

  const listSlots = slotsArray
    .reduce((prev, { day, freeSlots }) => { // Converto the object of free slots in to array with the difference
      for (const slot of freeSlots) {
        const dateSlot = moment(slot, 'h:mm a').day(indexDays[day]);
        const diff = dateSlot.diff(currentDate);
        if (diff >= 0) prev.push({ diff, date: dateSlot.format('ddd, h:mm a') }); // Get elements only if is in the fucture
      }
      return prev;
    }, [])
    .sort((a, b) => a.diff < b.diff ? -1 : 1); //  sort the array by diff, from the nearlest to further

  return listSlots?.[0]?.date || 'wait for next week'; // Return the date or the string
}

const freeSlotsArray = [
  {
    day: 'wed',
    freeSlots: [/* '12:00 am', */ '12:00 pm', '1:00 pm', '1:30 pm', '2:30 pm', '3:00 pm', '3:30 pm', '4:30 pm', '5:00 pm', '6:30 pm', '7:00 pm']
  },
  {
    day: 'sat',
    freeSlots: ['7:00 am', '7:30 am', '8:00 am', '9:00 am', '10:00 am', '10:30 am', '11:30 am', '12:00 pm', '12:30 pm']
  },
  {
    day: 'thu',
    freeSlots: ['12:00 pm', '1:00 pm', '1:30 pm', '2:30 pm', '4:00 pm', '5:30 pm', '6:30 pm', '7:00 pm']
  },
  {
    day: 'mon',
    freeSlots: ['4:00 pm', '4:30 pm', '6:00 pm', '6:30 pm', '7:30 pm', '8:00 pm', '8:30 pm', '9:30 pm']
  }
];

const nearestFreeSlot = findNearestFreeSlot(freeSlotsArray);
console.log('-----> ', nearestFreeSlot);

const nearestFreeSlotMyTry = findNearestFreeSlotMyTry(freeSlotsArray);
console.log('-----> ', nearestFreeSlotMyTry);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
AlTheLazyMonkey
  • 1,190
  • 1
  • 8
  • 20
  • Thank you so much @AlTheLazyMonkey for your fantastic answer! Your explanation of the `findNearestFreeSlot` and `findNearestFreeSlotMyTry` functions and how it processes the `slotsArray` was extremely clear and helpful. I really appreciate your effort in breaking down the code step by step. Your solution has solved my problem perfectly! Thanks again for sharing your expertise – Aimal Khan Aug 02 '23 at 05:07