the-collab-lab / tcl-23-smart-shopping-list

1 stars 2 forks source link

List Items By Frequency Purchased #28

Closed jssckbl closed 3 years ago

jssckbl commented 3 years ago

Description

We added functionality in List.js so it can filter list items alphabetically. It can also move an item into one of 4 different lists based on how often it is purchased. The 4 groupings are:

To test for accessibility, we used WebAIM WAVE as a Chrome extension, as well as the VoiceOver option available on Mac.

Related Issue

closes #13 closes #29

Acceptance Criteria

Type of Changes

Type
:bug: Bug fix
āœ“ :sparkles: New feature
āœ“ :hammer: Refactoring
:100: Add tests
:link: Update dependencies
:scroll: Docs

Notes

UPDATE as of May 16, 2021: aria-label removed. It was unnecessary for this project at this time in assisting the screen reader.

Before

Items were listed in a seemingly random order. When the user entered an item into the list, there was no visual showing which grouping it had been put into.

frequencyItemsBefore

After

Items are now grouped based on frequency of purchase. Within each grouping, items are listed alphabetically.

frequencyItemsAfter

Testing Steps / QA Criteria

  1. On main run git pull

  2. Run git checkout jr-jw-list-items-by-frequency

  3. Run npm install

  4. Run npm start

  5. Once you are at https://localhost:3000, clear any existing tokens from your local storage. The screenshot below can assist you in clearing any tokens when using Chrome as your browser.

    clearLocalStorage
  6. Once you are on the main page, it is advised to create your own new token, and to add a few items to each of the 3 categories - soon (0-7), kind of soon (8-30), not that soon (30+). Don't forget to include capitalization and punctuation as well with the grocery list items you add.

  7. Once you have created a grocery list with various items in the green (0-7), purple (8-30) and red (30+) day categories, you will see that items in each grouping are alphabetized. Items with a checkmark that are gray are considered inactive and have been purchased in the last 24 hours, or have exceeded their assumed time frame of when they would be purchased again.

  8. We used the native VoiceOver function on a 2018 MacBook Air, running macOS Big Sur, Version 11.3.1 to test the screen reader. The following are directions to use that screen reader:

    • command + spacebar
    • type accessibility, enter
    • make sure that VoiceOver is highlighted (as seen below) accessibilityScreenReader

FINAL UPDATES

I have addressed ALL the AC and everything is working as intended. The only thing I have NOT completed is refactoring the WET code to be more DRY with a switch statement or anything like that.

Check out the screen shots to see that everything is rendering on the screen correctly, still alphabetized, even if some of the items are capitalized, and that the items become inactive under the AC's stated conditions.

color-coded-list

inactive-list

firebase-utc

Okay Friends, I have updated A LOT of the codebase here. The main thing that I did was to break down and use a package for DateTime called Luxon https://moment.github.io/luxon/docs/manual/tour.html

If you look at the Firebase screen shot above, I've underscored in pink the new UTC DateTime format. Apparently, this is the industry standard way to store times in databases. Luxon gives us a ton of ways to work with their DateTime object, and this one is achieved by .toString().

// use DateTime package to get current time
const now = DateTime.now();

// convert now to readable ISO string
const nowToString = now.toString();

I am still storing the last_estimate as an integer representing days, which is total milliseconds divided by const millisecondsInADay = 86400000;

// because last_estimate is an integer representing days, convert now to days
const nowInDays = Math.floor(now.ts / millisecondsInADay);

// do the same conversion for last_purchased
const lastPurchasedToDays = Math.floor(
   DateTime.fromISO(itemData.last_purchased).ts / millisecondsInADay,
);

So now we have a more readable timestamp in the database, and still able to compare last_estimate by days.

compareTimeStamp(), which determines whether or not a checkmark stays checked or not is completely revamped:

 function compareTimeStamps(lastPurchased) {
    // first check to see if lastPurchased === null in database
    if (lastPurchased === null) {
      return false;
    }
    // use DateTime package to get current time
    const now = DateTime.now();

    // initialize how many milliseconds there are in a day for calculation
    const millisecondsInADay = 86400000;

    // convert now to days
    const nowInDays = Math.floor(now.ts / millisecondsInADay);

    // do the same conversion for last_purchased as lastPurchased
    const lastPurchasedToDays = Math.floor(
      DateTime.fromISO(lastPurchased).ts / millisecondsInADay,
    );

    return nowInDays - lastPurchasedToDays === 0;
}

An item in the database which is less than 24 hours old will remain checked, but now it's MUCH easier to follow the logic in the function and the properties in Firestore

Another feature I successfully implemented is the accessibility/screen-reader working correctly. Instead of using aria-label, I opted for <label>. I still have FOUR different filters and maps, but here is an example of one of them:

.map((doc) => (
   <li
     key={doc.id}
     className="checkbox-wrapper"
    style={{ color: 'green' }}
  >
    <input
      type="checkbox"
      id={doc.id}
      defaultChecked={compareTimeStamps(
        doc.data().last_purchased,
      )}
      disabled={compareTimeStamps(doc.data().last_purchased)}
        onClick={(e) => markItemPurchased(e, doc.id, doc.data())}
    />
   <label htmlFor={doc.id}>{doc.data().item_name}</label>
  </li>
))}

I updated the id to use id={doc.id} mirrored by the htmlFor={doc.id}. And now the screen reader knows which check box to associate with which {doc.data().item_name}.

Conclusion

I think we are good to go to merge. Please let me know if you see anything I can fix/update! If you test this branch with the live Github link, make sure to start with a new token so the data in Firestore is not stale.

I have added a ton of comments that I hope clarify the code, but if there isn't anything you don't understand, let me know!

github-actions[bot] commented 3 years ago

Visit the preview URL for this PR (updated for commit da30683):

https://tcl-23-shopping-list--pr28-jc-jw-list-items-by-4q92q112.web.app

(expires Sat, 29 May 2021 14:57:54 GMT)

šŸ”„ via Firebase Hosting GitHub Action šŸŒŽ

jamesncox commented 3 years ago

I think we are ready for approval!

skylerwshaw commented 3 years ago

To test for accessibility, we used WebAIM WAVE as a Chrome extension, as well as the VoiceOver option available on Mac.

tenor

skylerwshaw commented 3 years ago

NB: There is a lot of use of "I" in the PR comments above. As a group effort and also since it's unclear who's communicating, 'we' may be more appropriate.

I've underscored in pink the new UTC DateTime format

The image shows a timestamp with a UTC offset but is not UTC itself. And yes it's definitely best to use ISO-8601 timestamps! šŸ‘

skylerwshaw commented 3 years ago

There is a lot of logic within the presentational JSX of src/pages/List.js that is making it difficult to understand the changes being made. Typically logic is extracted from the JSX render/return to functions and variables within the component to keep the visual presentation code clean. Depending on team time, you might be doing your reviewers and your future self a big benefit by taking some time to not change the logic, but refactor it for legibility.

cc @jssckbl @jamesncox

jamesncox commented 3 years ago

@skylerwshaw regarding the issue about logic in JSX I 100% agree with you, but the problem was the the logic being processed outside the return statement before the connection to Firebase could be fully established, thus throwing an error (I believe an undefined error). I suppose I could create four different functions that I call in the return statement, one for each filter. Which would be a bit more readable. Can we escalate that to a different, yet-to-be-created issue?

jamesncox commented 3 years ago

@skylerwshaw requesting another review! I have extracted all of the logic out of the return and even DRYed up the render of the four unordered lists. Thanks!