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

Nk tr create tokenized list #24

Merged
merged 34 commits into from
May 17, 2020
Merged

Nk tr create tokenized list #24

merged 34 commits into from
May 17, 2020

Conversation

nabilkaz
Copy link
Contributor

@nabilkaz nabilkaz commented May 15, 2020

Description

The PR adds routing logic at / root, a library for handling tokens on the client, a SignIn page component for creating a list, functionality in getList.js and addItem.js to get and create lists based on the clients token and functional css styling to style SignIn.

We accomplished this by breaking the problem down into the following logic:

  1. When rendering / root check if client has token in localStorage
  2. if client...
    • does have token render ./list-view else show sign in page with option to enter share code or create new list.
    • doesn't have token render SignIn.
      • when user clicks create a new list then add token to their localStorage and route user to ./add-item
      • When user adds an item use token value as the collection name.
      • When item is added it will create a collection in firestore with the token name and add the new document (shopping item).
  3. When navigating to ./list-view if token exists on firestore it should render that list.

What is localStorage?

We researched localStorage via the MDN documentation that allows you to use the Storage object to store data across browser sessions. By using the method setItem(key, value) you can store a key-value pair that will persist across sessions.

Here is a video review of using localStorage (unfortunately there's no sound but you actually don't need it. Nabil walks through viewing, setting and retrieving localStorage values in the console): https://www.loom.com/share/9870282bd78049599e7a701381d4e525

New token functions

We added set, get, and has functions to token.js. We used the naming convention [type]LocalToken because it denotes both where it is localStorage and what it is token. It may have been better to use Client which isn't dependent on how we did it (if we stored it differently on the client).

  • setLocalToken - stores a String value generated by getToken and stores it in the localStorage under the key token
  • getLocalToken - retrieves the string value of the token stored on the client
  • hasLocalToken - returns a boolean depending on whether a token is found on the client or not.

Token-based routing logic at root /

We use token-based authentication to grant list access to users and have it persist through multiple browser sessions. This is accomplished by generating a token (using getToken found in ./lib/token.js) and setting it in the localStorage of the Client. We then use this reference to perform several tasks:

  • Use the token stored in localStorage to create a shopping list when a new item is made and to retrieve collections.
  • The logic for deciding whether to show a signin or list-view page is based on whether a token is found in the Clients localStorage.

Creating and Reading collections

Our application now has the CR of CRUD (Create, Read, Update, Delete).

  • The token value stored on client is used in getList.js and addItem.js to retrieve and create collections in firebase.

🔥Learning that took us a while -> Firebase implicitly creates collections. 🔥

We got hung up on how to create a new collection. We first assumed that we had to create it by adding a new collection via the fb object but after reading the documentation on data modeling there is a line that explicitly states:

Collections and documents are created implicitly in Cloud Firestore. Simply assign data to a document within a collection. If either the collection or document does not exist, Cloud Firestore creates it.

Which means if we use a name not represented by a collection in firebase when adding a document it will implicitly create a collection of that name in the database.

// ./src/components/addItem.js
// add item function
...
    const db = fb.firestore();
    db.collection('items').add({
    db.collection([NEW-NAME-NOT-IN-FIREBASE]).add({   // results in new collection
      itemName: this.state.itemName,
    });
...

CSS styling for sign-in page

We took a functional approach to CSS (basing it off of tachyons https://tachyons.io/). This means instead of describing the object in CSS. IE - building out a card class that has shadow, background color, etc. You build a drop-shadow class and bg-blue class and apply each class to the HTML element to style each part.

Pros: It makes it much easier to get in and style new elements once you understand the class syntax.
Cons: Functional CSS can be very atomic so you don't get the simplicity of using a single card class (but that's what React components are for right?) and you must be familiar with the stylistic syntax.

Here's a video walkthrough of using functional CSS: https://www.loom.com/share/c2f3290a268f4df9b2b3fa6d3e4b20a9

Accessibility updates

Ran the accessibility extension and found two errors:

  1. Gray in the sample app (#999999) doesn't pass the accessibility checker (which requires a 4.5 rating). Replaced with #767676 which has a 4.54 contrast ratio rating.
    image
    image

  2. When tabbing it would tab twice to the button "create a shopping list". This was because we had wrapped the button with an anchor tag so we could use onClick and route to a new path. Instead, we replaced it with an action property that points to the intended path ./add-item. Now it doesn't double tab to the "create a shopping list" button.

Here's the new tabbing behavior. Works great :)
image

Related Issue

Closes #4

Acceptance Criteria

AC:

  • For users who do not already have a token/list, a button or link exists at the / route (i.e. home screen) that allows them to create a new list
  • Clicking the button/link generates a new token and saves it to localStorage
  • Once the token has been created and saved, the user is redirected to the "list" view

Type of Changes

Type
✨ New feature
🔨 Refactoring

Updates

Before

/ root
image

/add-item
image

/list-view
image

After

/ root
image

/add-item
image

/list-view
image

Testing Steps / QA Criteria

General setup:

  • From your terminal, pull down this branch with git pull origin NK-TR-create-tokenized-list and check that branch out with git checkout NK-TR-create-tokenized-list

  • Then npm install to install the newly added dependencies locally and npm start to launch the app.

  • In your browser navigate to the localhost server that is indicated in your terminal after npm start.

Testing routing logic:

  1. On your localhost in chrome open the developers tools
  2. Select the “Application” tab in the console's top menu.
  3. Select “Local Storage” in the console's left menu.
  4. Right-click and click clear to delete the local storage. image
  5. In your browser navigate to root /
  6. you should see image

Testing token storage:

  1. In your browser navigate to root /
  2. You should see image
  3. click the create shopping list button
  4. open developers tools and select the console tab
  5. Copy and paste !!window.localStorage.getItem('token') into the console.
  6. It should return true

Add an item:

  1. Navigate to localhost to the path /add-item

  2. Write cucumber into the input field and hit submit.

  3. open developers tools and select the console tab

  4. Copy and paste window.localStorage.getItem('token') into the console and remember this value.

  5. In a new tab or window, open and log into https://console.firebase.google.com/u/0/project/tcl-7-smart-shopping-list/database

  6. Find the value that was returned to you in step 4

  7. If found verify that it has a document with a itemName field with the value cucumber.
    image

  8. If so test passed

nabilkaz and others added 30 commits May 11, 2020 08:52
…ab/tcl-7-smart-shopping-list into NK-TR-create-tokenized-list
Copy link
Member

@meganmckissack meganmckissack left a comment

Choose a reason for hiding this comment

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

I was able to cross off all of the acceptance criteria. Thank you for the detailed QA process.

Since we've all been testing different iterations of functionality, it was great to let us know how to clear the local storage that our browsers were already collecting so that we could see the user token functionality in action.

I was able to create a new list, see the local storage token in the console, add an item, and was sent to the the grocery list page and saw the item I had entered.

Using the testing criteria:
new local storage token was successful
Screen Shot 2020-05-16 at 1 55 00 PM

I was able to see the log of the cucumber item stored with my token named collection in the database
tcl_7_smart_shopping_list_–Database–_Firebase_console (1)

Copy link
Member

@alejandronanez alejandronanez left a comment

Choose a reason for hiding this comment

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

@Tanzi11 @nabilkaz this is awesome, what a great PR 👏 👏 👏. Superb description and QA steps, love it <3!

I had issues testing the whole cycle out in prod as you can see in this video, https://www.loom.com/share/179fbce2c1b74470a14273b5a4e24e80 I'm not really sure why it doesn't work once I create the token. But works fine the moment I reload the page!

I couldn't test this locally bc I'm having internet problems and pulling the branch was taking literally FOREVER 😩.

Still, I think this is 👍 to go, we can figure out the redirect bug later!

One thing that I'd like to get removed before merging is the extra dependencies you added, Mobx and the Firesbase wrapper.

Thanks again for the amazing work!

Update

Welp, I couldn't reproduce this locally...I wonder what the issue is 🤔. I'll try to take a look at it tomorrow morning before our meeting 👍

Comment on lines +113 to +115

/* Functional styles */

Copy link
Member

Choose a reason for hiding this comment

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

Oh interesting approach! Are you linking this better than regular css?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am! Technically this is still regular css. Being able to describe what you want using classes is great. Combining it with react components to give you both flexibility and abstraction.

Honestly, just needed to choose a scalable approach and chose this way of organizing the css. It was fun.

Choose a reason for hiding this comment

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

This is very similar to how Tailwind CSS works. I think it would be a really interesting side-quest to explore bringing it into this project if you wanted to go down the "utility styles as classnames" approach, to keep it consistent with an industry standard. For a small project, it's fine to make a few small utility functions, but over time this file will become really big (every time you need a new CSS state) and could be hard to explore without documentation.

src/App.js Outdated Show resolved Hide resolved
@@ -16,7 +17,7 @@ class AddItem extends React.Component {
addItem = e => {
e.preventDefault();
const db = fb.firestore();
db.collection('items').add({
db.collection(getLocalToken()).add({
Copy link
Member

Choose a reason for hiding this comment

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

👏 👏 👏 👏

src/lib/token.js Show resolved Hide resolved
<FirestoreDocument
path="items/tIA3kp24eSWYTNKxA3wl"
<FirestoreCollection
path={`${getLocalToken()}/`}
Copy link
Member

Choose a reason for hiding this comment

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

Nice work :)

package.json Outdated Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
Copy link

@msholty-fd msholty-fd left a comment

Choose a reason for hiding this comment

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

Wow, the description and documentation in this PR is 🏅 💯 . I love it!

I tested this out and probably ran into the same issue that @alejandronanez ran into, where when I created my first list it redirected me to /add-item (full page reload instead of a react-dom app redirect).

If you try to simply go to https://deploy-preview-24--tcl-7-smart-shopping-list.netlify.app/add-item you'll see the same. I believe this is a server-side configuration that we need to handle in netlify, since all requests should get routed through the root index.html and not try to access some other document like add-item.html. @segdeha can you confirm if there is some configuration you've set in the past so this works?

Other than that minor bug, which is not due to this PR or the project code at all, this amazing PR is ready to merge. 👏 👏 👍

@@ -3,15 +3,15 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"firebase": "^7.14.2",
"firebase": "^7.14.3",

Choose a reason for hiding this comment

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

One thing of note for dependency management - It's generally a good idea to indicate in your PR why you are changing the version of a dependency. This project is super young, so this shouldn't affect anything. However in any long-lived project, even a small version bump comes with risk so we should at least understand what the benefit of upgrading is.

I wouldn't worry about changing this back, but just something to note for the future!

Comment on lines +113 to +115

/* Functional styles */

Choose a reason for hiding this comment

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

This is very similar to how Tailwind CSS works. I think it would be a really interesting side-quest to explore bringing it into this project if you wanted to go down the "utility styles as classnames" approach, to keep it consistent with an industry standard. For a small project, it's fine to make a few small utility functions, but over time this file will become really big (every time you need a new CSS state) and could be hard to explore without documentation.

@segdeha
Copy link
Member

segdeha commented May 17, 2020

If you try to simply go to https://deploy-preview-24--tcl-7-smart-shopping-list.netlify.app/add-item you'll see the same. I believe this is a server-side configuration that we need to handle in netlify, since all requests should get routed through the root index.html and not try to access some other document like add-item.html. @segdeha can you confirm if there is some configuration you've set in the past so this works?

Hey! We’ve just ignored this issue in the past, but you’re more than welcome to try creating a _redirects file (as described in this post) to see if that fixes it!

@nabilkaz nabilkaz merged commit 5a6307b into master May 17, 2020
@nabilkaz nabilkaz deleted the NK-TR-create-tokenized-list branch May 17, 2020 20:31
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.

3. As a user, I want to set up a new shopping list so I can track purchased items
6 participants