DEV Community

loading...

Converting a Prototype to React Components

VBAK
music & code.
・8 min read

Newbie Nightmare: Open-Ended Tasks

It's what makes web development exciting and drew me to it but---one of the most challenging tasks I have encountered in my first year-ish of learning web development is translating visual designs to code. It's a very open-ended task with many opportunities to make future choices that lead to ugly if not wrong results which I believe is called technical debt.

Newbie Dream: Curated Best Practices

I have deferred and relied on others' best practices when approaching such an open-ended task. However, those best practices probably or rather hopefully came from a large number of iterations of experience and following them without sharing the same intuition requires a large amount of faith. Implementing someone else's best practices into whatever app I am applying them to also requires a good amount of luck (hopefully my app doesn't have that one feature/requirement that ends up being the kryptonite of any of the best practices I follow). Lastly, vetting someone's best practice as a newbie is nearly impossible.

Newbie Reality: Reinvent the Wheel

While I want to be efficient and resourceful, I also need to build a deeper intuition for tasks related to converting a prototype to UI logic. I think my favorite way to do that is to approach an open-ended task with one outcome: empirical learning. I'll be writing this post in (approximately) realtime while I work on and learn about the project at the same time a la Rahzel.

Plug

I manage the repo for the OSS project that I'll be talking about in this post. As you will see throughout this post, we need a lot of help building this app so if you are interested in contributing please take a look at our repo at the following link:

Wildfire Survivor Management System (Link to GitHub Repository)

We are building two apps for the staff at the United Way of Northern California to help them manage California wildfire survivor data. This is a project that started out initially as an IBM Call for Code one-day hackathon event (link).

Our hackathon team's UX designer created the Sketch files located at this link and the first non-hackathon-team-member contributor converted them to an interactive prototype for each app:

  • Wildfire Survivor Application (Link to Invision Prototype)
    • Users (wildfire survivors) fill out this HTML form-element-based application in order to submit the necessary information for United Way staff members to evaluate and distribute financial assistance. We have a development version which successfully runs locally with minimum functionality (user can enter and preview data in the form elements) but a lot of essential functionality is still missing before users can safely and conveniently use this app (authentication, file storage, CRUD methods, data encryption, and things we haven't even thought of...)
  • Wildfire Survivor Dashboard: (Link to Invision Prototype)
    • This is what I'll be tackling in this post!

Data, Display, Events

Of the many ways to breakdown this problem, the following three components of this project are fundamental:

  • What data will be displayed to the user?
  • How will it be displayed?
  • What events will take place?

Data

Since we are making both the app where users submit their data and the app where admin manage it, we have some flexibility in choosing how the data is structured. For now, I'll keep it simple and continue to use the very linear structure I gave to the data in the Wildfire Survivor Application:

schema.js (Link to GitHub repo)

This file exports an object (named SCHEMA) which contains data about each field that will receive some input from the user (inspired by MongoDB's $jsonSchema object (link to their awesome docs))

const SCHEMA = {
  survivor_first_name: {
    input: "text",
    type: "string",
    initial_value: "",
    placeholder: "First Name",
    test_value: test_values.first_name,
    validation: () => {}
  },
  ...
}

component_fields.js (Link to GitHub repo)

This file exports an object (named FIELDS) which lists the field names for each fieldset. (These fieldsets were determined from conversations with the end-users---the staff members who will be managing this information). Right now I'm assuming they are going to turn into separate React components, so I've kept the name as "component_fields". However, this is a fundamental structure I'm giving the data primarily to keep it simple (for now) so it may change over time as the project improves.

const FIELDS = {
  general_information: [
    "survivor_first_name",
    "survivor_middle_name",
    "survivor_last_name",
    "survivor_phone",
    "survivor_email",
    "survivor_address1",
    "survivor_address2",
    "survivor_city",
    "survivor_state",
    "survivor_zip"
  ],

  ...,
}

The code samples shown represent the following section of the Sketch file which corresponds to the general_information fieldset:

Sketch file screenshot showing General Information fieldset UI

The goal is to allow us to add and remove fields from different fieldsets over time as we gather more feedback from our end-users.

Display

The Dashboard consists of four main views. Here are my initial thoughts on the views' relationship with the various fields:


Dashboard

  • Applications are grouped first by fire_name in a scrolling navigation element and then by status (which is currently not included in either schema.js or component_fields.js) in two separate containers beneath it

Dashboard Page


Analytics

  • The financial assistance dollar amount visualizations will be displayed by wildfire and over time

Analytics Page


Applications

  • Each wildfire has its own screen displaying a list of all applications that were submitted to receive financial assistance, grouped by status in different tabs

Applications for Camp Fire

  • A single application is displayed as follows:

    • The main container displays the application data in the same fieldsets that are used in the Survivor Application (i.e. as grouped in component_fields.js) across different tabs
    • A side panel includes options for the application's status

Single Application Page


Map

  • The Map view displays an embed of CALFIRE's Camp Fire Structure Status (link)

California Wildfire Map


Events

There are a two broad types of events that the Survivor Dashboard components will need to handle:

  • Changes to data from a Survivor Application

  • Changes to Admin-only fields (application status, financial assistance, status update notifications, messaging, etc)


Version 0

Okay so talking through that has helped me to mentally organize the different screens a bit to start seeing some patterns across the screens. Time to jump into a codepen!

Survivor Application Data

I've created some data for an application to use for this initial version. The file lives in the repo at this link and I used jsdelivr to deliver it to my pen. I am avoiding any Firebase functions until I've wrapped my head around the UI.

I'll start with how the Survivor Dashboard displays a single survivor's application. This screen shows different fields based on different tabs that are selected.

Single Application Page


Here's the pen! Please click through and let me know if you have any feedback! (I am particularly proud of the way I wrote the logic around the UI for the "Notes" section.)


Bonus Learnings

A few bonus learnings (i.e. things I thought I knew until I spent a couple of hours debugging my misunderstanding for each one):

  • The C in CDN stands for Content but it could also stand for Cached.

    • I have been using the super cool jsdelivr for getting a .json file with fake data from this project's Github repo. However, I made some commits with changes to that file (adding a few key-value pairs) yet my fetch was not fetching the latest file! I came across this issue on the jsdelivr Github repo where one of the comments explains that CDN files are cached and may take up to a day to refresh. So my workaround was changing the file name in my repo which changes the URL and thus counts as a new file.
  • Another cache-related problem I encountered was the "Cache-Control" request header

    • At some point, I had waited long enough for the CDN to update its cache (which I realized after the fact), but my browser cache was still being referenced.
    • On a side not, I look forward to referencing these sorts of concepts in Julia Evans' HTTP zine, who teaches in a very effective style for me---visual comic:
  • I will purchase that zine eventually! For now, I've referenced MDN and added the following init object to my fetch call to ignore browser cache:

fetch("https://cdn.jsdelivr.net/...", { cache: "no-cache" })
  .then((response) => { /* ... */ })
  • CORS
    • CORS is a frustrating concept to learn/utilize for a newbie. Big safety and big headaches because of it. I ran into a CORS error when requesting a resource from Firebase Storage and found the following resolution which involved configuring CORS for the Google Cloud Platform project. Let's begin with the shell provided in the Google Cloud Platform console:
    • Open the shell (leftmost icon at top right corner of the screen)

Screenshot of the Google Platform Console project dashboard displaying the shell icon which is the leftmost icon located at the top right corner of the page

  • If it doesn't exist already, create a file called cors.json using a text editor. I chose to use pico for no other reason than it was part of one of the answers for this StackOverflow question - pico cors.json - Add something like this (replace the array mapped to the "origin" property to an array of strings with domains you wish to allow for a given method for this project's Storage:
  [
    {
      "origin": ["https://s.codepen.io"],
      "method": ["GET"],
      "maxAgeSeconds": 60
    }
  ]

  • Save that file! I exclaim it because I didn't.

    • one way of doing that is to type ^X and then Y when it asks "save modified buffer?"
    • another way is to type ^O to "Write Out" the file and hit enter when it prompts File name to write:
  • Run the following command (replace exampleproject in the URL with your actual project ID) to set your saved JSON file as the cors configuration file:

gsutil cors set cors.json gs://exampleproject.appspot.com
  • Now you can use Firebase Storage URLs in your codepen!

Discussion (0)