๐ŸŽ“ Advanced Booking App Tutorial (Step-By-Step)

Whatโ€™s up Gliders!

Thought Iโ€™d share my latest free tutorial for those that might be interested.

:popcorn: ๐—”๐—ฏ๐—ผ๐˜‚๐˜ ๐—ง๐—ต๐—ถ๐˜€ ๐—ง๐˜‚๐˜๐—ผ๐—ฟ๐—ถ๐—ฎ๐—น :popcorn:
This tutorial is an in-depth, step-by-step, tutorial that shows you how to build an advanced booking app from scratch in Glide.

:nerd_face: ๐—ฆ๐˜๐—ฎ๐˜† ๐—™๐—ผ๐—ฐ๐˜‚๐˜€๐—ฒ๐—ฑ :nerd_face:
Sprinkled throughout this tutorial are countless insider tips, strategies, code snippets and techniques that will take your Glide skills to the next level. So grab a coffee, get comfy, stay focused, and enjoy!

:raising_hand_man: ๐—ช๐—ต๐—ผ ๐—œ๐˜€ ๐—ง๐—ต๐—ถ๐˜€ ๐—™๐—ผ๐—ฟ :raising_hand_woman:
Anyone who wants to level up their skills. This tutorial is long, but because itโ€™s built on a free plan and is step-by-step (with an optional cheat sheet) I encourage all Gliders to give it a shot, no matter what skill level you are :muscle:

:rotating_light: ๐—จ๐—ฝ๐—ฑ๐—ฎ๐˜๐—ฒ๐˜€ :rotating_light:
#๐Ÿญ - I have upgraded the JavaScript snippet that is used in the Validation/Template column so it now allows the last slot of the day to be booked, and removes any Timeslots for the current day that have already passed. You can find the updated code below.

#๐Ÿฎ - If you use a time increment larger that 15 minutes (e.g. 30 or 60) you will need to create a filter on the settings page to ensure that the values you can select as the Open/Close time for each day are less than 1440. To do this, just add a the following filter to both choice components: Timeslot/Value is less than 1440.

๐—จ๐—ฝ๐—ฑ๐—ฎ๐˜๐—ฒ๐—ฑ ๐—๐—ฎ๐˜ƒ๐—ฎ๐˜€๐—ฐ๐—ฟ๐—ถ๐—ฝ๐˜:

const Check = "p7";

if(Check === "NaN"){ return "No date selected."};

const AS = [p1];
const TS = [p2];
const BS = [p3];
const BD = parseInt("p4", 10);
const DS = parseFloat(("p5" / 1440).toFixed(4))
const DE = parseFloat(("p6" / 1440).toFixed(4))
const SD = p7;

const date = new Date();
const [year, month, day] = [date.getFullYear(), date.getMonth() + 1, date.getDate()];
const today = year * 10000 + month * 100 + day;

let currentTimeFraction = SD === today
    ? (date.getHours() * 60 + date.getMinutes()) / 1440
    : 0;

const FrS = BS.filter(s => s >= DS && s <= DE && s >= currentTimeFraction && !TS.includes(s));

const VS = FrS.filter(s => {
    const SE = parseFloat(((Math.round(s * 1440) + BD) / 1440).toFixed(4));
    return AS.filter(ss => ss >= s && ss < SE).every(ss => FrS.includes(ss));
}).map(s => s.toFixed(4));

return VS.length ? VS.join(",") : "No availability on this date.";

๐—ง๐—ฒ๐—บ๐—ฝ๐—น๐—ฎ๐˜๐—ฒ ๐—ฉ๐—ฎ๐—ฟ๐—ถ๐—ฎ๐—ฏ๐—น๐—ฒ๐˜€ & ๐—ฉ๐—ฎ๐—น๐˜‚๐—ฒ๐˜€:
โ†ณ p1 = Validation/All Slots
โ†ณ p2 = Validation/Taken Slots
โ†ณ p3 = Validation/Barber Slots
โ†ณ p4 = Service/Duration
โ†ณ p5 = Trading Hours/Start
โ†ณ p6 = Trading Hours/End
โ†ณ p7 = Booking/Date โ†’ ID

9 Likes

Thank you for sharing. I will check it

1 Like

Youโ€™re welcome! Go for it :muscle:

Hi, can you please show where can I get the codes you are using throughtout the video?

Hi, thanks for the tutorial, I need help the โ€œValidation/Valid Slotsโ€ because it always gives me โ€œNo availability on this date.โ€ no matter what I put in the other columns. I donโ€™t understand.

Please show us what you have configured so far in screenshots or a video.

(post deleted by author)

https://youtu.be/sKL1g8uKDg4
If you need another video tell me

Can you copy your whole value of โ€œValidation/Templateโ€ (the value not the original function) so I can check if thereโ€™s an issue?

Maybe you can try this to see if it helps.

const Check = "p7";

if(Check === "NaN"){ return "No date selected."};

const AS = [p1];
const TS = [p2];
const BS = [p3];
const BD = parseInt(p4, 10);
const DS = parseFloat((p5 / 1440).toFixed(4))
const DE = parseFloat((p6 / 1440).toFixed(4))
const SD = p7;

const date = new Date();
const [year, month, day] = [date.getFullYear(), date.getMonth() + 1, date.getDate()];
const today = year * 10000 + month * 100 + day;

let currentTimeFraction = SD === today
    ? (date.getHours() * 60 + date.getMinutes()) / 1440
    : 0;

const FrS = BS.filter(s => s >= DS && s <= DE && s >= currentTimeFraction && !TS.includes(s));

const VS = FrS.filter(s => {
    const SE = parseFloat(((Math.round(s * 1440) + BD) / 1440).toFixed(4));
    return AS.filter(ss => ss >= s && ss < SE).every(ss => FrS.includes(ss));
}).map(s => s.toFixed(4));

return VS.length ? VS.join(",") : "No availability on this date.";

I tried the code you sent me, there is no longer the message โ€œNo availability on this date.โ€ but there are still no remaining slots for the day.

const Check = "p7";

if(Check === "NaN"){ return "No date selected."};

const AS = [p1];
const TS = [p2];
const BS = [p3];
const BD = parseInt("p4", 10);
const DS = parseFloat(("p5" / 1440).toFixed(4))
const DE = parseFloat(("p6" / 1440).toFixed(4))
const SD = p7;

const date = new Date();
const [year, month, day] = [date.getFullYear(), date.getMonth() + 1, date.getDate()];
const today = year * 10000 + month * 100 + day;

let currentTimeFraction = SD === today
    ? (date.getHours() * 60 + date.getMinutes()) / 1440
    : 0;

const FrS = BS.filter(s => s >= DS && s <= DE && s >= currentTimeFraction && !TS.includes(s));

const VS = FrS.filter(s => {
    const SE = parseFloat(((Math.round(s * 1440) + BD) / 1440).toFixed(4));
    return AS.filter(ss => ss >= s && ss < SE).every(ss => FrS.includes(ss));
}).map(s => s.toFixed(4));

return VS.length ? VS.join(",") : "No availability on this date.";

So did you use the code I sent or the one that you pasted above? Your version still has p4, p5, p6 inside brackets so thought I should ask.

I was asking for the final โ€œvalueโ€ of the column, not the original formula. I want to run a check mysefl.

I donโ€™t really understand what you want but I can invite you to my team so that you can have direct access to the data and understand whatโ€™s wrong.
Iโ€™ll send you a private message with the invitation.

He wants you to click on a cell and copy the javascript that way. Donโ€™t click on Edit to change the column, just click on a cell in one of your rows and copy whatever value that template column produced. It should be the javascript with all of the p values replaced with actual values.

I think Iโ€™ve got it, isnโ€™t it? this is the code you sent me

const Check = "20250725";

if(Check === "NaN"){ return "No date selected."};

const AS = [0.0000, 0.0104, 0.0208, 0.0313, 0.0417, 0.0521, 0.0625, 0.0729, 0.0833, 0.0938, 0.1042, 0.1146, 0.1250, 0.1354, 0.1458, 0.1563, 0.1667, 0.1771, 0.1875, 0.1979, 0.2083, 0.2188, 0.2292, 0.2396, 0.2500, 0.2604, 0.2708, 0.2813, 0.2917, 0.3021, 0.3125, 0.3229, 0.3333, 0.3438, 0.3542, 0.3646, 0.3750, 0.3854, 0.3958, 0.4063, 0.4167, 0.4271, 0.4375, 0.4479, 0.4583, 0.4688, 0.4792, 0.4896, 0.5000, 0.5104, 0.5208, 0.5313, 0.5417, 0.5521, 0.5625, 0.5729, 0.5833, 0.5938, 0.6042, 0.6146, 0.6250, 0.6354, 0.6458, 0.6563, 0.6667, 0.6771, 0.6875, 0.6979, 0.7083, 0.7188, 0.7292, 0.7396, 0.7500, 0.7604, 0.7708, 0.7813, 0.7917, 0.8021, 0.8125, 0.8229, 0.8333, 0.8438, 0.8542, 0.8646, 0.8750, 0.8854, 0.8958, 0.9063, 0.9167, 0.9271, 0.9375, 0.9479, 0.9583, 0.9688, 0.9792, 0.9896, 1.0000, 1.0104];
const TS = [0.3750, 0.3854, 0.3958, 0.4063, 0.4167, 0.4271, 0.4375, 0.4479, 0.4583, 0.4688, 0.4792, 0.4896];
const BS = [0,5104];
const BD = parseInt(180 Mins, 10);
const DS = parseFloat((540 / 1440).toFixed(4))
const DE = parseFloat((1140 / 1440).toFixed(4))
const SD = 20250725;

const date = new Date();
const [year, month, day] = [date.getFullYear(), date.getMonth() + 1, date.getDate()];
const today = year * 10000 + month * 100 + day;

let currentTimeFraction = SD === today
    ? (date.getHours() * 60 + date.getMinutes()) / 1440
    : 0;

const FrS = BS.filter(s => s >= DS && s <= DE && s >= currentTimeFraction && !TS.includes(s));

const VS = FrS.filter(s => {
    const SE = parseFloat(((Math.round(s * 1440) + BD) / 1440).toFixed(4));
    return AS.filter(ss => ss >= s && ss < SE).every(ss => FrS.includes(ss));
}).map(s => s.toFixed(4));

return VS.length ? VS.join(",") : "No availability on this date.";

I checked the app. your problem is here.

const BS = [0.5104];

The app filters the available slots based on your available Barber Slots, and it is looking for a 180-minute (3-hour) continuous slot.

If โ€ŽBS only contains โ€Ž[0.5104], there is no way to find a 3-hour window.

I tried populating your Barber table with this value of available slots:

0.3750, 0.3854, 0.3958, 0.4063, 0.4167, 0.4271, 0.4375, 0.4479, 0.4583, 0.4688, 0.4792, 0.4896, 0.5000, 0.5104, 0.5208, 0.5313, 0.5417, 0.5521, 0.5625, 0.5729, 0.5833, 0.5938, 0.6042, 0.6146, 0.6250, 0.6354, 0.6458, 0.6563, 0.6667, 0.6771, 0.6875, 0.6979, 0.7083, 0.7188, 0.7292, 0.7396, 0.7500, 0.7604, 0.7708, 0.7813

Then it works correctly.

Great! Thank you so much! I didnโ€™t understand that at all. You save me !

1 Like

Great to hear! Congrats!

1 Like

i have another question, iโ€™m 2:24 into the video, and when i make a reservation, it goes to today instead of the right date. iโ€™d like to understand why?

Thanks for the great tutorial. I have followed it today and nearly got it all working - just testing now. For some reason, itโ€™s not showing the right timeslots. I have one booking which is taking up 3 timeslots - 10am, 10:30am and 11am - on 2nd August. When I go to book on another date, those timeslots are not showing as available. It seems to be missing a bit of logic around date. Any clues?

Single Booking:

Booking form showing Taken Slots:

Booking on another dates but not showing times which should be available: