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.
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
- 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 theorigin master
branch to save this repo on your GitHub
- You can now
- 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
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 GET
ing and DELETE
ing, respectively.
- In
server/index.js
add a GET endpoint atapi/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 atapi/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!
- 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
andDELETE
endpoints work.
Now that a basic version of our API is working, it’s time to work on the client.
- Make a new file in
client/src
calledDashboard.js
- This component should take two props called
catToAdopt
anddogToAdopt
- It should render two
section
s: one for thecatToAdopt
, and one for thedogToAdopt
. - Within the
section
s, there should be aheader
with the animal’s name and photograph; beneath that, amain
with adl
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!
- Be sure that you add an
- At the bottom of the
main
, there should be a button with the textAdopt
.
- This component should take two props called
- In
index.js
, modify the existing call toReactDOM.render
so that it renders<Dashboard/ >
instead. Pass the above animal data as the propscatToAdopt
anddogToAdopt
. - Run the client:
npm start
- Visit http://localhost:3000. You should see both animals and the information about them.
- Create a new directory in
src
calledcomponents
; in it, create a file calledPet.js
.- This component should be called twice in the render method of the
Dashboard
. One should receive theDashboard
’scatToAdopt
as its own props; the other should receivedogToAdopt
. - It should use these props to render the
section
elements thatDashboard
was previously rendering. - It should also receive a prop called
onAdoptPet
, which will be a function that will be called when theAdopt
button within thePet
component is clicked.- For now, this function can be a simple
console.log()
; we will make it do more once we add Redux.
- For now, this function can be a simple
- Don’t forget to pass
onAdoptPet
to theonClick
handler of the button within thePet
component so yourconsole.log()
will fire!
- This component should be called twice in the render method of the
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.
- Make a folder in
client/src
calledactions
. In it, make a file calledcat.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 synchronousFETCH_CAT_SUCCESS
action. - Make sure you also write synchronous actions for initiating the request and handling errors.
- Write an async action,
- Do the same for fetching dogs as well: a
dog.js
action file withfetchDog
, and the appropriate synchronous actions. - Add an asynchronous
adoptCat
andadoptDog
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()
orfetchDog()
as appropriate to make the next animal available.
- Remember that, once the delete request is successful, it should, dispatch
- 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.
- Make a
src/reducers
folder. The files in it should mirror the files in youractions
folder. - You may want to use the following as a model for
cat
anddog
slices of your state:
{
data: null,
error: null,
loading: false
}
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
inindex.js
to bring together thecat
anddog
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 thestore
. You should be able to usestore.getState()
to see your cat and dog information. - Now you can write proper reducers. Set the
data
prop of each reducer back tonull
, then handle your request, success, and error actions.
- With your actions hooked up, create a
client/.env.development.local
and aclient/src/config.js
file.- In
.env.development.local
, create the variableREACT_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 whencreate-react-app
will read a particular.env
file. - The
REACT_APP_
prefix allowscreate-react-app
to send a variable to the app when we runnpm run start
- adding
- In
config.js
exportconst REACT_APP_API_BASE_URL
and set it equal toprocess.env.REACT_APP_API_BASE_URL
.
- In
- Import that constant from
config.js
and use it in your actions.
- In
client/src/index.js
, wrap your component in the React ReduxProvider
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 thecat
anddog
part of the state to thecatToAdopt
anddogToAdopt
props. - In the
componentDidMount
method of yourDashboard
component, dispatch thefetchCat
andfetchDog
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 theonAdoptPet
prop of eachPet
so that, instead of console-logging, it dispatchesadoptCat
oradoptDog
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!
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:
- 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
- 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 inserver/index.js