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

Allow user to join an existing shopping list #21

Merged
merged 14 commits into from
Apr 23, 2023

Conversation

jongranados
Copy link
Collaborator

@jongranados jongranados commented Apr 19, 2023

Description

This PR allows users to join existing shopping list so they can manage them with friends or family. This functionality takes the following steps:

  1. The user enters a three word token existing token into a form on the home page.
  2. The token is saved to localStorage.
  3. The user is taken to the List view and shown the existing list.
  4. If the list does not exist, the user sees an alert stating that the list does not exist.

The alert is generated here with Toastify which might present some accessibility concerns. The dev team will likely want to discuss the best route for generating alerts throughout the app.

Related Issue

Closes #5.

Acceptance Criteria

If a user doesn’t already have a token:

  • The Home view shows a form that allows the user to enter a token to join an existing list, in addition to the button that allows them to create a new list.
  • The input that accepts the list token has a semantic label element associated with its
  • The user can submit this form with both the mouse and the Enter key
  • If the list exists,
    • the token is saved in localStorage
    • the user is redirected to the List view and shown the items on that list
  • If the list does not exist, the user is shown an error message that explains the problem

If a user does already have a token:

  • They are automatically redirected to the List view.

Type of Changes

Type
🐛 Bug fix
✨ New feature
🔨 Refactoring
💯 Add tests
🔗 Update dependencies
📜 Docs

Updates

Before

This screenshot shows the application's home page before this functionality was implemented; there was no way for the user to join an existing shopping list unless an existing list's respective token was already stored in their browser's local storage.

before

After

This screenshot show the application's home page after this functionality was implemented; a new user is given the option to either create a brand new list or join an existing list with the submission of a valid three word token.

after

This video demonstrates a user attempting to access an existing list. They first attempt to access a list associated with token this should fail. Because such a token does not exist in the database, they are notified of their failed attempt through a pop-up message that reads: "Sorry, this list does not exist." The user then attempts to access a list with token my test list. Because this token does exist, the user is presented with the grocery items associated with this token.

after.mov

Testing Steps / QA Criteria

  • Launch application:
  • Clear your browser local storage of a pre-existing tcl-shopping-list-token
  • Navigate home (/)
  • Attempting to submit an invalid token such as this should fail should:
    • keep you on the home page (/)
    • display a pop-up that reads: "Sorry, this list does not exist."
    • not result in a tcl-shopping-list-token inside your browser's local storage
  • Attempting to submit a valid token such as my test list should:
    • redirect you to the list page (/list)
    • render the items in your list
    • save the validated token inside your browser's local storage under tcl-shopping-list-token

@github-actions
Copy link

github-actions bot commented Apr 19, 2023

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

https://tcl-57-smart-shopping-list--pr21-es-jg-join-existing-1hai28xb.web.app

(expires Sat, 29 Apr 2023 16:17:10 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: ad3eb6c34c2ec5986fcc218178df5985eb9c9ffb

@emilysellers emilysellers changed the title Es jg join existing list Allow user to join an existing shopping list Apr 19, 2023
emilysellers and others added 5 commits April 20, 2023 17:36
- remove setting token to empty string in local storage on failed token validation
- remove redundant update to tokenExist state variable on failed token validation
@jongranados jongranados marked this pull request as ready for review April 21, 2023 20:05
Copy link
Collaborator

@Amy-Pr Amy-Pr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks super great guys! We tested it from the preview link. Works as expected. I even used a token name saved in Beth's browser, and was able to bring up her list on my end! Awesome job!!!

*/
export async function validateToken(userTokenInput) {
const listCollectionRef = collection(db, userTokenInput);
const listSnapshot = await getDocs(listCollectionRef);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious how line 23 and 24 work together? We looked up the firebase "getDocs" function. Still a little fuzzy on how it all works.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Amy! If I'm understanding things correctly, accessing data from a firestore db is a two-part process. You first get a reference to a collection in the db using the collection method. I like to think of this like requesting an address. And with that reference, you're then able to actually query the db using getDocs to take "snapshots" of the db state at a particular instance in time. I like to think of this like a camera taking a picture of the db and capturing its state at an instance in time.

Still hazy with all of this myself though so I'm not sure this is completely right.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great explanation!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great explanation- thank you @jongranados !

Copy link
Collaborator

@djtaylor8 djtaylor8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, @jongranados and @emilysellers! I definitely think it is worth talking about the accessibility issues with everyone on the team with regards to using the Toastify library. Otherwise, the functionality is working as expected!

@@ -15,6 +15,16 @@ export function streamListItems(listId, handleSuccess) {
return onSnapshot(listCollectionRef, handleSuccess);
}

/**
* Check existence of list in Firestore associated with user token input.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the documentation here!


export function Home({ setListToken }) {
const [userTokenInput, setUserTokenInput] = React.useState('');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggesting again - import { useState } from 'react' as opposed to React.useState. Not a blocker, but a bit cleaner IMO.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, forgot about this! Done. Definitely cleaner!

Copy link
Collaborator

@mxmason mxmason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! One optional idea for an optimization before we ship.

Comment on lines +22 to +26
export async function validateToken(userTokenInput) {
const listCollectionRef = collection(db, userTokenInput);
const listSnapshot = await getDocs(listCollectionRef);
return !listSnapshot.empty;
}
Copy link
Collaborator

@mxmason mxmason Apr 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function works exactly as intended, but I have an optimization mission, should you choose to accept it.

Before we get to the question "does this list exist on the server?", we know our tokens have to be two things:

  1. non-empty, and
  2. a specific shape

Can we use this knowledge to check for validity and return early without wasting time and resources on a request to our database?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agh, such a great point EJ! I'll incorporate that now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, before doing so I want to ask a question at today's sync. Going to merge to main for now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point, EJ! It would be great to talk this over today.

<button type="button" onClick={handleClick}>
Create New List
Create new list
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yesssss! I'm such a fan of removing unnecessary title case from our UIs!

Copy link
Collaborator

@danainjax danainjax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent job on this issue. I especially liked the explicit and complete pr, and the step by step instructions on how to test, and what you considered re: toastify and there may need to be discussion regarding tradeoffs or approach. Fantastic!

Copy link
Contributor

@bethmelmtv bethmelmtv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @emilysellers and @jongranados ! Everything's working :) Awesome job!

@jongranados jongranados merged commit 71eb7e4 into main Apr 23, 2023
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5. As a user, I want to join an existing shopping list so I can share a shopping list with another person
7 participants