This is another gigantic PR, so as usual, I recommend just pulling and testing out the features rather than actually trying to review the whole change set.
1. Loading
We currently have two types of spinners, the FullScreenLoader and the OverlaySpinner. As their names suggest, FullScreenLoader is used for whole page reload and will have a solid white background, whereas OverlaySpinner is more for partial reload, and have translucent background.
Quick summary of how each component knows what is currently loading, and what has completed its loading.
Each redux store action comes in a set of three: _REQUEST, _SUCCESS, and _FAILURE. Before we make query using axios, we dispatch a _REQUEST action, which is caught by our loadingReducer. What loadingReducer does is, it matches literally _REQUEST, _SUCCESS, and _FAILURE for each action it receives, and ignores those that do not contain any of those three ending. Then, if the action was a _REQUEST, it sets loading state to true for that action type, and for _SUCCESS, and _FAILURE, it sets loading state to false.
From a component, we create a loadingSelector with an array of actions we are interested in knowing their loading state for. A loadingSelector is basically a function, that takes in a store state, and returns true if all our interested actions have finished loading, or false otherwise. As an eample, in MyTrecipes page, we have:
// in mapStateToProps
isUpdating: updatingSelector(state),
What this is doing, is creating a loading selector with the three actions to check its loading state for. Then, in `mapStateToProps`, we pass into the selector the current store state, and selector will set the `isUpdating` field properly. The component can then use the `isUpdating` field to decide whether to show spinner or not.
### 2. Error handling
##### Error from async actions, Google API call, server API call
I've created an `errorReducer` to surface error messages from redux actions to component, but none of the component so far needs to know whether an error has occured... so that reducer is kind of unused. Oh well.
Right now, how I handled these type of error is to show a toast for any exception that occured from google api and server calls. Used `react-toastify` for this.
##### Error from unknown path (404)
We have a catch all route in `Pages` that's going to render a 404 page.
![image](https://user-images.githubusercontent.com/33335963/89253302-4088eb80-d5ea-11ea-86d4-0b1ea3ff472d.png)
##### JS exceptions directly thrown from Component
There is something called `ErrorBoundary` that we can use to catch exceptions thrown directly from render, constructor, componentDidMount, DidUpdate, etc. But it WILL NOT catch exceptions thrown from any async code, callback methods.
When an exception is caught using ErrorBoundary, we show this.
![image](https://user-images.githubusercontent.com/33335963/89253553-f48a7680-d5ea-11ea-9eb4-e8e9c270ff9e.png)
You can test this by adding some `throw new Error()` inside a component constructor or any lifecycle method.
### 3. Miscellaneous bug fixes
* Bug with `Save` button in Destination page
While saving the destination to a trecipe, it was causing the uuid of destination to get updated. And many trecipes lost its reference to destination since the uuid was different. Fixed by not updating destination at all hahaha
* Bug in SearchBarPopup when adding/removing destinations
Adding and removing destinations from SearchBarPopup is done by placeId (and not dest uuid). This is because SearchBar deals with destinations directly taken from Google Place API, which may/may not be in our database yet. But when removing, we were using placeId as if it was dest uuid. So nothing was getting removed. Fixed by properly handling remove by place id.
### 4. UI improvements
Added empty content texts to trecipes and destinations. So now it shows some guidance to user instead of a big white blank.
Example of empty trecipes in MyTrecipes page
![image](https://user-images.githubusercontent.com/33335963/89254027-2bad5780-d5ec-11ea-8dca-1bfd033ba91f.png)
Closes #89, #106
This is another gigantic PR, so as usual, I recommend just pulling and testing out the features rather than actually trying to review the whole change set.
1. Loading
We currently have two types of spinners, the
FullScreenLoader
and theOverlaySpinner
. As their names suggest,FullScreenLoader
is used for whole page reload and will have a solid white background, whereasOverlaySpinner
is more for partial reload, and have translucent background.Quick summary of how each component knows what is currently loading, and what has completed its loading.
_REQUEST
,_SUCCESS
, and_FAILURE
. Before we make query using axios, we dispatch a_REQUEST
action, which is caught by ourloadingReducer
. WhatloadingReducer
does is, it matches literally_REQUEST
,_SUCCESS
, and_FAILURE
for each action it receives, and ignores those that do not contain any of those three ending. Then, if the action was a_REQUEST
, it sets loading state to true for that action type, and for_SUCCESS
, and_FAILURE
, it sets loading state to false. From a component, we create a loadingSelector with an array of actions we are interested in knowing their loading state for. A loadingSelector is basically a function, that takes in a store state, and returns true if all our interested actions have finished loading, or false otherwise. As an eample, inMyTrecipes
page, we have:// in mapStateToProps isUpdating: updatingSelector(state),