Skip to content

Latest commit

 

History

History
312 lines (208 loc) · 14 KB

web_engineering_aaa_frontend_demo.md

File metadata and controls

312 lines (208 loc) · 14 KB

aaa-frontend-demo guideline

0. Clone the sample repository

# clone and change cwd
git clone https://github.com/majodev/aaa-frontend-demo.git
cd aaa-frontend-demo

# checkout the initial (fixed) commit
git checkout fc9e950098e735d8ab547e886b5c54487b114398
git checkout -b <your username, e.g. mranftl>

# install the project dependencies
yarn

# open VSCode (eventually disable "files.autoSave": "afterDelay" in your VSCode config)
code .

# start the dev-server
yarn start

# let's get familiar with the project...

All the following sections are bound to specific commits e.g. fc9e950098e735d8ab547e886b5c54487b114398 related to the aaa-frontend-demo git repo and are marked accordingly at the beginning of the section (the end result).

1. Add a dependency to handle Routing

80aa8d58a5a8ce3babfb7e6091e081b15ad05f8f

2. Lifecycle and event handlers

09287ec060c375cc1cc472442e4e93ed6cb16b3c

2.1 Component Lifecycle

2.2 Bound functions (event handlers)

3. Material UI: Drawer and AppBar

12ea8992dac0bd42499f2fd6213a215bc5564376

4. Stateless Components

87b9bb0df15b3b0666468151ef2c41ddaed2f088

5. Decorators, advanced types, context and props.children: i18n

05e493e96a5e64c425dc3393c509356ae5e7f275

5.1 Make the location context available for i18n

ac0f7de42795150e884212472096d254304c5007

  • Casting with TypeScript: We can opt out of compile time safetly for i18n key anytime. This might be useful for mapping paths to i18n keys
  • react-router location inject via withRouter and Partial<RouteComponentProps<any>>
  • This works with TypeScript Generics under the hood
    • / —> path.home
    • /beers —> path.beers
    • /anything —> path.anything
    • /anything/anotherthing —> path.anything.anotherthing

6. Let's have some beers!

6.1 Implement beers remaining counter and a simple list

7471b31689698070ad571790daa5171aad48a6c4

Attention: Only 3600 requests per hour ~1 req/sec are allowed

Special header: x-ratelimit-remaining —>remainingRequests state

6.2 Implement a beer detail route

50d740862a6096ca79f04f00e4cdadc80c364847

7. State Management

First discuss some background on application state (setState vs Flux vs Redux vs MobX)...

7.1 Refactor BeersRoute to observe state change from a global store

17b0ecf9590007716b0a1e6bd059c7f126401b4e

Let's share beer information between the 2 routes —> Application-Wide singleton store for our beers

7.2 Access raw beer information in beerDetailRoute

01a86ce7d15ebe89b3b7dd1f829ed7d8ee916293

  • Reuse already fetched beer if possible
  • selectBeer(id: number)

ES6 / TypeScript Spread Operator

7.3 Bugs and features...

So you've shown your current prototype your project owner come back with a list of bugs and new features:

  • (7.3.1, code smell): Remove duplicated code (duplicate loading flags, fetch handling)
  • (7.3.1, bug): Go from single beer site to beer list should actually work
  • (7.3.1, bug): Beer should not be visible if we revisit the site (while loading a new single beer)
  • (7.3.1, feature): Sort beer list alphabetically
  • (7.3.2, feature): Single Beer or beers list were already loaded? Use that!. However still only load the single beer if on the detail page!
  • (7.3.2, feature): Single shared loading information if the store is currently fetching something from any endpoint.
  • (7.3.2, feature): Counter how many requests were currently successfully made by the store
  • (7.3.3 feature): Error handling: Alert on fetch errors (mui.SnackBar): e.g. id was not found, id is not a number or on request errors
  • (7.3.3 feature): The beer detail page should use the same header as the beer list page.
7.3.1 Remove code smell, deselectBeer and sort

d049151912ca31915cbcbe7cd6c7f759f2d86948

  • Start by defining a single getBeersApi(id?: number): Promise<IBeer[]> fn
  • All requests pipe through unionAndSortBeers(newBeers: IBeer[]):IBeer[]
  • _.sortBy
  • _.unionWith
7.3.2 @computed and ObservableMap

ca9ebb5d651ed2edd46f3b55aeab390749beb2d5

7.3.3 Same title bar on both beer related pages and error alerts

c5ae2408da3b06d516c42782ccac98229242f103

  • We need to have an Alert like functionality if something is not right.
    • try/catch handle this in our state store but allow to dismiss it
  • Furthermore we need to further split our components to show this alert (and the title heading) on both routes —> Child Routes
    • Route can appear anywhere in your component, but not as direct a
  • mui.Snackbar

8. Beer detail page

21e849d7b4093be41043536fbe1b61594c91f19a

Lets style the beer detail!

9. Persist state client side and flexbox alignments

13da51ba24cfab374bd168c0ae109281c0861cc8

10. Like (& unlike) beers

80c7ff8dc8b6ad24425acefe035b16b98e8815ab

  • Use a combination of @observable, @computed.
  • Icon: action/thumb-up
  • mui.CardActions inside mui.Card
  • Icon Example of mui.RaisedButton (Icon only, 2 states!)
  • ListIcon use rightIcon

10.1 Show liked beers in sidebar and add a counter

f00f4859cf90c65c7b72d638d0dfe5ecc0addf41

10.2 autorun and caching (+ fix unlike bug)

740b3541424f89bbc1d0b32aa84dcd098d358afe

  • In preparation for server side loading: what if we have multiple liked beers in our store, but no information on them yet
  • autorun: Autoruns are about initiating effects, not about producing new values.
  • _.remove fix.

10.3 (optional) wipe dialog

7ace09826fdd5df835fae608cb1d4c487efbfeca

  • View state vs. global state
  • mui.Dialog for beerState.wipe()

11. Forms: Comment your beer

  • TextInput and Submit-Button
    • Submit Button should only be enabled if the form was changed since the last submit
  • Comment validations (feedback must be shown to the user):
    • Should not start or end with a space
    • Should have max length of 35 characters
    • Should not have multiple spaces
    • An empty comment is allowed and will trigger a delete of the comment

11.1 BeerCommentForm

6e275cdf9f97e85f6c84f2f7b6daf9e0ff9d9f09

11.2 Connect to state

d642364f086ff3873eb44b1712eea75bfa74c285

  • Another map in our state.

12. Login: Guest access token

bf055ea3214782f00dbffa179eae6c1e3f953e08

13. Save likes and comments on the server

bc68b97edc15ff6d3fe63888cf467634d8849942

  • PATCH /app/v1/user/profile allows to set save any JSON data on the user profile
  • your likes / comments count
  • Push local changes to the server if we are authenticated...
  • We won't get it again (no synchronization will take place, local state will always overwrite user server state)
  • Could be easily done while rehydration, same as getting the user profile (testing the connection) in the authState

14. Show global liked count and other user comments

bcf43a9e0e077ad4c1657ad141587675105ea7a6

  • GET /app/v1/beers-info allows to retrieve all updated likes and comments from all beers
    • Public endpoint, try it out.
type IBeersInfo = {
    globalLikes: { [id: string]: number },
    globalComments: { [id: string]: { user: string, comment: string }[] }
};

15. Deploy to GitHub Pages (optional)

Let's try out an easy way to host your static bundle for free (requires a working GitHub account).

Reference Docs

TL;DR:

  • Install the gh-pages package through yarn: yarn add --dev gh-pages.
  • Add a homepage property to package.json. See here.
  • Add scripts for predeploy and deploy in your package.json. See here.