0

I am making an app for my thesis an I need help with a specific problem I am trying to solve. Let me describe the functionality i want to achive first.

In my front end I want the user to able to pick an appointment date and time. The way I am thinking to do this is to have him pick a specific date. When he submits the date I want to generate an array of available time slots in the following way.

In my db I have shop objects. Each shop has an array of appointmetns. Each appointment has a starting hour and an ending hour. For reasons of simplicity I am having the time slot set to 30 minutes for every appointment eg if the starting hour is 14:00 the ending hour is 14:30. So after the customer submits the date I retrieve with a query all the appointments for that specific date. My shops are, again for simplicity open every day from 8:00 to 21:00.

With that in mind I want to create an array that starts from 8:00 ends at 21:00 and the interval is thirty minutes. But I want to dynamicaly create this array based on the existing appointments meaning that if there is an appointment starting at 14:30 the time slot 14:30 - 15:00 will not be inserted in the array.

I have a crud way of doing this by hardcoding an array with all timeslots from 8:00 to 9:00 and then an array dynamicaly with appointment timeslots. Then i make a third array by filtering the to arrays. I would your help to find a way to do this more dynamicaly in order to have different opening times across shops and different time duration for each appointment in the feature.

E.G

const shop = {
    user: "fakeid123",
    title: "Barber Shop",
    description: "fake description",
    appointments: [{
            customername: "Kostas",
            start: "12:00",
            end: "12:30"
        },
        {
            customername: "Makis",
            start: "13:00",
            end: "13:30"
        },
        {
            customername: "Kostas",
            start: "14:00",
            end: "14:30"
        },
        {
            customername: "Kostas",
            start: "17:00",
            end: "17:30"
        }
    ],
    opens: "8:00",
    closes: "21:00"
};

Base on the example above the array should be :

[
    8: 00 - 8: 30
    8: 30 - 9: 00
    9: 00 - 9: 30
    9: 30 - 10: 00
    10: 30 - 11: 00
    11: 00 - 11: 30
    11: 30 - 12: 00
    12: 30 - 13: 00
    13: 30 - 14: 00
    14: 30 - 15: 00
    15: 00 - 15: 30
    ....
    16: 30 - 17: 00
    18: 00 - 18: 30
    ...
    20: 30 - 21: 00
]

The timeslots 12:00-12:30 13:00-13:30 14:00-14:30 and 17:00-17:30 are not in the array

I am doing it this way in order to present the customer with a drop down menu with available time slots to pick.

The start and end fields are string but are time formats. How can I iterate over them to create the array? Thanks in advance

3 Answers 3

1

You're provided a time range with shop.opens and shop.closes. This is a very good point to start with. You can generate other time ranges for appointments from this. Think of it this way :

function generateAppointments(shop) {
    let appointments = [];
    let [hoursOp, minutesOp] = shop.opens.split(":"); //here you retrieve hours and minutes from your input string
    let [hoursCl, minutesCl] = shop.closes.split(":");
    let timeRange = Number.parseInt(hoursCl) - Number.parseInt(hoursOp);

    for (let i = 0; i < timeRange; i++) { //here you iterate for the whole range of hours you are given
        const appHourStart = Number.parseInt(hoursOp) + i;
        //here you check if the appointment is already booked
        //this is a lot of iteration, maybe you could find a better way to approach this
        //I made it what with came to my mind first
        const firstHalfBooked = shop.appointments.some(a => a.start === `${appHourStart}:00`); 
        const secondHalfBooked = shop.appointments.some(a => a.start === `${appHourStart}:30`);

        //here, you only create a array element if the spot isn't booked
        if(!firstHalfBooked) appointments.push(`${appHourStart}:00 - ${appHourStart}:30`);
        if(!secondHalfBooked) appointments.push(`${appHourStart}:30 - ${appHourStart+1}:00`);
    }

    console.log (appointments);
    return appointments;
}

Hope this helps, and you can understand it.

Edit: I kept the minutes for the "opens" and "closes" field so you can anticipate in case a shop opens say at 8:30.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks This helped a lot ! I made some changes that allow me to create an all slots table from opening to closing.And then I can do the same for the appointmets and filter out all the non available time slots and send the final array to the front end ! Thanks a lot !
1

In case you have an array of reserved slots and want to get an array of available slots, you need an array of all slots anyway (reserved as well as available ones). It's possible to iterate over the array of all slots filtering out the reserved slots presented in another array, but it doesn't seem very efficient.

I'd like to suggest a different approach: have an array of all slots (all of them are available for the reserve by default), and then just use a simple flag to indicate whether the slot is reserved or not. This will allow us to easily filter the original array and get an array of free slots or reserved slots, depending on which one you currently need:

const shop = {
  user: "fakeid123",
  title: "Barber Shop",
  description: "fake description",
  opens: new Date('2010-01-01T08:00:00Z'),
  closes: new Date('2010-01-01T21:00:00Z'),
  slotDuration: 30 * 60000
};

shop.slots = generateSlots(shop.opens, shop.closes, shop.slotDuration);

reserveSlot("14:00-14:30", 'Customer 1');
reserveSlot("10:00-10:30", 'Customer 2');
reserveSlot("15:30-16:00", 'Customer 3');
reserveSlot("19:00-19:30", 'Customer 4');

console.log('RESERVED', getFilteredSlots(true));
console.log('AVAILABLE', getFilteredSlots(false));

function generateSlots(startTime, endTime, duration) {
  const allSlots = [];
  let slotStart = startTime;

  do {
    const slot = {
      start: slotStart,
      end: new Date(slotStart.getTime() + duration),
      reserved: false
    };
    slot.id = `${slot.start.getUTCHours()}:${slot.start.getUTCMinutes() || '00'}-${slot.end.getUTCHours()}:${slot.end.getUTCMinutes() || '00'}`;
    
    allSlots.push(slot);
    slotStart = slot.end;
  } while (slotStart < endTime);

  return allSlots;
}

function reserveSlot(slotId, customerName) {
  const result = shop.slots.map(slot => slot.id === slotId ? {...slot, customerName, reserved: true} : slot);
  shop.slots = result;
}

function getFilteredSlots(isReserved) {
  return shop.slots.filter(slot => slot.reserved === isReserved);
}

P.S: I also used Date type instead of a regular string because it's easier to generate lists like the one from generateSlots function.

1 Comment

Thanks for you solution ! I will use your logic about having an array of all time slots and a reserved slots and I will use this in combination with a solution another user suggested. I want to avoid having flags (for now) so I wont have to make changes to my Models and API. Thanks Again :)
0

The easiest way is to use lodash library. It provides many array functions.

The one that you are looking for is _.xor

https://lodash.com/docs/4.17.15#xor

var timeTable = [];
for(let i = 8; i < 21; i++){
    timeTable.push(`${i}:00-${i}:30`);
    timeTable.push(`${i}:30-${i+1}:00`);
}

var myAppointments = ['8:00-8:30', '8:30-9:00', '9:00-9:30', '9:30-10:00', '10:00-10:30', '10:30-11:00', '11:00-11:30', '11:30-12:00', '12:30-13:00', '13:30-14:00', '14:30-15:00', '15:00-15:30', '15:30-16:00', '16:00-16:30', '16:30-17:00', '17:30-18:00', '18:00-18:30', '18:30-19:00', '19:00-19:30', '19:30-20:00', '20:00-20:30', '20:30-21:00'];

var myFreeTime = _.xor(myAppointments, timeTable);

myFreeTime.forEach((time) => document.getElementById("time").insertAdjacentHTML('beforeend', `${time}<br />`))

See example: https://jsfiddle.net/domus71/1n0voakc/

Kostis

1 Comment

_.xor([reserved_array2],[all_available_array1]);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.