Skip to content

Instantly share code, notes, and snippets.

@mxmason
Created December 26, 2017 18:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mxmason/0e3b131a4b3f77531c052c81a4a4af0e to your computer and use it in GitHub Desktop.
Save mxmason/0e3b131a4b3f77531c052c81a4a4af0e to your computer and use it in GitHub Desktop.

Data Structure and Algorithms: Full Stack Project

You've been asked to create a site for an animal shelter which allows adoption of cats and dogs. These are the only two animals allowed in the shelter. The adoption process works strictly on a first-in, first-out basis. People can adopt a cat, or a dog, or both, but they may only adopt the oldest one (by arrival time, not age) that is in the shelter.

The following instructions should guide you to through the project from start to finish. Be sure to follow them in the order!

If you’re the sort of person who likes a working example, you can see the working client and the working server for yourself.

Setting up

This app will use two distinct repositories: one for the client, and one for the server.

  • Create the parent directory for your app on your local machine: mkdir AnimalShelter
  • Move into the directory: cd AnimalShelter

Set up the server

  • Clone the server template repository: git clone https://github.com/Thinkful-Ed/backend-template server
  • Move into the server directory: cd server
  • Install the dependencies: npm install
  • Create a new repo called animalShelter-server on GitHub: https://github.com/new
    • Make sure the "Initialize this repository with a README" option is left unchecked
  • Update the remote to point to your GitHub repository: git remote set-url origin https://github.com/YOUR_GITHUB_USERNAME/animalShelter-server
    • You can now git push to the origin master branch to save this repo on your GitHub

Set up the client

  • Move back to the project directory: cd ..
  • Update create-react-app and then use it to generate our client: npm install -g create-react-app && create-react-app client/
  • Move into the client directory: cd client
  • Install the Redux dependencies our app will need: npm install --save react-redux redux redux-thunk
  • Initialize Git: git init
  • Commit your changes: git add -A; git commit-m "Initial commit"
  • Create a new repo on GitHub called animalShelter-client: https://github.com/new
  • Add a new remote that points to your GitHub repository: git remote add origin https://github.com/YOUR_GITHUB_USERNAME/animalShelter-client
    • Push your changes up to GitHub

Create and test API endpoints

Our app should be able to show us the cat or dog that has been in the shelter the longest, and also be able to remove an animal from the shelter database once it has been adopted. This will require GETing and DELETEing, respectively.

Getting an animal

  • In server/index.js add a GET endpoint at api/cat which returns the following cat information as JSON:
{
  imageURL:'https://assets3.thrillist.com/v1/image/2622128/size/tmg-slideshow_l.jpg',
  imageDescription: 'Orange bengal cat with black stripes lounging on concrete.',
  name: 'Fluffy',
  sex: 'Female',
  age: 2,
  breed: 'Bengal',
  story: 'Thrown on the street'
}
  • Run the server: npm start
  • go to http://localhost:8080/api/cat and look at your cat!
  • In server/index.js add another GET endpoint at api/dog which returns a dog as JSON. You can use the following information:
{
  imageURL: 'http://www.dogster.com/wp-content/uploads/2015/05/Cute%20dog%20listening%20to%20music%201_1.jpg',
  imageDescription: 'A smiling golden-brown golden retreiver listening to music.',
  name: 'Zeus',
  sex: 'Male',
  age: 3,
  breed: 'Golden Retriever',
  story: 'Owner Passed away'
}
  • Go to http:://localhost:8080/api/dog and day hi to your dog!

Adopting an animal out of the shelter

  • Since we want to test the modification of data, move the cat and dog data into arrays declared near the top of your index.js file.
  • Modify your GET handlers so they return the item at the beginning of their respective animal arrays.
  • Write functions to route DELETE requests to each of your API endpoints. Recall that the goal is to adopt the animal that has been waiting in the shelter the longest, so deletion should remove the animal at the beginning of the array.
    • You may want to make some more animals as dummy data.
    • Each new animal you make should contain: an image of the pet; a physical description of the pet; its name, sex, age, and breed; and a story of its journey to the shelter. All of this should be in an object with the same structure as the dummy data you're already using.
  • Use Postman as well to verify that your GET and DELETE endpoints work.

Create a front end with React

Now that a basic version of our API is working, it’s time to work on the client.

Create a React component

  • Make a new file in client/src called Dashboard.js
    • This component should take two props called catToAdopt and dogToAdopt
    • It should render two sections: one for the catToAdopt, and one for the dogToAdopt.
    • Within the sections, there should be a header with the animal’s name and photograph; beneath that, a main with a dl to display the rest of the animal’s information.
      • Be sure that you add an alt attribute to your images that uses the animal’s description!
    • At the bottom of the main, there should be a button with the text Adopt.

Render the React component

  • In index.js, modify the existing call to ReactDOM.render so that it renders<Dashboard/ > instead. Pass the above animal data as the props catToAdopt and dogToAdopt.
  • Run the client: npm start
  • Visit http://localhost:3000. You should see both animals and the information about them.

Refactor the Dashboard component

  • Create a new directory in src called components; in it, create a file called Pet.js.
    • This component should be called twice in the render method of the Dashboard. One should receive the Dashboard’s catToAdopt as its own props; the other should receive dogToAdopt.
    • It should use these props to render the section elements that Dashboard was previously rendering.
    • It should also receive a prop called onAdoptPet, which will be a function that will be called when the Adopt button within the Pet component is clicked.
      • For now, this function can be a simple console.log(); we will make it do more once we add Redux.
    • Don’t forget to pass onAdoptPet to the onClick handler of the button within the Pet component so your console.log() will fire!

Put some Redux in your React

If you need a refresher on actions and reducers, take some time to read the Thinkful lesson on async actions, as well as the Redux documentation for combineReducers, which your app will need.

Actions

  • Make a folder in client/src called actions. In it, make a file called cat.js
    • Write an async action,fetchCat , which uses the Fetch API to make a GET request to your API’s /cat endpoint and should dispatch a corresponding synchronous FETCH_CAT_SUCCESS action.
    • Make sure you also write synchronous actions for initiating the request and handling errors.
  • Do the same for fetching dogs as well: a dog.js action file with fetchDog, and the appropriate synchronous actions.
  • Add an asynchronous adoptCat and adoptDog actions (and corresponding synchronous actions) which use the Fetch API to delete an animal at the appropriate endpoint.
    • Remember that, once the delete request is successful, it should, dispatch fetchCat() or fetchDog() as appropriate to make the next animal available.
  • Finally, you might want to make an index.js file in this folder, through which you can export the actions in the other 2 files to make it easier to import those actions elsewhere.

Reducers

  • Make a src/reducers folder. The files in it should mirror the files in your actions folder.
  • You may want to use the following as a model for cat and dog slices of your state:
{
  data: null,
  error: null,
  loading: false
}

Prove that it works

Before you write proper reducers, do the following so that you can be sure that redux is working:

  • Set one of your dummy cat and dog objects as the data prop of initial state of its appropriate reducer.
  • return the initialState from each reducer
  • use combineReducers in index.js to bring together the cat and dog reducers, then export the combined reducer.
  • Create a store file at client/src/store.js which uses your reducer.
    • Don't forget to apply the Redux Thunk middleware so your async actions work.
  • In client/src/index.js, import the store. You should be able to use store.getState() to see your cat and dog information.
  • Now you can write proper reducers. Set the data prop of each reducer back to null, then handle your request, success, and error actions.

Client-side house-cleaning

  • With your actions hooked up, create a client/.env.development.local and a client/src/config.js file.
    • In .env.development.local, create the variable REACT_APP_API_BASE_URL=http://localhost:8080/api
      • adding .development.local to the filename means the variables in this file won’t be read when we build the app. You can read more about when create-react-app will read a particular .env file.
      • The REACT_APP_ prefix allows create-react-app to send a variable to the app when we run npm run start
    • In config.js export const REACT_APP_API_BASE_URL and set it equal to process.env.REACT_APP_API_BASE_URL.
  • Import that constant from config.js and use it in your actions.

Connect the Dashboard component

  • In client/src/index.js, wrap your component in the React Redux Provider component so it has access to the store.
  • Remove the props which you currently pass to the Dashboard component.
  • Use React Redux to connect your Dashboard to the store, mapping the cat and dog part of the state to the catToAdopt and dogToAdopt props.
  • In the componentDidMount method of your Dashboard component, dispatch the fetchCat and fetchDog actions to fetch the their respective animals.
  • Try reloading your app. You should see both animals.
  • Once you know the actions run in componentDidMount, change the onAdoptPet prop of each Pet so that, instead of console-logging, it dispatches adoptCat or adoptDog as appropriate.
  • Now, you should see one of each animal when the page loads, and get a new animal by clicking one of the adopt buttons. Test that both adopt buttons work!

Enhancing your App

If you have your app deployed, you should look for places to DRY out your code. Do you see any repeated patterns that could be replaced with simpler code? After thinking about that, give the following extension tasks a try:

Task I: User choice for the adoption process

  • Right now, our app shows users both a cat and a dog by default. Add functionality so that the user can do the following:
    • choose to see a cat or a dog or both
    • choose to see the animal that has been in the shelter the longest, regardless of whether it is a cat or a dog

Task II: A database

  • Update your backend so that cat or dog is stored in either a Mongo or a Postgres database. Hint: You can make use of the as-yet-ignored dbConnect variables in server/index.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment