Home > Mobile >  How to create an array with time slots based on preexisting data with javascript
How to create an array with time slots based on preexisting data with javascript

Time:12-24

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

CodePudding user response:

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.

CodePudding user response:

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.

CodePudding user response:

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

  • Related