This gist details the decisions I made, the tests I conducted, the observations recorded, and the directions I took while building out an API for Project Catwalk.
Design the Product Overview (highest priority) for our team's project.
This gist details the decisions I made, the tests I conducted, the observations recorded, and the directions I took while building out an API for Project Catwalk.
Design the Product Overview (highest priority) for our team's project.
Today was the first day of the project. I spent the morning reviewing expectations, and in the afternoon, my team and I went over Trello's features, Create-React-App's setup, and dividing responsibilities.
I started our project's README.md and created the tickets to build my widget.
I was given all of the documentation that would be needed for the next three weeks.
I decided to ignore reading into the expectations for each widget/API feature, so that I could spend time understanding the ticketing system, progress demos, how to review other's code, and the phases of this project.
I was surprised to hear that I would be able to practice reviewing my classmate's code, as well as being put up to the challenge of designing my own tests for my code.
We spent some time going over documentation, but then began to implement parts of step 0.
Ryan created the organization on GitHub and our system on Trello, while I began to work on our README, which included an overview and basic structure of what we would work on.
I learned that the README uses markdown, and that it would be easy to customize.
We had to edit the Create React App codebase to fit our immediate needs.
Ryan removed certain dependencies in package.JSON, as well as created folders for each of our components. Michael and I spent the time observing, as we never used CRA before.
I learned that CRA came with a lot of CSS already, as well its own testing dependencies.
Needed to have tickets created before 12:30PM tomorrow
I went through the Business Requirements Document and broke down my tickets into subsections. I tried to make sure that each ticket was not going to overlap to others, and that the code I would produce for it would be worthy of just one ticket.
The Trello board's backlog looks overwhelmed already with only my tickets, and I wonder how effective it is when there's 20+ tickets in the backlog column.
Day 2 - This morning we learned about Git Workflow, specifically focused on a Feature-based workflow.
I had to learn how to create a new branch using Command Line, as well as the conflicts to expect when making multiple Pull Requests on several branches.
I was able to create a branch for a ticket, as well as maintain as much synchronicity with the main branch by pulling from there before working on my branch.
To start off, it'd be wise for the team to stick to their modules for now, so as to prevent any conflicts in the immediate future. In addition, we should have a codebase set up already so we won't need to make further adjustments in our own branch that can affect everyone else.
As a team, we had to agree on what technologies we wanted to implement for testing, CSS framework, and state management.
I made sure our main app component imported the subcomponents that we would individually be working out of. Additionally, we came to an agreement on using Jest for testing, tabled using a CI until later (when we've had more practice with Jest), and we agreed to individually do our research on Material-UI for designing the page. We will be sticking with using either stateful class components (depending on how much we each need to pass down to our subcomponents), or use React hooks, but we will definitely not be using Redux.
It is easy to want to take on multiple new technologies at once, but in order to make sure our steps are actionable, it makes sense to pick 1-2 new technologies to implement, as long as they're not directly related to each other.
Do more research on Jest, Circle CI, and Material-UI.
I know that we won't be using Circle CI, but I wanted to know what the setup would look like in terms of how long it'd take to implement it. I watched a tutorial on Material-UI, as well as looked into installation/integration into our React App.
Since I'm not the admin of our current project, I can't integrate Circle CI into the repo. Overall, it seems really easy to install, especially once we have tests built with Jest. So I think it's wise that we wait until we've each made our Jest tests in order to determine if there's any conflicts with each of our components (might need to check-in with team again in the middle of next week). Surprisingly, Material-UI relies on the props that React makes available in their components, which I am now really comfortable with. I'm thinking that I'll be able to knock off a good portion of my tickets by using Material-UI. My one concern is that we don't have a template to work off of, so we'll need to stay in communication with what the page looks like over time.
Day 3 - We learned about Optimization, as well as finalized on some CSS/State choices. Framework is nearly 100% complete.
Axios - including Headers object in GET request for Authorization
We were expected to give an update on the progress we made with the Program Lead, as well as what challenges/steps we were going to come across next.
I felt like it was a good idea to lay out our progress on a Google Doc, just so that our thoughts would be organized during the demo. We made the decision to stick with a stateful App, instead of looking into Redux as an investment, and we decided on using Semantic-UI over Material-UI or React-Bootstrap.
It turns out that it was a wise decision, as everyone else was speaking freely, and it was hard to track what progress they already made. It also helped with stamping out what we discussed already, and what we wanted to work on next. My understanding of why we would want to use Redux is that there would be props that we'd need to be passed down to multiple components, and I felt like the Atelier API documentation made it clear that there would be very little (if any) shared props. It made more sense to just have 4-5 GET requests take place in their respective components in order to pull the necessary data for each component rather than spending a large chunk of time on building Redux to make an equivalent number of requests in one place. Lastly, Semantic-UI is pretty exciting to use. We decided to go against the grain in using Material-UI, as it appears to be very generic and difficult to customize. React-Bootstrap has more to play with than Material-UI, but Semantic-UI's documentation showed so many more ways to play around with customizing, and it was just as easy to implement as the other two.
API Connected (via Postman) and 1st Real Code Review
Connect to API using Authorization/API key in Headers
of request.
Review Michael's outline of component/subcomponents.
Aside from making sure to use the correct parameters for the API URL, I learned that the Authorization key will take the API key I created,
and pass it into the Headers
of the request I made on Postman.
I pointed out that Michael should consider when components would be children vs. siblings, as well as consider what props would be passed
down into his main component from the App.js
file.
I'm concerned about how easy it'll be to find my API key inside our codebase, even after .gitignore
-ing the config.js
that holds our
API keys, since we need to import the token into each of our components when we want to make an axios request.
In code review, I like writing out the comments over GitHub, so that any criticism is made less subjective and much easier to get across.
It's also easier to reference!
Create Axios Request Template and Class Component for ProductDetails.jsx
Merging conflict with Ryan and I having both worked on App.jsx
in separate branches, and my work was already merged with Main.
I imported config.js
and used template literals to insert the token into the Headers
of my axios GET request.
I also laid out a class component for my main component, that way I can begin to console.log
the requests I make.
Walked through Command Line with Ryan to make sure our merge conflict was resolved.
Because I had to wait for Ryan to install our linters (airbnb, React, React-Hooks), I wasn't able to test out the axios request yet. I'll be trying out what I've made so far some time this weekend. I'm hoping that we can do without any more major edits to the higher-level files, so that there are less merging conflicts to worry about.
Spent the afternoon organizing the main component into three subcomponents.
Outline ProductDetails (Overview) Component
Clearly mark subcomponents in order break problems into smaller pieces. Verify that axios request works in componentDidMount.
I created three subcomponents of ProductDetails, and made sure to pass down some props that they would end up requiring.
Included return
keyword before axios request.
I will likely need to create a child component of BuyProduct, in which the styles of an item can be selected, which will end up changing the price/images/size/quantity of the product. Realizing that now, does it make sense to not create a child component if it'll affect the props passed down to BuyProduct? So far, it looks like API key is hidden from public view when a request is made from the client! Also, page is rendering on browser.
Started to place information into the BuyProducts subcomponent, including two dropdowns and Cart/Favorite buttons.
Semantic UI's React - Grid/Column/Row/Segment/Divider/Dropdown/Button/Breadcrumb
Populate Subcomponents with Data
I needed to begin segmenting the parts of each subcomponent, without relying on having all of the data yet.
I began with transferring the three subcomponents into actual Segments of a Grid. Then, I worked with some of my state to populate
BuyProduct.jsx
with the category/name/price/size/qty of the product. I also used Divider/Dropdown/Button to organize the parts of this subcomponent; I used Amazon's product page as an exemplar of what would make sense to be grouped together within the Dividers.
The most difficult task was actually playign around with the sizes of the dropdown, and realizing that I wanted to compact
them so
that they'd be able to stay inline with other buttons. Additionally, I realized that the bigger task will be manipulating the component
when I incorporate the different styles of a given product (quantity/size/images/price).
Use React Hook to Change Dropdown Values
The quantity of a given style is dependent on the size chosen for that style (by the user).
In order to change the quantity based on the size selected, I made a Use Hook that stores the quantity of the style whenever a different size is chosen. Prior to this, I had to make a second GET request to retrieve all of the styles of a given product (eg. variations of a shirt).
Now that I have the styles of each product, I will need to change the price/images/features depending on the style that's been chosen.
Worked on the Styles component that allows the user to switch styles of a given product.
Semantic UI's React - Image/Label React Hook - UseState()
Style Change w/ User Interaction
I needed to present the thumbnail for each style of a product, and make it so that a user's click would change the price/styleName/sizes shown on screen.
I created Image components that were clickable, and responded to a click by changing the state of CurrentStyle.
The next challenge is making it so that the sizes/quantities of each style are rendered. This likely requires make another React Hook, but whether it's a useState or useEffect is yet to be seen.
Created the Product Description and Image Gallery components using Semantic UI and imported carousels.
[https://github.com/layershifter/semantic-ui-react-with-pure-react-carousel](Pure React Carousel) [https://github.com/leandrowd/react-responsive-carousel](React Responsive Carousel)
Create Product Description and First Attempt at Importing Carousel
Create an interactive Image Gallery that includes arrows for navigation, thumbnails to select image, and highlights selected image. Also include product's description under gallery.
Installed and imported Pure React Carousel, and attempted to map
the array of image URLs. Also, designed Product Description to match with the Visual Design demo provived by Hack Reactor.
The Pure React Carousel did not interact well with the codebase I already had. Although it was meant to use the same React-Semantic UI, the images didn't appear on screen immediately, and when they did, it was all photos grouped together. There were no pre-built arrows or thumdnails either, so it ultimately needed to be switched out. The Product Description only needed two props and no interaction, so it was an easy build. I also decided to move the "Share" buttons (Facebook, Twitter, Pinterest) to underneath the Cart/Favorite buttons, as desgn-wise they didn't go well with the product description.
Switch to React Responsive Carousel
Find a carousel component that includes thumbnails/arrows to replace first carousel.
Installed and imported React Responsive Carousel. It also required importing the CSS library for this specific carousel.
Initially, I thought that it had everything I needed: thumbnails that highlight the selected image, arrows to navigate through the images, and even the ability to use arrow keys for navigation. The issue that I still faced, however, was that the images are of different sizes, and so attempting to manipulate the CSS was unsuccessful.
Merging all three subcomponents to Main branch and coming to terms with Carousels.
(React-Share)[https://github.com/nygardk/react-share]
Trial and Error with CSS Manipulation of Carousel / Create Share Buttons that send user to their social media account with pre-filled information.
Attempt to make the images fit on the screen without taking up more height than allowed, as well as bringing the white space to a minimum between the arrows, main image, and thumbnails. Additionally, merge all three subcomponent (Product Description, Product Images, Buy Product (cart management)). Also, create share buttons using React Share that send users to their social media accounts.
The merge required fixing some errors due to my having made three separate branches from the Main branch. After fixing the errors and
merging to Main, more issues came about in node_modules
as well as in the name of props from one branch differing from another. After
fixing those errors, the rest of the afternoon was spent on the CSS for the carousel gallery.
Create share buttons.
I realized that I should now create a branch from Main in which I can make my several branches off of, so that when I'm ready to merge
all of my work, each branch will still receive their own PR and then I can work on any merge errors before committing to Main.
The issue with my node_modules
was due to the missing filepath to the FontAwesome icons, which caused all of my icons to disappear.
My solution was to delete my node_modules
folder and reinstall all of the packages.
The share buttons were very easy to make, and I decided that it was time to start making subcomponents for the already existing subcomponent Buy Product
. Its file was exceeding 100 lines of code, and I knew that eventually it would be difficult to read.
Lastly, I came to the conclusion that I am better off making my own carousel so that I can manipulate the CSS however I need to. I continually ran into CSS specificity issues, in which my attempt to override the styling was made impossible with the amount of specificity that was already present in the imported Carousel. I'll be working on designing my own tomorrow.
Refactored largest component into five components and moved two variables into state to allow for re-rendering.
Refactor Buy Product
In order to review how data was being moved and what props were redundant, I needed to refactor the +120 line component into five subcomponents.
Working from top-down in the Buy Product component, I created functional components for the Price Tag, Style Thumbnails, Size/Quantity Dropdowns, Cart/Favorite Button, and Share Button.
While refactoring, I realized that there was an entire object with three key-pairs that was being made for the quantity of each size (S,M,L, etc.), so I reduced it to one line. I was also able to see which components needed a component from Semantic Ui to be imported, and that made it easier to track which of those components were redundant.
Replace Size/Quantity Arrays into State
The Size and Quantity dropdowns weren't repopulating after a style was changed by the user.
Initially, I tried using useEffect
and useState
to repopulate Size and Quantity every time the currentStyle
changed, but there was conflict with two components re-rendering at the same time. I then decided to switch to moving Size and Quantity to the parent component and having them re-render whenever currentStyle
changed.
I found that I was passing quantity data into one too many variables, so I removed one array variable, which reduced several lines of redundant code. As stated earlier, I decided to try using React hooks to have the Size and Quantity re-render within their functional component, but I realized that I haven't fully understood useEffect
and useState
enough to confidently use them. Once I moved them into the class component, there was no longer any rendering conflicts. Although I know that class components are considered bulkier and confusing for certain people, I've grown very used to them and knowing how to pass props down correctly. I know in the future when I'm working with larger files, it'll be more efficient to use hooks, but it doesn't feel as pressing when I'm only passing props down two files.
Cart Management is fully functional!
Refactored and created some methods in order to handle sync issues regarding updating Quantity when a Size is chosen.
In order for the Cart button to send a POST request to the API, the quantity and size dropdowns needed to populate synchronously.
Most of the day was spent on moving variables/props to the parent component, which was the class component. Then, I needed to reconfigure some objects to include the SKU id of the product/style so that the correct size was added to the cart. Lastly, the API only accepted the SKU_id, but not the quantity of that style, so I had to create a method that used a while
loop to send a POST request equivalent to the quantity number.
The most difficult piece was getting the quantity to populate once the size was selected. Initially, I had to grab the size name (S,M,L) through the event.target.contentName
and the SKU through React's state.value
which was saved in the dropdown component. But that caused an async issue in which the quantity wouldn't populate. So, what I ended up doing was design the quantity options to be an object with the keys: key:[some number], text:[quantity#], value:[SKU]
. This way, when I finally had the opportunity to press the CART button, all it needed to send was the quantity#
and the SKU
to the method that would make the API request.
Checkmark over selected style
If style thumbnail is selected, a checkmark should appear over the image.
What made this finally work was that I used the label
attribute, inserted a ternary operator within it, and compared the currentStyle
to the style
selected in order to give it the check
icon. Otherwise, the label
would be equal to null
.
I had made prior attempts to make the label work so that it would leave a checkmark over the image. I think I overcomplicated things by trying to use 3-4 of Semantic-UI-React's components. The inability to really control how these components would interact meant that I should've taken advantage of their props that they already provided (ie. label
prop inside Image
component, instead of creating a Label
component underneath Image
)
Cart Management is fully functional!
Refactored and created some methods in order to handle sync issues regarding updating Quantity when a Size is chosen.
In order for the Cart button to send a POST request to the API, the quantity and size dropdowns needed to populate synchronously.
Most of the day was spent on moving variables/props to the parent component, which was the class component. Then, I needed to reconfigure some objects to include the SKU id of the product/style so that the correct size was added to the cart. Lastly, the API only accepted the SKU_id, but not the quantity of that style, so I had to create a method that used a while
loop to send a POST request equivalent to the quantity number.
The most difficult piece was getting the quantity to populate once the size was selected. Initially, I had to grab the size name (S,M,L) through the event.target.contentName
and the SKU through React's state.value
which was saved in the dropdown component. But that caused an async issue in which the quantity wouldn't populate. So, what I ended up doing was design the quantity options to be an object with the keys: key:[some number], text:[quantity#], value:[SKU]
. This way, when I finally had the opportunity to press the CART button, all it needed to send was the quantity#
and the SKU
to the method that would make the API request.
Checkmark over selected style
If style thumbnail is selected, a checkmark should appear over the image.
What made this finally work was that I used the label
attribute, inserted a ternary operator within it, and compared the currentStyle
to the style
selected in order to give it the check
icon. Otherwise, the label
would be equal to null
.
I had made prior attempts to make the label work so that it would leave a checkmark over the image. I think I overcomplicated things by trying to use 3-4 of Semantic-UI-React's components. The inability to really control how these components would interact meant that I should've taken advantage of their props that they already provided (ie. label
prop inside Image
component, instead of creating a Label
component underneath Image
)
Remove Favorite Button with Shared Buttons, with the challenge of aligning Cart button with Shared Buttons (two components from different
libraries (semantic-ui-react
and react-share
)
Most of the time was spent on figuring out the element/className combination required to manipulate the alignment of the buttons.
I was attempting to manipulate the margin
or justify-content
, but something as simple as
.cartShare { display: flex; }
did the trick.
I need to be more aware of how CSS can be manipulated. I understand that practicing is the best way to understand it, but I also want to make sure that what I'm learning is still considered the most effective/professional.
Use the Star Rating component created by Ryan (for his Ratings & Reviews component), which includes making a GET request and inserting a link at the top of the page that directs users to the Ratings & Reviews at the bottom of the page.
Following the data in Ryan's files, I made a GET request to the API for an object of all ratings, imported that as props to the component where my Star Ratings would exist, and imported Ryan's component into my BuyProducts file. Using this article, I included a line of code in my file, which would redirect users to the bottom of the page where the Ratings & Reviews component existed.
This is one instance where I made a mistake that affected the rest of my team. I purposefully did not write into Ryan's file the <a id=''>
that would be needed for my <a href="...">
to redirect the users to the bottom of the page. I figured that it would cause merge errors
if he was working on the same file in his branch. Instead, I made a PR, then told him what he needed to change in his file to make the
href
work for the user. As it turns out, the appropriate sequence of steps would have been to talk to him about making that change
before starting a PR. It doesn't matter whether the change would be 1 line or 20 lines of code, it still affects his files and it could
mean he would have to change his setup. So I learned to be more aware of how to communicate with my team, especially when it relates to
code that would affect their own work.
Insert a Modal that uses the same Carousel as the main page, including arrow buttons and same image in Default/Expanded view.
I turned my Carousel into a helper function so that it could be used for both the main page, as well as the Modal. The issue here was that when I needed to switch the cursor from a magnifying glass to a '+' sign, they shared the same class names and specificity. Eventually, I was able to get each cursor to appear depending on the view, but the cursors extended beyond the actual image.
I learned that not only did I need to find ways for a default image to be distinguishable from its modal counterpart, but that they also needed to override the specificity of the Carousel itself when it came to which cursor to use. By the time that the day was over, I only knew how to get the cursors to appear separately, but they covered the entire component, not just the image.
Learn and implement the Higher Order Component feature of React so that each Carousel component (for default and modal) can receive their own cursors, indicator/thumbnail feature, and onClick() function.
I created a new file to store the HOC Carousel, and imported it into ProductImage.jsx
. I then created the selectData
objects for both
main
and modal
carousels, so that when they call on the HOC, their props are inserted into their new Carousel.
I am amazed at how much of the HOC was already made by my having worked on the Carousel. The only thing that needed to be replaced were the props that I'd eventually be passing into the HOC, depending on what features it needed. It also made it easier to create a className that was unique to each type of Carousel, and so the cursor bug was fixed!
After merging the last component into our page, the team had to have a discussion on styling and the end goal. Afterwards, in preparation for the next day's Progress Demo, I had to work on styling the carousel images so that the images were centered.
Michael was given the control to style his component so that it would match closely with the rest of the page instead of Ryan or myself styling Michael's component with Semantic UI (React). I worked on the CSS styling until the images were at a reasonable size, and stretched the smaller images' height so that they matched more closely with the larger images.
The conversation was very difficult to have, as Michael had not merged his work for the last two weeks, so it was difficult to ever know what his work would look like until today. Although he initially used Semantic UI (React) to build his component, he used a lot of styling and the !important
keyword to format it to a certain size. Once we merged the component with the main branch, it was obvious that his component was disproportionate from the rest, and it would require some restyling to make it match the other components. We compromised by making the widths of our components shorter, so his component wouldn't have to stretch far.
For my CSS styling, once I was able to have the images reach a max-height
, I then chose to stretch the shorter images so that there'd be less white space. This was completely short-term, and was meant to only have our demo be presentable for tomorrow.
I wanted to have a presentable Carousel with centered images before the Progress Demo.
I simplified my CSS in order to have better control on what was being changed.
Eventually, I was only able to center the images when the page was on a specific computer. We presented our page with the specific screen that would render the page in its most presentable form, but after the demo, I was able to finally fix the centering to stay the same for any size screen.
Center the thumbnails of the carousel and try a third magnifier for expanded view.
In order to center the thumbnails, I had to remove some of the margin styling I made previously, and instead move up two parents to the div
that controlled the entire thumbnail carousel:
div.carousel { justify-content: center; display: flex; }
For the magnified view, I initially placed a conditional in my HOC for the Carousel that would render the expanded view if the prop
zoom
was true
. This made it so that some of the images could be magnified. During a break from the screen, I realized that I needed
to move the Magnifier
component out of the HOC and instead inside the Modal
component, which I'll be working on for the afternoon.
During the Code Share with my team, I was able to ask for assistance on styling the imported Carousel component. I was already
spending time on previous days with getting the CSS styling done correctly, so that the images would appear in the same place no matter
the size of the screen. I didn't think that they entire thumbnail component neeeded to be centered, but rely on padding/margins instead,
which was what I was able to accomplish previously with the main image.
For the Magnifier
, it was satisfying being able to think out loud and realize where it made the most sense to have my Magnifier
component exist so that it was replacing the Modal's Carousel as opposed to living inside the Carousel.
Have Magnifier
set up properly to react to clicks and allow for Modal to return to Carousel mode when exiting "magnified" view.
I was able to use similar CSS tactics from the default view in order to get my Modal to show most of the image on the screen without requiring scrolling. Also used React hooks to change state of Modal from Carousel to Magnified and back. Lastly, used !important
in order to bypass an element.style
that prevented the cursor from being zoom-in
when Magnifier
was on.
I managed to get the Magnifier
to zoom in slightly for the larger images, and too much for the smaller images. I'll be bringing up with my team tomorrow on whether they'd prefer the GlassMagnifier
component which would circumvent the sporadic Magnifier
, but not quite meet the Document's expectations. I will say that I'm proud to have gotten this component to work as best as I could get it to before the weekend. I've technically touched upon every major piece of this component now, and just need to work on a few bugs and determine what I want the finished result to be able to do.
Deploy the app!
Using the instructions provided by HR's slides, I created a server that ran all requests from the client side to the Atelier API. This allowed
for a safer website that didn't include our API Keys anywhere on the page. It took some time to debug how the URls/Paths needed to look
for each file, as well as in the server.js
. There was also time spent on correctly passing data back to the client so that there'd be less
reconfiguring of our files overall.
The amount of times that I had to edit files within Ubuntu's terminal, run npm run build
, and debug using Ubuntu and AWS, has made it so
that I can confidently set up a client-server app using EC2. Majority of the issues came from fixing the filepaths and URLs on the client and
server sides, as well as how they sent/received the data from the API. With that said, there was no time to fix the Imgur POST request that
would have converted our submitted photos into actual URLs. Additioanlly, oru Progress Demo included some bugs that we ended up not having
the time to fix, but it's fair to recognize that they still existed. This project taught me a lot about CSS styling and the trickiness
of installing multiple libraries and components and never being able to expect that they'd work together.
As part of the finishing touches before presentation on Monday, we needed to include a way to track the user's clicks on the page.
Import and install Ryan's Data Analytics component and fix the Read all # reviews
link.
Ryan found a method from ReactDOM
called findDOMNode
, which made it so that an event listener could be invoked starting at the most
parent class component, and it would listen to any clicks that occurred in any of the children beneath that parent (including parent).
What eventually became an issue was that Michael had no class components, and this method wouldn't work on functional components. Although
a solution for Michael's situation was found, he decided to turn his parent component into a class component in order to use the same DA
component as the rest of the team.
For the Read all # reviews
link, I realized that my total was coming from the total number of reviews submitted, but not the total
number of reviews that were written and thus 'readable'.