CS142 Project 5: Single Page Applications
Due: Thursday, May 6, 2021 at 11:59 PM
In this project you will use ReactJS with Material-UI to create the beginnings of a photo-sharing web application. In the second half of this project, you'll also explore retrieving data from a server.
You should already have installed Node.js and the npm package manager to your system. If not, follow the installation instructions now.
Create a directory
project5 and extract the contents of
this zip file into the directory.
The zip file contains the starter files for this assignment.
This assignment requires many node modules that contain the tools
ESLint) needed to build a
ReactJS web application as well as
a simple Node.js web server (ExpressJS)
to serve it to your browser.
It also fetches Material-UI which
contain the React components and style sheets we will be using.
These modules can be fetched by
running the following command in the
npm installReactJS and Material-UI are fetched into the
node_modulessubdirectory even though we will be loading it into the browser rather than Node.js.
Like the previous assignment, we can use npm to run the various tools
we had it fetch. The following npm scripts are available
npm run build- Runs Webpack using the configuration file
webpack.config.jsto package all of the projects JSX files into a single JavaScipt bundle in the directory
npm run build:w- Runs Webpack like the "run build" command except it invokes webpack with --watch so it will monitor the React components and regenerates the bundle if any of them change.
Your solutions for all of the problems
below should be implemented in the
As was done with on the previous project you will need to run a web server we provide for you
by running a command in your
As in the last project, you can use the command:
node webServer.js & npm run build:w
Problem 1: Create the Photo Sharing Application (40 points)
As starter code for your PhotoApp we provide you a skeleton (
that can be started
using the URL
Loads a ReactJS web application that
to layout a Master-Detail pattern as described in class. It has a
header made from a
Material-UI App Bar
accross the top,
UserListcomponent along the side, and has a content area beside it with either a
to enable deep linking for our single page application by configuring
routes to three stubbed out components:
/usersis routed to the component
/users/:userIdis routed to the component
/photos/:userIdis routed to the component
photoShare.jsxfor details. For the stubbed out components in
components/*, we provide an empty CSS file and a simple render function that includes some description of what it needs to do and the model data to use.
For this problem, we will continue to use our magic
cs142models hack to provide the model data so we display a pre-entered set of information. As before, the models can be accessed using
window.cs142Models. The schema of the model data is defined below.
Your assignment is to extend the skeleton into a working web app operating on the fake model data.
Since the skeleton is already wired to either display components
with the appropriate parameters passed by React Router,
most of the work will be implementing the stubbed out components.
They should be filled in so that:
components/userListcomponent should provide navigation to the user details of all the users in the system. The component is embedded in the side bar and should provide a list of user names so that when a name is clicked, the content view area switches to display the details of that user.
components/userDetailcomponent is passed a
props.matchby React Router. The view should display the details of the user in a pleasing way along with a link to switch the view area to the photos of the user using the
components/userPhotoscomponent is passed a
userId, and should display all the photos of the specified user. It must display all of the photos belonging to that user. For each photo you must display the photo itself, the creation date/time for the photo, and all of the comments for that photo. For each comment you must display the date/time when the comment was created, the name of the user who created the comment, and the text of the comment. The creator for each comment should be a link that can be clicked to switch to the user detail page for that user.
Besides these components, you need to update the
TopBar component in
components/topBar as follows:
The left side of the
TopBarshould have your name.
The right side of the
TopBarshould provide app context by reflecting what is being shown in the main content region. For example, if the main content is displaying details on a user the toolbar should have the user's name. If it is displaying a user's photos it should say "Photos of " and the user's name.
The use of ReactRouter in the skeleton we provide allows for deep-linking to the different views of the application. Make sure the components you build do not break this capability. It should be possible to do a browser refresh on any view and have it come back as before. Our standard approach to building components handles deep-linking automatically. Care must be taken when doing things like sharing objects between components. A quick browser refresh test on each view will show when you broke something.
Although you don't need to spend a lot of time on the appearance of the app, it should be neat and understandable. The information layout should be clean (e.g., it should be clear which photo each comment applies to).
Photo App Model Data
For this problem we keep the magic DOM loaded model data we used in the previous project. The model consists of four types of objects:
Photos in the photo-sharing site are organized by user.
We will represent users as an object
userwith the following properties:
_id: The ID of this user. first_name: First name of the user. last_name: Last name of the user. location: Location of the user. description: A brief user description. occupation: Occupation of the user.
userobject of the user with id
user_id. The DOM function
window.cs142models.userListModel()returns an array with all
userobjects, one for each the users of the app.
Each user can upload multiple photos. We represent each photo by
photoobject with the following properties:
_id: The ID for this photo. user_id: The ID of the
userwho created the photo.
date_time: The date and time when the photo was added to the database. file_name: Name of a file containing the actual photo (in the directory
comments: An array of the
commentobjects representing the comments made on this photo.
window.cs142models.photoOfUserModel(user_id)returns an array of the
photoobjects belonging to the user with id
For each photo there can be multiple comments (any user can comment on any photo).
commentobjects have the following properties:
_id: The ID for this comment. photo_id: The ID of the
phototo which this comment belongs.
userobject of the user who created the comment.
date_time The date and time when the comment was created. comment The text of the comment.
For testing purposes we have
SchemaInfoobjects have the following properties:
_id: The ID for this SchemaInfo. __v: Version number of the SchemaInfo object. load_date_time: The date and time when the SchemaInfo was loaded. A string.
Problem 2: Fetch model data from the web server (20 points)
webServer.js given out with this project reads in the
we were loading into the DOM in Problem 1 and makes them available using
ExpressJS routes. The API exported by
webServer.js uses HTTP GET requests to particular URLs to return the
cs142Models models. The HTTP response to these GET requests is encoded in JSON.
The API is:
cs142models.schemaInfo(). This URL is useful for testing your model fetching method.
You can see the APIs in action by pointing your browser at above URLs. For example, the
wiil return the JSON-encoded model data in the browser's window.
To convert your app to fetch models from the web server you should implement a FetchModel
lib/fetchModelData.js. The function should be declared as follows:
/* * FetchModel - Fetch a model from the web server. * url - string - The URL to issue the GET request. * Returns: a Promise that should be filled * with the response of the GET request parsed * as a JSON object and returned in the property * named "data" of an object. * If the requests has an error the promise should be * rejected with an object contain the properties: * status: The HTTP response status * statusText: The statusText from the xhr request */
Your solution needs to be able to handle multiple outstanding FetchModel requests.
To demonstrate your FetchModel routine works, your web application should work so
displays the version number returned by sending an AJAX request to the
http://localhost:3000/test/info URL. The version number should
be displayed in the
TopBar component of your app.
After successfully implementing the FetchModel function in
lib/fetchModelData.js, you should modify the code in
window.cs142modelsin your code and your app should work without the line in
Style Points (5 points)
These points will be awarded if your problem solutions have proper MVC decomposition. In addition, your code and components must be clean and readable, and your app must be at least "reasonably nice" in appearance and convenience.
Note that we are using Material-UI, React components that implement Google's Material Design. We have used Material-UI's Grid component to layout the Master-Detail pattern as described in class, and a App Bar header for you. Although you don't need to build a fully Material Design compatible app, you should use Material-UI components when possible.
In addition, remember to run ESLint before submitting. ESLint should raise no errors.
Extra Credit (5 points)
userPhotos component specifies that the display should include
all of a user's photos along the photos' comments. This approach doesn't work well for users with a large numbers of photos. For extra credit you can implement a photo viewer that only shows one photo at a time (along with the photo's comments) and provides a mechanism to step forward or backward through the user's photos (i.e. a stepper).
In order to get extra credit on this assignment your solution must:
- Introduce the concept of "advanced features" to your photo app. On app startup "advanced features" is always disabled. The toolbar on the app should have a checkbox labelled "Enable Advanced Features" that displays the current state of "advanced features" (checked meaning advanced features is enabled) and supports changing the enable/disable state of the advanced features.
- Your app should use the original photo view unless the "advanced features" have been enabled by the checkbox. If enabled, viewing the photos of a user should use the single photo with stepper functionality.
- The user interface for stepping should be something obvious and the mechanism should indicate (e.g. a disabled button) if stepping is not possible in a direction because the user is at the first (for backward stepping) or last photo (for forward stepping).
- Your app should allow individual photos to be bookmarked and shared by copying the URL from the browser location bar. The browser's forward and back buttons should do what would be expected. When entering the app using a deep linked URL to individual photos the stepper functionality should operate as expected.
Warning: Doing this extra credit involves touching various pieces used in the non-extra credit part of the assignment. Adding new functionality guarded by a feature flag is common practice in web applications but has a risk in that if you break the non-extra credit part of the assignment you can lose more points than you could get from the extra credit. Take care.
Use the standard class submission mechanism
to submit the entire application (everything in the
directory). Please clean up your project directory before submitting,
as described in the instructions. In particular, the node_modules directory
is 180MB in size so you won't want to copy it to the Farmshare machines.