CS 312 Software Development

CS 312 - Assignment Three

Goals

  • Get more practice implementing React components, including incorporating PropTypes
  • Advance your understanding of the division of responsibilities and state between components

Prerequisites

This assignment builds on the work of assignment 2. As such, you should not start it until you have passed all of the Gradescope tests for assignment 2. While this doesn't assure you that you will have "met expectations", it is enough to proceed.

  1. Visit the Assignment 3 page on Replit (or click the 'Start Project' link for Assignment 3 on our team page).
  2. Click the GitHub classroom link to accept the assignment.
  3. Return to the assignment on Replit and go to the Version Control panel.
  4. Click the button to create a new git repository (not the one for connecting to an existing repo).
  5. Open the shell and follow the instructions on your GitHub repository for connecting an existing repository:
    1. git remote add origin repo-name where repo-name is the name of your repository (e.g., https://github.com/csci312-s21/assignment03-ChristopherPAndrews.git)
    2. git branch -m main
    3. git push -u origin main
  6. Update the author information in the package.json file
  7. Copy your components over from assignment 2. In the interest of letting you resubmit assignment 2, the assignment 3 skeleton does not include the work you did in assignment 2, so you need to manually copy it over. Make sure to just copy the .js of the components you worked on.

Once you have the dependencies installed you can start the development server with the Run button.

Important Make sure that the new copy of your project is working before proceeding.

Background

This assignment, the next part of creating Simplepedia, starts where assignment two left off. As with previous assignments an initial set of (failing) tests are provided as part of the skeleton (run with npm test). These tests are intended to help you as you develop your application and to ensure that the grading scripts can successfully test your assignment. Code that passes all of the provided tests is not guaranteed to be correct. However, code that fails one or more these tests does not meet the specification. Testing React applications is a future topic and so you are not expected to write any additional tests for this assignment.

Assignment

Part 1: Add PropTypes

Please add PropTypes to your existing modules. You will find that I have enabled the PropTypes checker in eslint and added some tests that look for them, so your code will no longer pass the linter without them.

When adding PropTypes, be as specific as possible. There are a lot of different validators. Note that these cover specifying the contents of arrays and the structure of objects.

Part 2: Allow the user to add new files

Create a new Editor component in src/components/Editor.js. It should allow the user to create a new article. In this part you should pass a single prop to the Editor component: a "required" callback named complete that takes an article object as its argument and creates or updates that article (the comments discuss a second prop -- this will be added later).

Important Make sure to use these names (and any others specified in the assignment) to facilitate automated testing. While there may be different, equally valid designs, you are expected to code to the specifications I have laid out. Consider this practice for working on a team.

Simplepedia editing

Your component should use an <input> of type "text" to allow the user to enter in a new title and a <textarea> to allow the user to write the body of the article. Your component should have two buttons. The first should be a "Save" button. When the user clicks it, the article should be saved, and editing should be completed (your editor styling does not need to match the example above). The date on the article should be set to the current date and time (as an ISOString via Date.toISOString()), and the article should be added to the collection. The second should be a "Cancel" button. When the user clicks cancel, the edit should be discarded and the primary interface should be restored. Keep in mind the newly created article might not belong to an existing section.

There is one form validation required. If the title is not set, you should not let the user save the article by disabling the "Save" button. To help the user, provide meaningful initial placeholder text in both input elements.

Mode switching

The Simplepedia component (in index.js) will be responsible for switching between adding and viewing.

Create a new component called ButtonBar. It should display a single button called "Add".

The component will take a single callback prop called handleClick. When the button is clicked, the component should call the function, passing "add" as an argument (i.e., handleClick('add')).

Add this new component to Simplepedia underneath the Article component.

Write the handleClick callback so that when it receives the command "add", it switches the entire interface over to the Editor (we should not see IndexBar, Article, or ButtonBar).

In the Editor, if the user uses the "Cancel" button, the Editor should go away and IndexBar, Article, and ButtonBar restored. if the user had been viewing an article, it should still be visible.

If the user instead uses the "Save" button, IndexBar, Article, and ButtonBar should be restored, and the article the user just created should be displayed in Article.

Hint: this modal switching should sound like there is some new state involved

Updating the collection

Of course, the new article should also be added to the main collection as well...

Recall that we don't mutate state, we make a copy.

Updating IndexBar

We would like IndexBar to be consistent with the current article (i.e., display the correct section). There are a couple of ways to ensure this. I would like you to share currentArticle with IndexBar as a new prop. Unfortunately, you can't just use the first character of the title to determine the section, because then we couldn't switch sections. Instead, I would like you to add an effect hook. We discussed useEffect in lecture, and you used (or will use) the effect hook in practical 4.

The basic concept is that we register a function to be called under certain circumstances (when state or prop values change). The useEffect() function takes two arguments, the first is the function to run and the second is the list of variables to watch. For the practical, we passed the empty array indicating that we just wanted to run the effect once when the component is first created. You will want to watch for changes to the current article, changing the section if appropriate. This will mean that the section will change when the article changes, but can then be changed independently.

It is possible for the user to create a new article with the same title as a current article. We will ignore that problem in this assignment as we will fix it in the next assignment when we introduce a server (which will validate that the title is unique).

Simplepedia new article

Part 3: Allow editing

Once you can successfully add new articles, you will adapt the interface to allow editing of articles. Add an "Edit" button to the ButtonBar to request the current article be edited. When clicked, the edit button should call handleClick with the string "edit".

When handleClick receives "edit", the interface should then switch to your new Editor component, but the current title and article body should already be filled in. To do so, add an optional second prop to Editor called article. When creating a new article, this prop should not be set, or be set to undefined. When editing an article, this prop should be the article Object to be edited.

On "Save", the date should be updated and the changes saved (and the newly edited article displayed). On "Cancel", the changes should be discard leaving the article unmodified and the previous article view should be restored (displaying the original, unedited, article).

Part 4: Improve the UI

I would also like you to improve the user experience (UX) of the website.

One principle in UX design is to not allow the user to perform actions when the actions don't make sense. We have already done this in Editor, where the "Save" button isn't enabled unless the user has added a title. The user also shouldn't be able to edit or delete if there isn't a current article. Add another prop to ButtonBar called allowEdit. When True, the "Edit" button should be visible. When False, it shouldn't be visible.

Reflection

In the README.md file, I would like you to write a brief reflection about your assignment.

If it meets the requirements (passes all of the automated checks), write how comfortable with your solution. Did you use good development practices, or is it a hacky, last minute solution. Do you understand your own solution? How much effort did you put into it? Do you feel like you could do a similar assignment with more ease?

If it doesn't yet meet the requirements, what are you struggling with? What does it not do correctly? What have you done to try to correct it? How hard have you tried to correct it? How much effort have you put into the entire assignment?

Put a date on the reflection and if you do any revisions, add another dated reflection below it.

Finishing up

Your submission should not have ESLint warnings or errors when run with npm run lint (or npx eslint .). Remember than you can fix many errors automatically with npm run lint -- --fix (although since ESLint can sometimes introduce errors during this process, we suggest committing your code before running "fix" so you can rollback any changes). As described in the README, the assignment skeleton includes the Prettier package and associated hooks to automatically reformat your code to a consistent standard when you commit. Thus do not be surprised if your code looks slightly different after a commit.

Submit your assignment by pushing your changes to GitHub via git push --all origin and then submitting your repository to Gradescope. You can submit (push to GitHub and submit to Gradescope) multiple times. Portions of your assignment will undergo automated assessment. Make sure to follow the specifications exactly, otherwise the tests will fail (even if your code generally works as intended). Use the provided test suite (run with npm test) to get immediate feedback on whether your code follows the specification. Because of the increased complexity of a React application, Gradescope can take minutes to run all of the tests. Thus you will be more efficient testing locally and only submitting to Gradescope when you are confident your application meets the specification.

Advice

You will go astray if you worry too much about the flow of interactions through your application. While information flow is important, focusing on it will have you attempting to code everything linearly. Practice compartmentalization and trusting that other components will work. You should also remember that as you write React components, the primary question should be "given the current state and props, what should I render?"

For example, contemplate the handleClick function that you pass to the ButtonBar. It should be quite simple. A "delete" operation can be carried out immediately, but the other operations require you to change the view (to show the editor). So, how can you change the state so that you will get the correct view (either a populated editor or a fresh one)? In essence, you are going to communicate through the state change to indicate what you want to see next.

FAQ

Do I need to implement unit testing?

We will learn later in the semester how to unit test React components. For this assignment you are not expected to implement any of your own unit tests. The skeleton includes some unit tests to assist you in your development and to ensure that the grading scripts can automatically test your submission.

What if the tests and assignment specification appear to be in conflict?

Please post to Slack so that we can resolve any conflict or confusion ASAP.


Last updated 03/24/2021