Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript function to filter the "schedule" #141

Open
ArthurSmid opened this issue Nov 21, 2020 · 7 comments
Open

JavaScript function to filter the "schedule" #141

ArthurSmid opened this issue Nov 21, 2020 · 7 comments

Comments

@ArthurSmid
Copy link
Contributor

Write JavaScript function to filter the "schedule" table (a tab found along the menu bar in the Little Help Book Airtable) to display services available when the toggle is on. The schedule table is linked to the "Help Services" table, and the Hours of operation field.

The toggle is found on the category page, Basic Needs, Care, Education, Food, and the rest.

@ArthurSmid
Copy link
Contributor Author

ArthurSmid commented Nov 21, 2020

The schedule table has "name" and "description" fields linking records from the Help Services table to the schedule table. (Airtable is a relational database, allowing us to connect records from one spreadsheet to another in the same "base." Base is Airtable lingo for the database.) We're using something called RRule to enter the times, a format for notating recurring calendar days for schedule information. This list is all the fields in the schedule table:

id
name [linked record, connected to Help Services]
description [linked record, connected to Help Services]
Hours of operation (from description)
freq
byday
opens_at
closes_at
bymonthday
valid_from
valid_to

NOTE:

freq - how often the frequency repeats, for example DAILY, WEEKLY, MONTHLY.

byday - comma separated days of the week, SU,MO,TU,WE,TH,FR,SA. Where freq is MONTHLY each part can be preceded by a positive or negative integer to represent which occurrence in a month; for example, 2MO is the second Monday in a month, 3TH for third Thursday, -1FR is the last Friday.

bymonthday - comma separated numeric days of the month if frequency is MONTHLY. Can be negative to represent days before the end of the month; for example, -5 is the 5th to last day in a month.

valid_from and valid_to - for schedules with time (multiple months, for example) in which the service isn't available, this is only used on one or two records.

Airtable-schedule

@ArthurSmid
Copy link
Contributor Author

ArthurSmid commented Nov 21, 2020

If a service has multiple open and close times, each goes on it's own record, and that's why you'll see a few repetitions in the rows, for example, the times for Access the Law.

@ArthurSmid
Copy link
Contributor Author

A very rough draft, attempting to articulate the workings of the "schedule" table and begin a JavaScript function with pseudocode to filter the providers for all those with services available at the time a person switches the toggle.

We're using recurrence rules, RRule, to translate the "Hours of operation" descriptions into a shared (and Human Services Data Specification compatible) format for writing recurring calendar events. This issue has a screen shot of the schedule table above here.

To start, I'll introduce possible schedule “freq” variations:

  • weekly
    with a single open and close time for each day

  • weekly
    with different open and close times, either for the same day, such as when a service is closed for lunch, or different available hours for different days

  • daily
    this one is used for 24-hour a day, seven days a week, and the opens_at time is listed as 00:00 and closes_at 23:59

*monthly
on a recurring weekday, for example, the second Tuesday (2TU), third Friday (3FR), or last Saturday (-1SA)

*monthly
on a specific recurring calendar day every month, “the eleventh day of every month,” using the bymonthday field

The Available Now toggle filters the results of a specific category page (Basic Needs, Care, Education, and all the rest). Some things that come to mind for the function:

  1. add #schedule id to the Available Now toggle on the category.html page

  2. create an "available" variable and add an event listener:

let available = document.getElementById("schedule");

available.addEventListener("click", availableNow);

function availableNow () {
we need to know the calendar day and what time it is when the person triggers the function
getFullYear() Get the year as a four digit number (yyyy)
getMonth() Get the month as a number (0-11)
getDate() Get the day as a number (1-31)
getHours() Get the hour (0-23)
getMinutes() Get the minute (0-59)find the category page the person is on
only display providers in that category when displaying results

if the category name of a provider in the Help Services table matches the category-page-name of the page the person is on when they switch on the Available Now toggle

look for services available at all hours, every day

if opens_at 00:00 and closes_at 23:59
(and those service provider matches category the person is on), then display providers

check if the service is only available during some months of the year

and if the valid_from and valid_to fields have an entry
and the current month/day/year are after the valid_from date and before the valid_tothen check 
if the current day matches 
one of the days of week MO, TU, WE, TH, FR, SA, SU listed in the byday column 
and if the current time is after the opens_at time
but before the closes_at
then display those providers

check if the service is available at all times of the year

and for all the providers (the vast majority) that don’t have valid_from and valid_to fields if the day matches one of the days of week: MO, TU, WE, TH, FR, SA, SU
listed in the byday
and the current time is after the opens_at time
but before the closes_at
then display those providers

look for monthly recurring events by day of week

and if a number proceeds the day in the byday column (1TU signifies an event recurring on the first Tuesday)
and if a negative number 
(a number can be negative, for example -1SA is the last Saturday of every month)
then count the number of weeks to determine whether it's currently the 1st, 2nd, 3rd, 4th week
and if a number matches, check to see if the day matches
if the day matches 
check the opens_at and closes_at to see if it's currently available
then display providers

look for an event happening on a specific numbered day, for example, the eleventh day of every month

if 
the freq column in schedule is monthly 
and the current day matches the day in the bymonthday column
then display providers

display all providers using a subcategory.html style layout

@colindavey
Copy link
Contributor

colindavey commented Dec 9, 2020

I think at the heart of this is an isOpenAtTime() function that takes a time and a provider as parameters. You could pass any time in, though the main use case is passing in now. The functions returns true if the provider is open at the specified time, otherwise returns false.

pseudocode:

for each schedule row associated with the provider
  // Test if the time falls in the span specified by the schedule row
  if time falls between valid_from and valid_to (or if those fields are empty)
    if the day is in byday
      if the time is between opens_at and closes_at
        return true
return false

@colindavey
Copy link
Contributor

colindavey commented Dec 10, 2020

The following mocks the schedule items and has already pulled day, month, date, hours, minutes from a time. The full code will have to pull the schedule items for a provider from the table, decompose the time into the components, and then call this function.

A start at how to write this function:

let schedule_items = [
    {byday: "MO, TU, WE, TH, FR", opens_at: "08:00", closes_at: "12:00", valid_from: "", valid_to: ""},
    {byday: "MO, TU, WE, TH, FR", opens_at: "13:00", closes_at: "17:00"},
];

// Will need test cases with values in valid_from, and valid_to

let day = 4; 
let month = 11;
let date = 10;
let hours = 15;
let minutes = 30;

function isOpenAt(schedule_items, day, month, date, hours, minutes) {
   for (i = 0; i < schedule_items.length) { 
     if () {
      return true;
     }
   }
   return false;
}

// Alternate, but the break when finding a match is tricky. (https://stackoverflow.com/questions/2641347/short-circuit-array-foreach-like-calling-break)

function isOpenAt(schedule_items, day, month, date, hours, minutes) {
   schedule_items.forEach( item => 

   )
   return false;
}

@colindavey
Copy link
Contributor

PS one more thought: Instead of foror forEach loops, we can use a filter() function. The tests that occur during each iteration of the loop can be the function that gets handed to the filter() function. True means the results have at least one row, otherwise, false.

@colindavey
Copy link
Contributor

colindavey commented Dec 17, 2020

function isOpenAt(schedule_item, day, month, date, hours, minutes (or minute of day can replace hours&minutes)) {
  // Test if the time falls in the span specified by the schedule row
  if time falls between valid_from and valid_to (or if those fields are empty)
    if the day is in byday
      if the time is between opens_at and closes_at
        return true
  return false
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants