├── .gitignore
├── 00-props-state
├── README.md
└── search-example
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── actions.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── reducers.js
│ └── serviceWorker.js
├── 01-react-hooks
├── README.md
└── hooks-example
│ ├── .eslintrc
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
│ ├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── brace_yourselves.jpg
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── serviceWorker.js
│ ├── useCustom
│ │ ├── class.jsx
│ │ ├── hook.jsx
│ │ └── index.jsx
│ ├── useEffect
│ │ ├── class.jsx
│ │ └── hook.jsx
│ └── useState
│ │ ├── class.jsx
│ │ └── hook.jsx
│ └── yarn.lock
├── 02-component-patterns
├── .prettierrc
├── README.md
├── exercises
│ ├── compound-components
│ │ ├── exercise-solution
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── Stepper.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ ├── exercise
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── Stepper.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ ├── lecture-solution
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── Logo.js
│ │ │ │ ├── Navigation.js
│ │ │ │ ├── SearchBar.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ └── lecture
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ └── manifest.json
│ │ │ └── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── Logo.js
│ │ │ ├── Navigation.js
│ │ │ ├── SearchBar.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── serviceWorker.js
│ ├── controlled-components
│ │ ├── exercise-solution
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── Stepper.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ ├── exercise
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── Stepper.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ ├── lecture-solution
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── RadioGroup.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ └── lecture
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ └── manifest.json
│ │ │ └── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── RadioGroup.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── serviceWorker.js
│ ├── higher-order-components
│ │ ├── exercise-solution
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── App.test.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ ├── exercise
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ ├── lecture-solution
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── index.html
│ │ │ │ └── manifest.json
│ │ │ └── src
│ │ │ │ ├── App.css
│ │ │ │ ├── App.js
│ │ │ │ ├── App.test.js
│ │ │ │ ├── NetworkStatus.js
│ │ │ │ ├── index.css
│ │ │ │ ├── index.js
│ │ │ │ └── serviceWorker.js
│ │ └── lecture
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ └── manifest.json
│ │ │ └── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── NetworkStatus.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── serviceWorker.js
│ └── render-props
│ │ ├── exercise-solution
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ └── manifest.json
│ │ └── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── Count.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── serviceWorker.js
│ │ ├── exercise
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ └── manifest.json
│ │ └── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── Count.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── serviceWorker.js
│ │ ├── lecture-solution
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ └── manifest.json
│ │ └── src
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── Fetch.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── serviceWorker.js
│ │ └── lecture
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ │ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── Fetch.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── serviceWorker.js
└── package.json
├── 03-css-debugging
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── src
│ ├── App.js
│ ├── App.scss
│ ├── App.test.js
│ ├── examples
│ ├── 00-intro.js
│ ├── 01-vertical-alignment.js
│ ├── 02-z-index.js
│ ├── 03-selector-specificity.js
│ ├── 04-responsive-design.js
│ ├── 05-transitions.js
│ ├── examples.scss
│ └── index.js
│ ├── index.css
│ ├── index.js
│ └── lib
│ ├── index.js
│ └── lib.scss
├── 04-suspense-and-async-mode
├── .eslintrc
├── README.md
├── exercise-fetch-solution
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── spinner.css
│ │ └── spinner.jsx
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── pages
│ │ ├── content.jsx
│ │ ├── home.jsx
│ │ ├── kitties.css
│ │ └── kitties.jsx
├── exercise-fetch
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── spinner.css
│ │ └── spinner.jsx
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── pages
│ │ ├── content.jsx
│ │ ├── home.jsx
│ │ ├── kitties.css
│ │ └── kitties.jsx
├── exercise-lazy-solution
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── spinner.css
│ │ └── spinner.jsx
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── pages
│ │ ├── content.jsx
│ │ ├── home.jsx
│ │ └── prague-image.jsx
├── exercise-lazy
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── components
│ │ ├── spinner.css
│ │ └── spinner.jsx
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── pages
│ │ ├── content.jsx
│ │ ├── home.jsx
│ │ └── prague-image.jsx
└── images
│ ├── concurrent_lifecycle_methods.jpeg
│ └── concurrent_mode_explained.png
├── 05-component-testing
├── .gitignore
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── Fetcher.tsx
│ ├── Movie.tsx
│ ├── MovieList.tsx
│ ├── __tests__
│ │ ├── exercise.001.test.jsx
│ │ ├── exercise.002.test.jsx
│ │ ├── exercise.003.test.jsx
│ │ └── exercise.004.test.jsx
│ ├── actions
│ │ └── wishlistAction.ts
│ ├── index.css
│ ├── index.tsx
│ ├── logo.svg
│ ├── playground.test.jsx
│ ├── react-app-env.d.ts
│ ├── reducers
│ │ ├── index.ts
│ │ └── wishlistReducer.ts
│ ├── serviceWorker.ts
│ └── store.ts
└── tsconfig.json
├── 06-graphql
├── README.md
├── backend
│ ├── app.js
│ ├── getData.js
│ ├── graphqlSchema.js
│ ├── package-lock.json
│ └── package.json
└── web
│ ├── babel.config.js
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── components
│ │ ├── Character.js
│ │ ├── Character.scss
│ │ ├── CharacterSheet.js
│ │ └── CharacterSheet.scss
│ ├── graphqlRequest.js
│ ├── helpers
│ │ └── getRandomCharacterIds.js
│ ├── index.html
│ └── index.js
│ ├── webpack.common.js
│ ├── webpack.dev.js
│ └── webpack.prod.js
├── 07-firebase
├── README.md
├── excersise
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── src
│ │ ├── components
│ │ │ ├── Account
│ │ │ │ └── index.js
│ │ │ ├── Admin
│ │ │ │ └── index.js
│ │ │ ├── App
│ │ │ │ └── index.js
│ │ │ ├── Firebase
│ │ │ │ ├── context.js
│ │ │ │ ├── firebase.js
│ │ │ │ └── index.js
│ │ │ ├── Home
│ │ │ │ └── index.js
│ │ │ ├── Landing
│ │ │ │ └── index.js
│ │ │ ├── Navigation
│ │ │ │ └── index.js
│ │ │ ├── PasswordChange
│ │ │ │ └── index.js
│ │ │ ├── PasswordForget
│ │ │ │ └── index.js
│ │ │ ├── Session
│ │ │ │ ├── context.js
│ │ │ │ ├── index.js
│ │ │ │ ├── withAuthentication.js
│ │ │ │ └── withAuthorization.js
│ │ │ ├── SignIn
│ │ │ │ └── index.js
│ │ │ ├── SignOut
│ │ │ │ └── index.js
│ │ │ └── SignUp
│ │ │ │ └── index.js
│ │ ├── constants
│ │ │ └── routes.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── serviceWorker.js
│ └── yarn.lock
└── solution
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
│ ├── src
│ ├── components
│ │ ├── Account
│ │ │ └── index.js
│ │ ├── Admin
│ │ │ └── index.js
│ │ ├── App
│ │ │ └── index.js
│ │ ├── Firebase
│ │ │ ├── context.js
│ │ │ ├── firebase.js
│ │ │ └── index.js
│ │ ├── Home
│ │ │ └── index.js
│ │ ├── Landing
│ │ │ └── index.js
│ │ ├── Navigation
│ │ │ └── index.js
│ │ ├── PasswordChange
│ │ │ └── index.js
│ │ ├── PasswordForget
│ │ │ └── index.js
│ │ ├── Session
│ │ │ ├── context.js
│ │ │ ├── index.js
│ │ │ ├── withAuthentication.js
│ │ │ └── withAuthorization.js
│ │ ├── SignIn
│ │ │ └── index.js
│ │ ├── SignOut
│ │ │ └── index.js
│ │ └── SignUp
│ │ │ └── index.js
│ ├── constants
│ │ └── routes.js
│ ├── index.css
│ ├── index.js
│ └── serviceWorker.js
│ └── yarn.lock
├── 08-testing-hooks
├── .gitignore
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── 01
│ │ ├── 01-exercise.js
│ │ ├── 01-exercise.test.js
│ │ ├── 01-solution.js
│ │ └── 01-solution.test.js
│ ├── 02
│ │ ├── 02-exercise.js
│ │ ├── 02-exercise.test.js
│ │ ├── 02-solution.js
│ │ └── 02-solution.test.js
│ ├── 03
│ │ ├── 03-exercise.js
│ │ ├── 03-exercise.test.js
│ │ ├── 03-solution.js
│ │ └── 03-solution.test.js
│ ├── 04
│ │ ├── 04-exercise.js
│ │ ├── 04-exercise.test.js
│ │ ├── 04-solution.js
│ │ └── 04-solution.test.js
│ ├── 05
│ │ ├── 05-exercise.js
│ │ ├── 05-exercise.test.js
│ │ ├── 05-solution.js
│ │ └── 05-solution.test.js
│ ├── 06
│ │ ├── 06-solution.js
│ │ ├── 06-solution.test.js
│ │ └── react-redux.js
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ └── serviceWorker.js
└── yarn.lock
├── 09-typescript-in-react
├── .gitignore
├── .prettierrc
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── IMG_5437.JPG
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── exercise-1
│ │ ├── blog.jsx
│ │ └── index.tsx
│ ├── exercise-2
│ │ ├── fetch-jokes.ts
│ │ ├── index.tsx
│ │ └── jokes.jsx
│ ├── exercise-3
│ │ ├── clock.jsx
│ │ └── index.tsx
│ ├── homepage
│ │ ├── homepage.tsx
│ │ └── index.tsx
│ ├── index.css
│ ├── index.tsx
│ ├── react-app-env.d.ts
│ ├── sandbox.tsx
│ ├── solution-1
│ │ ├── blog.tsx
│ │ └── index.tsx
│ ├── solution-2
│ │ ├── fetch-jokes.ts
│ │ ├── index.tsx
│ │ └── jokes.tsx
│ ├── solution-3
│ │ ├── clock.tsx
│ │ └── index.tsx
│ ├── use-context
│ │ ├── index.tsx
│ │ └── use-context.tsx
│ └── use-reducer
│ │ ├── index.tsx
│ │ └── use-reducer.tsx
└── tsconfig.json
├── 10-suspense-for-data-fetching
├── .eslintrc.js
├── .gitignore
├── .prettierrc.js
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── public
│ └── index.html
├── src
│ ├── 01-exercise-suspense
│ │ └── index.tsx
│ ├── 02-exercise-error-boundaries
│ │ ├── index.tsx
│ │ └── people.tsx
│ ├── 03-exercise-loading-states
│ │ ├── index.tsx
│ │ ├── people.tsx
│ │ ├── person.tsx
│ │ ├── searchForm.tsx
│ │ └── style.css
│ ├── 04-exercise-suspense-list
│ │ ├── index.tsx
│ │ ├── leftNav.tsx
│ │ ├── mainContent.tsx
│ │ ├── navBar.tsx
│ │ ├── rightNav.tsx
│ │ ├── spinner.tsx
│ │ └── style.css
│ ├── app.tsx
│ ├── index.tsx
│ └── utils
│ │ ├── errorBoundary.tsx
│ │ ├── fetch.ts
│ │ ├── types.ts
│ │ └── wrapPromise.ts
└── tsconfig.json
├── LICENSE
└── README.md
/00-props-state/search-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "00-props-state",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0-alpha",
7 | "react-dom": "^16.7.0-alpha",
8 | "react-scripts": "2.1.1",
9 | "redux": "^4.0.1",
10 | "redux-thunk": "^2.3.0",
11 | "react-redux": "^5.1.0"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test",
17 | "eject": "react-scripts eject"
18 | },
19 | "eslintConfig": {
20 | "extends": "react-app"
21 | },
22 | "browserslist": [
23 | ">0.2%",
24 | "not dead",
25 | "not ie <= 11",
26 | "not op_mini all"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/00-props-state/search-example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/00-props-state/search-example/public/favicon.ico
--------------------------------------------------------------------------------
/00-props-state/search-example/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/00-props-state/search-example/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | justify-content: space-between;
6 | height: 90vh;
7 | padding-top: 5vh;
8 | }
9 |
--------------------------------------------------------------------------------
/00-props-state/search-example/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/00-props-state/search-example/src/actions.js:
--------------------------------------------------------------------------------
1 | const fakeRes1 = [{title: 'Result 1', body: 'Long Description', more: 'abc'}]
2 | const fakeRes2 = [{title: 'Result 1', body: 'Description D', more: 'def'}, {title: 'Result 2', body: 'Description E'}]
3 | const getHash = () => window.decodeURI(window.location.hash.substr(1))
4 |
5 | export const setRoute = route => ({type: 'SET_ROUTE', route})
6 | export const setQuery = query => ({type: 'SET_QUERY', query})
7 | export const setResults = results => ({type: 'SET_RESULTS', results})
8 |
9 | export const setRouteAndSubmit = route => dispatch => {
10 | window.location.hash = route
11 | dispatch(setRoute(route))
12 | dispatch(setResults([]))
13 | setTimeout(() => {
14 | dispatch(setResults(Math.random() < 0.5 ? fakeRes1 : fakeRes2))},
15 | 500
16 | )
17 | }
18 |
19 | export const loadRoute = () => dispatch => {
20 | const hash = getHash()
21 | dispatch(setRouteAndSubmit(hash))
22 | dispatch(setQuery(hash))
23 | }
24 |
--------------------------------------------------------------------------------
/00-props-state/search-example/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/00-props-state/search-example/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import {createStore, applyMiddleware, compose} from 'redux';
5 | import thunk from 'redux-thunk';
6 | import rootReducer from './reducers'
7 | import {loadRoute} from './actions';
8 | import './index.css';
9 | import App from './App';
10 | import * as serviceWorker from './serviceWorker';
11 |
12 | const store = createStore(
13 | rootReducer,
14 | compose(
15 | applyMiddleware(thunk),
16 | window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
17 | )
18 | )
19 |
20 | ReactDOM.render(
21 |
22 |
23 | ,
24 | document.getElementById('root')
25 | );
26 |
27 | const dispatchLoadRoute = () => store.dispatch(loadRoute())
28 | dispatchLoadRoute()
29 | window.onhashchange = dispatchLoadRoute
30 |
31 | // If you want your app to work offline and load faster, you can change
32 | // unregister() to register() below. Note this comes with some pitfalls.
33 | // Learn more about service workers: http://bit.ly/CRA-PWA
34 | serviceWorker.unregister();
35 |
--------------------------------------------------------------------------------
/00-props-state/search-example/src/reducers.js:
--------------------------------------------------------------------------------
1 | const initialState = {route: '', query: '', results: []}
2 |
3 | const reducer = (state = initialState, action) => {
4 | const {type, route, query, results} = action
5 | switch (type) {
6 | case 'SET_ROUTE': return {...state, route}
7 | case 'SET_QUERY': return {...state, query}
8 | case 'SET_RESULTS': return {...state, results}
9 | default: return state
10 | }
11 | }
12 |
13 | export default reducer
14 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/README.md:
--------------------------------------------------------------------------------
1 | ## To run the application
2 |
3 | If you've just downloaded the code and you are running the application
4 | for the first time, go to the project directory and install all packages
5 |
6 | ```shell
7 | npm ci
8 | ```
9 |
10 | Then, you can run the app in the development mode:
11 |
12 | ```shell
13 | npm start
14 | ```
15 |
16 | The page will reload if you make edits.
17 | You will also see any lint errors in the console.
18 |
19 | ```shell
20 | npm run build
21 | ```
22 |
23 | Builds the app for production to the `build` folder.
24 | It correctly bundles React in production mode and optimizes the build for the best performance.
25 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-hooks",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0-alpha.2",
7 | "react-dom": "^16.7.0-alpha.2",
8 | "react-router-dom": "^4.3.1",
9 | "react-scripts": "2.1.1"
10 | },
11 | "scripts": {
12 | "build": "react-scripts build",
13 | "eject": "react-scripts eject",
14 | "eslint": "eslint --ext .js --ext .jsx .",
15 | "lint": "npm run eslint",
16 | "start": "react-scripts start",
17 | "test": "react-scripts test"
18 | },
19 | "eslintConfig": {
20 | "extends": "react-app"
21 | },
22 | "browserslist": [
23 | ">0.2%",
24 | "not dead",
25 | "not ie <= 11",
26 | "not op_mini all"
27 | ],
28 | "devDependencies": {
29 | "eslint": "^5.9.0"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/01-react-hooks/hooks-example/public/favicon.ico
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/brace_yourselves.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/01-react-hooks/hooks-example/src/brace_yourselves.jpg
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | body, html {
12 | background-color: #282c34;
13 | }
14 |
15 | code {
16 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
17 | monospace;
18 | }
19 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister();
13 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/useCustom/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {JokeList} from './class';
3 |
4 | export class ChuckJokes extends Component {
5 | state = {
6 | searchInput: '',
7 | query: ''
8 | };
9 |
10 | _handleQueryChange = e => {
11 | this.setState({
12 | searchInput: e.target.value
13 | });
14 | };
15 |
16 | _triggerSearch = e => {
17 | const {searchInput} = this.state;
18 | e.preventDefault();
19 | this.setState({
20 | query: searchInput
21 | });
22 | };
23 |
24 | render() {
25 | const {query} = this.state;
26 | return (
27 |
28 |
34 |
35 |
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/useEffect/class.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export class MyMouse extends React.Component {
4 | state = {
5 | x: 0,
6 | y: 0
7 | }
8 |
9 | componentDidMount() {
10 | window.addEventListener('mousemove', this.onMouseMove);
11 | }
12 |
13 | componentWillUnmount() {
14 | window.removeEventListener('mousemove', this.onMouseMove);
15 | }
16 |
17 | onMouseMove = event => {
18 | this.setState({
19 | x: event.clientX,
20 | y: event.clientY
21 | });
22 | }
23 |
24 | render = () => {
25 | const {x, y} = this.state;
26 | return (
27 | My mouse x position is {x} and y position is {y}
28 | );
29 | }
30 | }
31 |
32 | export const MyMouseHook = () => {
33 | // @TODO useEffect, mount and unmount vs. update, un/bk
34 | };
35 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/useEffect/hook.jsx:
--------------------------------------------------------------------------------
1 | import React, {useState, useEffect} from 'react';
2 |
3 | export const MyMouse = () => {
4 | const [mousePosition, setMousePosition] = useState({x: 0, y: 0});
5 | const onMouseMove = event => {
6 | setMousePosition({
7 | x: event.clientX,
8 | y: event.clientY
9 | });
10 | };
11 | useEffect(() => {
12 | window.addEventListener('mousemove', onMouseMove);
13 | return () => {
14 | window.removeEventListener('mousemove', onMouseMove);
15 | };
16 | }, []);
17 | const {x, y} = mousePosition;
18 | return (
19 | My mouse x position is {x} and y position is {y}
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/useState/class.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export class MyStatus extends React.Component {
4 | state = {
5 | myStatus: 'cool'
6 | }
7 | switchMyStatus = () => {
8 | const {myStatus} = this.state;
9 | this.setState({myStatus: (myStatus === 'cool') ? 'awesome' : 'cool'});
10 | }
11 | render = () => (
12 |
13 |
I am {this.state.myStatus}
14 |
15 |
16 | );
17 | }
18 |
19 | export const MyStatusHook = () => {
20 | // @TODO for superman and batman
21 | };
22 |
--------------------------------------------------------------------------------
/01-react-hooks/hooks-example/src/useState/hook.jsx:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 |
3 | export const MyStatus = () => {
4 | // whatever we pass to useState function will become the initial value
5 | const [myStatus, setMyStatus] = useState('cool');
6 | return (
7 |
8 |
I am {myStatus}
9 |
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/02-component-patterns/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": false,
6 | "singleQuote": true,
7 | "trailingComma": "none",
8 | "bracketSpacing": false,
9 | "jsxBracketSameLine": true,
10 | "arrowParens": "always"
11 | }
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exercise-solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/compound-components/exercise-solution/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise-solution/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | display: flex;
3 | }
4 |
5 | .stepper {
6 | margin: 50px auto;
7 | padding: 15px;
8 | border: 1px solid #efefef;
9 | border-radius: 4px;
10 | text-align: center;
11 | max-width: 80%;
12 | }
13 |
14 | .stepper-status {
15 | display: flex;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: 12px;
19 | margin: 10px 0px;
20 | }
21 |
22 | .status-item {
23 | cursor: pointer;
24 | }
25 |
26 | .status-divider {
27 | width: 15px;
28 | display: inline-block;
29 | height: 1px;
30 | border-top: 1px solid #afb1b3;
31 | margin: 5px;
32 | margin-top: 7px;
33 | }
34 |
35 | .step-btn {
36 | background-color: #0064ff;
37 | color: white;
38 | border: none;
39 | padding: 5px 10px;
40 | border-radius: 4px;
41 | outline: none;
42 | margin-right: 10px;
43 | cursor: pointer;
44 | }
45 |
46 | .step-btn:disabled {
47 | background-color: #8bb8ff;
48 | cursor: not-allowed;
49 | }
50 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise-solution/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | import Stepper from './Stepper'
4 | import './App.css'
5 |
6 | const steps = [
7 | {
8 | title: 'First Step!',
9 | content: 'Here is the first step, its really good.'
10 | },
11 | {
12 | title: 'Second Step!',
13 | content: 'First is the worst, second the best'
14 | },
15 | {
16 | title: 'Third Step!',
17 | content: 'THIRD STEP YOU MADE IT, GOOD JOB!'
18 | }
19 | ]
20 |
21 | const App = () => (
22 |
23 |
24 |
25 |
26 |
27 | )
28 |
29 | export default App
30 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "excersise",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/compound-components/exercise/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | display: flex;
3 | }
4 |
5 | .stepper {
6 | margin: 50px auto;
7 | padding: 15px;
8 | border: 1px solid #efefef;
9 | border-radius: 4px;
10 | text-align: center;
11 | max-width: 80%;
12 | }
13 |
14 | .stepper-status {
15 | display: flex;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: 12px;
19 | margin: 10px 0px;
20 | }
21 |
22 | .status-item {
23 | cursor: pointer;
24 | }
25 |
26 | .status-divider {
27 | width: 15px;
28 | display: inline-block;
29 | height: 1px;
30 | border-top: 1px solid #afb1b3;
31 | margin: 5px;
32 | margin-top: 7px;
33 | }
34 |
35 | .step-btn {
36 | background-color: #0064ff;
37 | color: white;
38 | border: none;
39 | padding: 5px 10px;
40 | border-radius: 4px;
41 | outline: none;
42 | margin-right: 10px;
43 | cursor: pointer;
44 | }
45 |
46 | .step-btn:disabled {
47 | background-color: #8bb8ff;
48 | cursor: not-allowed;
49 | }
50 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/exercise/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lecture-solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@fortawesome/fontawesome-free-solid": "^5.0.13",
7 | "@fortawesome/fontawesome-svg-core": "^1.2.12",
8 | "@fortawesome/react-fontawesome": "^0.1.3",
9 | "classnames": "^2.2.6",
10 | "react": "^16.7.0",
11 | "react-dom": "^16.7.0",
12 | "react-router-dom": "^4.3.1",
13 | "react-scripts": "2.1.3"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": "react-app"
23 | },
24 | "browserslist": [
25 | ">0.2%",
26 | "not dead",
27 | "not ie <= 11",
28 | "not op_mini all"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/compound-components/lecture-solution/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/src/App.css:
--------------------------------------------------------------------------------
1 | .nav {
2 | list-style: none;
3 | display: flex;
4 | border-bottom: 1px solid #efefef;
5 | height: 50px;
6 | margin: 0;
7 | background-color: #282c34;
8 | color: #efefef;
9 | align-items: center;
10 | padding: 0px 15px;
11 | }
12 |
13 | .nav li {
14 | padding-right: 10px;
15 | }
16 |
17 | .nav a {
18 | color: white;
19 | text-decoration: none;
20 | }
21 |
22 | .nav-split {
23 | margin-left: auto;
24 | margin-right: auto;
25 | }
26 |
27 | .nav-active a {
28 | color: pink;
29 | }
30 |
31 | .searchbar {
32 | border: none;
33 | padding: 4px;
34 | border-radius: 2px;
35 | min-width: 150px;
36 | margin-right: 10px;
37 | outline: none;
38 | }
39 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 | import './App.css'
3 | import Navigation from './Navigation'
4 | import SearchBar from './SearchBar'
5 | import Logo from './Logo'
6 |
7 | class App extends Component {
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
24 | }
25 |
26 | export default App
27 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/src/Logo.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
3 | import {faCrow} from '@fortawesome/fontawesome-free-solid'
4 |
5 | const Logo = () =>
6 |
7 | export default Logo
8 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/src/SearchBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const SearchBar = () =>
4 |
5 | export default SearchBar
6 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lecture",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@fortawesome/fontawesome-free-solid": "^5.0.13",
7 | "@fortawesome/fontawesome-svg-core": "^1.2.12",
8 | "@fortawesome/react-fontawesome": "^0.1.3",
9 | "classnames": "^2.2.6",
10 | "react": "^16.7.0",
11 | "react-dom": "^16.7.0",
12 | "react-router-dom": "^4.3.1",
13 | "react-scripts": "2.1.3"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": "react-app"
23 | },
24 | "browserslist": [
25 | ">0.2%",
26 | "not dead",
27 | "not ie <= 11",
28 | "not op_mini all"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/compound-components/lecture/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/src/App.css:
--------------------------------------------------------------------------------
1 | .nav {
2 | list-style: none;
3 | display: flex;
4 | border-bottom: 1px solid #efefef;
5 | height: 50px;
6 | margin: 0;
7 | background-color: #282c34;
8 | color: #efefef;
9 | align-items: center;
10 | padding: 0px 15px;
11 | }
12 |
13 | .nav li {
14 | padding-right: 10px;
15 | }
16 |
17 | .nav a {
18 | color: white;
19 | text-decoration: none;
20 | }
21 |
22 | .nav-split {
23 | margin-left: auto;
24 | margin-right: auto;
25 | }
26 |
27 | .nav-active a {
28 | color: pink;
29 | }
30 |
31 | .searchbar {
32 | border: none;
33 | padding: 4px;
34 | border-radius: 2px;
35 | min-width: 150px;
36 | margin-right: 10px;
37 | outline: none;
38 | }
39 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 | import Navigation from './Navigation'
3 | import Logo from './Logo'
4 |
5 | // Compound components!
6 | const navItems = [
7 | {to: '/', label: 'Home'},
8 | {to: '/messages', label: 'Messages'},
9 | {to: '/notifications', label: 'Notifications'},
10 | {to: '/profile', label: 'Profile'}
11 | ]
12 |
13 | class App extends Component {
14 | render() {
15 | return (
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 | export default App
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/src/Logo.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
3 | import {faCrow} from '@fortawesome/fontawesome-free-solid'
4 |
5 | const Logo = () =>
6 |
7 | export default Logo
8 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/src/Navigation.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 | import cx from 'classnames'
3 | import {BrowserRouter as Router, Link} from 'react-router-dom'
4 |
5 | import './App.css'
6 |
7 | const NavigationItem = ({label, to, isActive}) => (
8 |
12 | {label}
13 |
14 | )
15 |
16 | class Navigation extends React.Component {
17 | static Item = NavigationItem
18 | // Pretend this is dynamic and must be
19 | // read from state!
20 | state = {active: 'Home'}
21 | render() {
22 | const {children} = this.props
23 | return (
24 |
27 | )
28 | }
29 | }
30 |
31 | export default Navigation
32 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/src/SearchBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const SearchBar = () =>
4 |
5 | export default SearchBar
6 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/compound-components/lecture/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exercise-solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/controlled-components/exercise-solution/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise-solution/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | display: flex;
3 | }
4 |
5 | .stepper {
6 | margin: 50px auto;
7 | padding: 15px;
8 | border: 1px solid #efefef;
9 | border-radius: 4px;
10 | text-align: center;
11 | max-width: 80%;
12 | }
13 |
14 | .stepper-status {
15 | display: flex;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: 12px;
19 | margin: 10px 0px;
20 | }
21 |
22 | .status-item {
23 | cursor: pointer;
24 | }
25 |
26 | .status-divider {
27 | width: 15px;
28 | display: inline-block;
29 | height: 1px;
30 | border-top: 1px solid #afb1b3;
31 | margin: 5px;
32 | margin-top: 7px;
33 | }
34 |
35 | .step-btn {
36 | background-color: #0064ff;
37 | color: white;
38 | border: none;
39 | padding: 5px 10px;
40 | border-radius: 4px;
41 | outline: none;
42 | margin-right: 10px;
43 | cursor: pointer;
44 | }
45 |
46 | .step-btn:disabled {
47 | background-color: #8bb8ff;
48 | cursor: not-allowed;
49 | }
50 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exercise",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/controlled-components/exercise/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | display: flex;
3 | }
4 |
5 | .stepper {
6 | margin: 50px auto;
7 | padding: 15px;
8 | border: 1px solid #efefef;
9 | border-radius: 4px;
10 | text-align: center;
11 | max-width: 80%;
12 | }
13 |
14 | .stepper-status {
15 | display: flex;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: 12px;
19 | margin: 10px 0px;
20 | }
21 |
22 | .status-item {
23 | cursor: pointer;
24 | }
25 |
26 | .status-divider {
27 | width: 15px;
28 | display: inline-block;
29 | height: 1px;
30 | border-top: 1px solid #afb1b3;
31 | margin: 5px;
32 | margin-top: 7px;
33 | }
34 |
35 | .step-btn {
36 | background-color: #0064ff;
37 | color: white;
38 | border: none;
39 | padding: 5px 10px;
40 | border-radius: 4px;
41 | outline: none;
42 | margin-right: 10px;
43 | cursor: pointer;
44 | }
45 |
46 | .step-btn:disabled {
47 | background-color: #8bb8ff;
48 | cursor: not-allowed;
49 | }
50 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/exercise/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lecture-solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/controlled-components/lecture-solution/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | flex-direction: column;
6 | height: 100vh;
7 | }
8 |
9 | .radio-group {
10 | display: flex;
11 | width: 85px;
12 | border: none;
13 | border-radius: 3px;
14 | }
15 |
16 | .radio-group-item {
17 | margin-top: 5px;
18 | justify-content: space-between;
19 | display: flex;
20 | flex-direction: row-reverse;
21 | }
22 |
23 | .radio-group-item input[type='radio']:checked + label {
24 | color: #004bde;
25 | }
26 |
27 | .radio-group-item label,
28 | input {
29 | cursor: pointer;
30 | }
31 |
32 | .radio-group-item label:hover {
33 | text-decoration: underline;
34 | }
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | import RadioGroup from './RadioGroup'
4 | import './App.css'
5 |
6 | class App extends Component {
7 | state = {
8 | value: 'Second'
9 | }
10 |
11 | onChange = (value) => {
12 | this.setState({
13 | value
14 | })
15 | }
16 |
17 | render() {
18 | return (
19 |
20 | Value: {this.state.value}
21 |
22 |
23 |
24 |
25 |
26 |
27 | )
28 | }
29 | }
30 |
31 | export default App
32 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/src/RadioGroup.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | const RadioContext = React.createContext()
4 |
5 | const RadioGroupOption = ({value, label}) => (
6 |
7 |
8 | {({contextValue, onChange}) => (
9 |
10 | )}
11 |
12 |
13 |
14 | )
15 |
16 | class RadioGroup extends Component {
17 | static Option = RadioGroupOption
18 |
19 | onChange = (event) => {
20 | this.props.onChange(event.target.value)
21 | }
22 | getContext = () => ({
23 | contextValue: this.props.value,
24 | onChange: this.onChange
25 | })
26 |
27 | render() {
28 | return (
29 |
30 |
31 |
32 | )
33 | }
34 | }
35 |
36 | export default RadioGroup
37 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lecture",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/controlled-components/lecture/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | flex-direction: column;
6 | height: 100vh;
7 | }
8 |
9 | .radio-group {
10 | display: flex;
11 | width: 85px;
12 | border: none;
13 | border-radius: 3px;
14 | }
15 |
16 | .radio-group-item {
17 | margin-top: 5px;
18 | justify-content: space-between;
19 | display: flex;
20 | flex-direction: row-reverse;
21 | }
22 |
23 | .radio-group-item input[type='radio']:checked + label {
24 | color: #004bde;
25 | }
26 |
27 | .radio-group-item label,
28 | input {
29 | cursor: pointer;
30 | }
31 |
32 | .radio-group-item label:hover {
33 | text-decoration: underline;
34 | }
35 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | import RadioGroup from './RadioGroup'
4 | import './App.css'
5 |
6 | class App extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 | )
15 | }
16 | }
17 |
18 | export default App
19 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/src/RadioGroup.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | const RadioGroupOption = ({value, label}) => (
4 |
5 |
6 |
7 |
8 | )
9 |
10 | class RadioGroup extends Component {
11 | static Option = RadioGroupOption
12 |
13 | render() {
14 | return
15 | }
16 | }
17 |
18 | export default RadioGroup
19 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/controlled-components/lecture/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exercise-solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "hoist-non-react-statics": "^3.2.1",
7 | "react": "^16.7.0",
8 | "react-dom": "^16.7.0",
9 | "react-scripts": "2.1.3"
10 | },
11 | "scripts": {
12 | "start": "react-scripts start",
13 | "build": "react-scripts build",
14 | "test": "react-scripts test",
15 | "eject": "react-scripts eject"
16 | },
17 | "eslintConfig": {
18 | "extends": "react-app"
19 | },
20 | "browserslist": [
21 | ">0.2%",
22 | "not dead",
23 | "not ie <= 11",
24 | "not op_mini all"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/higher-order-components/exercise-solution/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise-solution/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | height: 60vh;
3 | display: flex;
4 | align-items: center;
5 | justify-content: center;
6 | font-size: 30px;
7 | }
8 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise-solution/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div')
7 | ReactDOM.render(, div)
8 | ReactDOM.unmountComponentAtNode(div)
9 | })
10 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exercise",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "hoist-non-react-statics": "^3.2.1",
7 | "react": "^16.7.0",
8 | "react-dom": "^16.7.0",
9 | "react-scripts": "2.1.3"
10 | },
11 | "scripts": {
12 | "start": "react-scripts start",
13 | "build": "react-scripts build",
14 | "test": "react-scripts test",
15 | "eject": "react-scripts eject"
16 | },
17 | "eslintConfig": {
18 | "extends": "react-app"
19 | },
20 | "browserslist": [
21 | ">0.2%",
22 | "not dead",
23 | "not ie <= 11",
24 | "not op_mini all"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/higher-order-components/exercise/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | height: 60vh;
3 | display: flex;
4 | align-items: center;
5 | justify-content: center;
6 | font-size: 30px;
7 | }
8 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/exercise/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lecture-solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "hoist-non-react-statics": "^3.2.1",
7 | "react": "^16.7.0",
8 | "react-dom": "^16.7.0",
9 | "react-scripts": "2.1.3"
10 | },
11 | "scripts": {
12 | "start": "react-scripts start",
13 | "build": "react-scripts build",
14 | "test": "react-scripts test",
15 | "eject": "react-scripts eject"
16 | },
17 | "eslintConfig": {
18 | "extends": "react-app"
19 | },
20 | "browserslist": [
21 | ">0.2%",
22 | "not dead",
23 | "not ie <= 11",
24 | "not op_mini all"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/higher-order-components/lecture-solution/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | font-size: 20px;
4 | }
5 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | import {Online, Offline} from './NetworkStatus'
4 | import './App.css'
5 |
6 | class App extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 | Online with a connection.
13 |
14 | Running at ~
15 |
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 | export default App
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div')
7 | ReactDOM.render(, div)
8 | ReactDOM.unmountComponentAtNode(div)
9 | })
10 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lecture",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "hoist-non-react-statics": "^3.2.1",
7 | "react": "^16.7.0",
8 | "react-dom": "^16.7.0",
9 | "react-scripts": "2.1.3"
10 | },
11 | "scripts": {
12 | "start": "react-scripts start",
13 | "build": "react-scripts build",
14 | "test": "react-scripts test",
15 | "eject": "react-scripts eject"
16 | },
17 | "eslintConfig": {
18 | "extends": "react-app"
19 | },
20 | "browserslist": [
21 | ">0.2%",
22 | "not dead",
23 | "not ie <= 11",
24 | "not op_mini all"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/higher-order-components/lecture/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | font-size: 20px;
4 | }
5 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 | import {Online, Offline} from './NetworkStatus.js'
3 | import './App.css'
4 |
5 | class App extends Component {
6 | render() {
7 | return (
8 |
9 |
10 |
11 | Online with a connection.
12 |
13 | Running at
14 |
15 | Where'd you go?!
16 |
17 |
18 | )
19 | }
20 | }
21 |
22 | export default App
23 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/higher-order-components/lecture/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exercise-solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/render-props/exercise-solution/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | display: flex;
4 | }
5 |
6 | .App-counter {
7 | margin: 50px auto;
8 | padding: 15px;
9 | border: 1px solid #efefef;
10 | border-radius: 4px;
11 | text-align: center;
12 | max-width: 80%;
13 | }
14 |
15 | .App-counter-btn {
16 | background-color: #0064ff;
17 | color: white;
18 | border: none;
19 | padding: 5px 10px;
20 | border-radius: 4px;
21 | outline: none;
22 | margin-right: 5px;
23 | margin-left: 5px;
24 | cursor: pointer;
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import Count from './Count'
4 | import './App.css'
5 |
6 | const App = () => (
7 |
8 |
9 | {({increase, decrease, count}) => (
10 |
11 |
Counter
12 |
15 |
18 |
{count}
19 |
20 | )}
21 |
22 |
23 | )
24 |
25 | export default App
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/src/Count.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | class Count extends Component {
4 | state = {
5 | count: 0
6 | }
7 |
8 | increase = () => {
9 | this.setState({count: this.state.count + 1})
10 | }
11 |
12 | decrease = () => {
13 | this.setState({count: this.state.count - 1})
14 | }
15 |
16 | render() {
17 | return this.props.children({
18 | increase: this.increase,
19 | decrease: this.decrease,
20 | count: this.state.count
21 | })
22 | }
23 | }
24 |
25 | export default Count
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exercise",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/render-props/exercise/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | display: flex;
4 | }
5 |
6 | .App-counter {
7 | margin: 50px auto;
8 | padding: 15px;
9 | border: 1px solid #efefef;
10 | border-radius: 4px;
11 | text-align: center;
12 | max-width: 80%;
13 | }
14 |
15 | .App-counter-btn {
16 | background-color: #0064ff;
17 | color: white;
18 | border: none;
19 | padding: 5px 10px;
20 | border-radius: 4px;
21 | outline: none;
22 | margin-right: 5px;
23 | margin-left: 5px;
24 | cursor: pointer;
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/src/App.js:
--------------------------------------------------------------------------------
1 | /**
2 | * RENDER PROPS EXERCISE
3 | *
4 | * The App component will be only for presentational purpose.
5 | * The Counter container will hold all the logic and local state.
6 | *
7 | * Using Render props share:
8 | * 1. Event handlers for increasing and decreasing counts
9 | * 2. Total count
10 | *
11 | */
12 | import React, {Component} from 'react'
13 |
14 | import Count from './Count'
15 | import './App.css'
16 |
17 | class App extends Component {
18 | render() {
19 | return (
20 |
21 |
22 |
23 |
26 |
29 |
count
30 |
31 |
32 | )
33 | }
34 | }
35 |
36 | export default App
37 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/src/Count.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | class Count extends Component {
4 | render() {
5 | return Counter
6 | }
7 | }
8 |
9 | export default Count
10 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/exercise/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/render-props/lecture-solution/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | import Fetch from './Fetch'
4 | import './App.css'
5 |
6 | const URL = 'http://quotes.rest/qod.json?category=inspire'
7 |
8 | class App extends Component {
9 | render() {
10 | return (
11 |
12 |
13 | {({loading, error, data}) => {
14 | if (error !== null) {
15 | console.log(error)
16 | return {error.toString()}
17 | }
18 | return loading ? 'Loading...'
: {data.contents.quotes[0].quote}
19 | }}
20 |
21 |
22 | )
23 | }
24 | }
25 |
26 | export default App
27 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/src/Fetch.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | class Fetch extends Component {
4 | state = {
5 | loading: true,
6 | error: null,
7 | data: null
8 | }
9 |
10 | componentDidMount() {
11 | fetch(this.props.url)
12 | .then((res) => res.json())
13 | .then((data) =>
14 | this.setState({
15 | loading: false,
16 | data: data
17 | })
18 | )
19 | .catch((error) =>
20 | this.setState({
21 | loading: false,
22 | error: error
23 | })
24 | )
25 | }
26 |
27 | render() {
28 | return this.props.children(this.state)
29 | }
30 | }
31 |
32 | export default Fetch
33 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exercise",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.7.0",
7 | "react-dom": "^16.7.0",
8 | "react-scripts": "2.1.3"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/02-component-patterns/exercises/render-props/lecture/public/favicon.ico
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | import Fetch from './Fetch'
4 | import './App.css'
5 |
6 | // const URL = 'http://quotes.rest/qod.json?category=inspire'
7 | // data path data.contents.quotes[0].quote
8 |
9 | class App extends Component {
10 | render() {
11 | return (
12 |
13 |
14 |
15 | )
16 | }
17 | }
18 |
19 | export default App
20 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/src/Fetch.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react'
2 |
3 | class Fetch extends Component {
4 | render() {
5 | return Fetch Component
6 | }
7 | }
8 |
9 | export default Fetch
10 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/02-component-patterns/exercises/render-props/lecture/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './App'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | ReactDOM.render(, document.getElementById('root'))
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister()
13 |
--------------------------------------------------------------------------------
/02-component-patterns/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-workshop-component-patterns",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "author": "Blazek Adam ",
6 | "license": "MIT",
7 | "scripts": {
8 | "prettier": "prettier --write \"exercises/**/*.js\""
9 | },
10 | "dependencies": {
11 | "prettier": "^1.15.3"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/03-css-debugging/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "03-css-debugging",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "emotion": "10.0.7",
7 | "node-sass": "4.11.0",
8 | "react": "^16.7.0-alpha",
9 | "react-dom": "^16.7.0-alpha",
10 | "react-router": "4.3.1",
11 | "react-router-dom": "4.3.1",
12 | "react-scripts": "2.1.3"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": "react-app"
22 | },
23 | "browserslist": [
24 | ">0.2%",
25 | "not dead",
26 | "not ie <= 11",
27 | "not op_mini all"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/03-css-debugging/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/03-css-debugging/public/favicon.ico
--------------------------------------------------------------------------------
/03-css-debugging/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/03-css-debugging/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {BrowserRouter as Router, Route, NavLink} from 'react-router-dom'
3 | import './App.scss'
4 | import examples from './examples'
5 |
6 | const App = () => (
7 |
8 |
9 |
10 | {examples.map(ex => {ex.title})}
11 |
12 |
13 |
14 | {examples.map(ex => )}
15 |
16 |
17 |
18 | )
19 |
20 | export default App
21 |
--------------------------------------------------------------------------------
/03-css-debugging/src/App.scss:
--------------------------------------------------------------------------------
1 | .App {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | height: 100vh;
6 | background: #aaafae;
7 | font-size: 32px;
8 | }
9 |
10 | .App__header {
11 | margin: 10px;
12 | display: flex;
13 | flex-wrap: wrap;
14 | justify-content: center;
15 |
16 | a {
17 | color: #557;
18 | text-decoration: none;
19 | padding: 0 10px;
20 | transition: 0.2s;
21 | }
22 | a.active {
23 | color: black;
24 | font-weight: bold;
25 | }
26 | a:hover {
27 | color: #33b;
28 | }
29 | }
30 |
31 | .App__content {
32 | display: flex;
33 | flex: 1;
34 |
35 | & > *:not(.Vertical) {
36 | margin: auto;
37 | }
38 | }
39 |
40 | // !! Keep following code, to uncomment during parts of live demo. !!
41 | //
42 | //$debugColor: #c30;
43 | //* {
44 | // background: rgba($debugColor, .1) !important;
45 | // outline: 1px dotted $debugColor !important;
46 | // color: $debugColor !important;
47 | //}
48 | //
49 | // !! End keep !!
50 |
--------------------------------------------------------------------------------
/03-css-debugging/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import examples from './examples'
5 | import fs from 'fs'
6 |
7 | it('renders without crashing', () => {
8 | const div = document.createElement('div')
9 | ReactDOM.render(, div)
10 | ReactDOM.unmountComponentAtNode(div)
11 | });
12 |
13 | it('all examples are imported', () => {
14 | const files = fs.readdirSync(`${__dirname}/examples`).filter(f => f.match(/^\d.*\.js$/)).map(f => f.slice(0, 2))
15 | const imported = examples.map(e => e.id)
16 | expect(imported.sort()).toEqual(files.sort())
17 | })
18 |
--------------------------------------------------------------------------------
/03-css-debugging/src/examples/00-intro.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {css, cx} from 'emotion'
3 |
4 | const clsPrefix = 'Intro'
5 | const coin = 0.5 // Math.random()
6 |
7 | const randomStyle = css`color: orange;`
8 | const randomName = cx({
9 | first: coin < 0.6,
10 | second: coin > 0.4
11 | })
12 | const niceName = cx(`${clsPrefix}__niceName`, css`color: green;`)
13 |
14 | const Example = () => (
15 |
16 | Example 00: browser inspector + class names
17 |
Lorem ipsum
18 |
Lorem ipsum
19 |
Lorem ipsum
20 |
21 | )
22 |
23 | export default {
24 | id: '00',
25 | title: 'Intro',
26 | component: Example,
27 | }
28 |
--------------------------------------------------------------------------------
/03-css-debugging/src/examples/01-vertical-alignment.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Example = () => (
4 |
5 | Example 01: why am I not vertically centered?
6 |
7 | )
8 |
9 | export default {
10 | id: '01',
11 | title: 'Vertical alignment',
12 | component: Example,
13 | }
14 |
--------------------------------------------------------------------------------
/03-css-debugging/src/examples/02-z-index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Example = () => (
4 |
5 |
6 | Example 02: why am I not on top?
7 |
8 |
9 | Lorem ipsum
10 |
11 |
12 | )
13 |
14 | export default {
15 | id: '02',
16 | title: 'Z-index',
17 | component: Example,
18 | }
19 |
--------------------------------------------------------------------------------
/03-css-debugging/src/examples/03-selector-specificity.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Button} from './../lib'
3 |
4 | const Example = () => (
5 |
6 | Example 03: "cascade" style sheets
7 |
8 |
9 |
10 |
11 | )
12 |
13 | export default {
14 | id: '03',
15 | title: 'Selector specificity',
16 | component: Example,
17 | }
18 |
--------------------------------------------------------------------------------
/03-css-debugging/src/examples/04-responsive-design.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const boxes = Array.from(Array(50)).map((_, i) => {i}
)
4 | const Example = () => (
5 |
6 | {boxes}
7 |
8 | )
9 |
10 | export default {
11 | id: '04',
12 | title: 'Responsive design',
13 | component: Example,
14 | }
15 |
--------------------------------------------------------------------------------
/03-css-debugging/src/examples/05-transitions.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Example = () => (
4 |
5 | Example 05: Transition defined on "after" class
6 |
7 | )
8 |
9 | export default {
10 | id: '05',
11 | title: 'Transitions',
12 | component: Example,
13 | }
14 |
--------------------------------------------------------------------------------
/03-css-debugging/src/examples/index.js:
--------------------------------------------------------------------------------
1 | import './examples.scss'
2 |
3 | import ex00 from './00-intro'
4 | import ex01 from './01-vertical-alignment'
5 | import ex02 from './02-z-index'
6 | import ex03 from './03-selector-specificity'
7 | import ex04 from './04-responsive-design'
8 | import ex05 from './05-transitions'
9 |
10 | export default [
11 | ex00,
12 | ex01,
13 | ex02,
14 | ex03,
15 | ex04,
16 | ex05,
17 | ]
18 |
--------------------------------------------------------------------------------
/03-css-debugging/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/03-css-debugging/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/03-css-debugging/src/lib/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './lib.scss'
3 |
4 | export const Button = ({className = '', children}) =>
5 |
--------------------------------------------------------------------------------
/03-css-debugging/src/lib/lib.scss:
--------------------------------------------------------------------------------
1 | .lib {
2 | $bg: #998;
3 | &-button {
4 | border-radius: 5px;
5 | border: 1px solid darken($bg, 20);
6 | background: $bg;
7 | font-size: inherit;
8 | padding: 3px 10px;
9 | margin: 3px;
10 | cursor: pointer;
11 | }
12 | &-button:hover {
13 | background: darken($bg, 10);
14 | border-color: darken($bg, 100);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/README.md:
--------------------------------------------------------------------------------
1 | # To run the application
2 |
3 | If you've just downloaded the code and you are running the application
4 | for the first time, go to the project directory and install all packages
5 |
6 | ```shell
7 | npm ci
8 | ```
9 |
10 | Then, you can run the app in the development mode:
11 |
12 | ```shell
13 | npm start
14 | ```
15 |
16 | The page will reload if you make edits.
17 | You will also see any lint errors in the console.
18 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "suspense-and-concurrent-mode",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "lodash": "^4.17.11",
7 | "react": "16.7.0-alpha.2",
8 | "react-cache": "^2.0.0-alpha.1",
9 | "react-dom": "16.7.0-alpha.2",
10 | "react-router-dom": "4.4.0-beta.7",
11 | "react-scripts": "2.1.1",
12 | "scheduler": "0.13.3",
13 | "serve": "^10.1.2"
14 | },
15 | "scripts": {
16 | "build": "SKIP_PREFLIGHT_CHECK=true react-scripts build",
17 | "eject": "react-scripts eject",
18 | "eslint": "eslint --ext .js --ext .jsx .",
19 | "lint": "npm run eslint",
20 | "serve": "./node_modules/serve/bin/serve.js -s build",
21 | "start": "SKIP_PREFLIGHT_CHECK=true PORT=3006 react-scripts start",
22 | "test": "react-scripts test"
23 | },
24 | "eslintConfig": {
25 | "extends": "react-app"
26 | },
27 | "browserslist": [
28 | ">0.2%",
29 | "not dead",
30 | "not ie <= 11",
31 | "not op_mini all"
32 | ],
33 | "devDependencies": {
34 | "babel-eslint": "^10.0.1",
35 | "eslint": "^5.9.0",
36 | "prop-types": "^15.7.2"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/04-suspense-and-async-mode/exercise-fetch-solution/public/favicon.ico
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {lazy, Suspense} from 'react';
2 | import {BrowserRouter as Router, Route, Link, Switch} from 'react-router-dom';
3 | import './App.css';
4 | import Spinner from './components/spinner';
5 |
6 | const Home = lazy(() => import('./pages/home'));
7 | const Content = lazy(() => import('./pages/content'));
8 | const Kitties = lazy(() => import('./pages/kitties'));
9 |
10 | const App = () => (
11 |
12 |
13 |
20 |
21 | Loading the page...}>
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 |
33 | export default App;
34 |
35 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/src/components/spinner.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import './spinner.css';
4 |
5 | const Spinner = ({children}) => (
6 | <>
7 |
8 | {children}
9 | >
10 | );
11 |
12 | Spinner.propTypes = {
13 | children: PropTypes.node
14 | };
15 |
16 | Spinner.defaultProps = {
17 | children: null
18 | };
19 |
20 | export default Spinner;
21 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | body, html {
12 | background-color: #282c34;
13 | }
14 |
15 | code {
16 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
17 | monospace;
18 | }
19 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/src/pages/home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import logo from '../logo.svg';
4 |
5 | const Home = () => (
6 |
7 |

8 |
Suspense and Concurrent Mode in React
9 |
10 | "Code splitting and improving UX made easy."
11 |
12 |
13 | );
14 |
15 | export default Home;
16 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch-solution/src/pages/kitties.css:
--------------------------------------------------------------------------------
1 | .kitties {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | }
6 |
7 | .kitties > * {
8 | margin-top: 20px;
9 | }
10 |
11 | .kitties img {
12 | max-width: 80vw;
13 | max-height: 80vh;
14 | }
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/README.md:
--------------------------------------------------------------------------------
1 | # To run the application
2 |
3 | If you've just downloaded the code and you are running the application
4 | for the first time, go to the project directory and install all packages
5 |
6 | ```shell
7 | npm ci
8 | ```
9 |
10 | Then, you can run the app in the development mode:
11 |
12 | ```shell
13 | npm start
14 | ```
15 |
16 | The page will reload if you make edits.
17 | You will also see any lint errors in the console.
18 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "suspense-and-concurrent-mode",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "lodash": "^4.17.11",
7 | "react": "16.7.0-alpha.2",
8 | "react-cache": "^2.0.0-alpha.1",
9 | "react-dom": "16.7.0-alpha.2",
10 | "react-router-dom": "4.4.0-beta.7",
11 | "react-scripts": "2.1.1",
12 | "scheduler": "0.13.3",
13 | "serve": "^10.1.2"
14 | },
15 | "scripts": {
16 | "build": "SKIP_PREFLIGHT_CHECK=true react-scripts build",
17 | "eject": "react-scripts eject",
18 | "eslint": "eslint --ext .js --ext .jsx .",
19 | "lint": "npm run eslint",
20 | "serve": "./node_modules/serve/bin/serve.js -s build",
21 | "start": "SKIP_PREFLIGHT_CHECK=true PORT=3006 react-scripts start",
22 | "test": "react-scripts test"
23 | },
24 | "eslintConfig": {
25 | "extends": "react-app"
26 | },
27 | "browserslist": [
28 | ">0.2%",
29 | "not dead",
30 | "not ie <= 11",
31 | "not op_mini all"
32 | ],
33 | "devDependencies": {
34 | "babel-eslint": "^10.0.1",
35 | "eslint": "^5.9.0",
36 | "prop-types": "^15.7.2"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/04-suspense-and-async-mode/exercise-fetch/public/favicon.ico
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {lazy, Suspense} from 'react';
2 | import {BrowserRouter as Router, Route, Link, Switch} from 'react-router-dom';
3 | import './App.css';
4 | import Spinner from './components/spinner';
5 |
6 | const Home = lazy(() => import('./pages/home'));
7 | const Content = lazy(() => import('./pages/content'));
8 | const Kitties = lazy(() => import('./pages/kitties'));
9 |
10 | const App = () => (
11 |
12 |
13 |
20 |
21 | Loading the page...}>
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 |
33 | export default App;
34 |
35 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/src/components/spinner.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import './spinner.css';
4 |
5 | const Spinner = ({children}) => (
6 | <>
7 |
8 | {children}
9 | >
10 | );
11 |
12 | Spinner.propTypes = {
13 | children: PropTypes.node
14 | };
15 |
16 | Spinner.defaultProps = {
17 | children: null
18 | };
19 |
20 | export default Spinner;
21 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | body, html {
12 | background-color: #282c34;
13 | }
14 |
15 | code {
16 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
17 | monospace;
18 | }
19 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/src/pages/home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import logo from '../logo.svg';
4 |
5 | const Home = () => (
6 |
7 |

8 |
Suspense and Concurrent Mode in React
9 |
10 | "Code splitting and improving UX made easy."
11 |
12 |
13 | );
14 |
15 | export default Home;
16 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-fetch/src/pages/kitties.css:
--------------------------------------------------------------------------------
1 | .kitties {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | }
6 |
7 | .kitties > * {
8 | margin-top: 20px;
9 | }
10 |
11 | .kitties img {
12 | max-width: 80vw;
13 | max-height: 80vh;
14 | }
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/README.md:
--------------------------------------------------------------------------------
1 | # To run the application
2 |
3 | If you've just downloaded the code and you are running the application
4 | for the first time, go to the project directory and install all packages
5 |
6 | ```shell
7 | npm ci
8 | ```
9 |
10 | Then, you can run the app in the development mode:
11 |
12 | ```shell
13 | npm start
14 | ```
15 |
16 | The page will reload if you make edits.
17 | You will also see any lint errors in the console.
18 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "suspense-and-concurrent-mode",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "lodash": "^4.17.11",
7 | "react": "16.7.0-alpha.2",
8 | "react-cache": "^2.0.0-alpha.1",
9 | "react-dom": "16.7.0-alpha.2",
10 | "react-router-dom": "4.4.0-beta.7",
11 | "react-scripts": "2.1.1",
12 | "scheduler": "0.13.3",
13 | "serve": "^10.1.2"
14 | },
15 | "scripts": {
16 | "build": "SKIP_PREFLIGHT_CHECK=true react-scripts build",
17 | "eject": "react-scripts eject",
18 | "eslint": "eslint --ext .js --ext .jsx .",
19 | "lint": "npm run eslint",
20 | "serve": "./node_modules/serve/bin/serve.js -s build",
21 | "start": "SKIP_PREFLIGHT_CHECK=true PORT=3006 react-scripts start",
22 | "test": "react-scripts test"
23 | },
24 | "eslintConfig": {
25 | "extends": "react-app"
26 | },
27 | "browserslist": [
28 | ">0.2%",
29 | "not dead",
30 | "not ie <= 11",
31 | "not op_mini all"
32 | ],
33 | "devDependencies": {
34 | "babel-eslint": "^10.0.1",
35 | "eslint": "^5.9.0",
36 | "prop-types": "^15.7.2"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/04-suspense-and-async-mode/exercise-lazy-solution/public/favicon.ico
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/src/components/spinner.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import './spinner.css';
4 |
5 | const Spinner = ({children}) => (
6 | <>
7 |
8 | {children}
9 | >
10 | );
11 |
12 | Spinner.propTypes = {
13 | children: PropTypes.node
14 | };
15 |
16 | Spinner.defaultProps = {
17 | children: null
18 | };
19 |
20 | export default Spinner;
21 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | body, html {
12 | background-color: #282c34;
13 | }
14 |
15 | code {
16 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
17 | monospace;
18 | }
19 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/src/pages/home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import logo from '../logo.svg';
4 |
5 | const Home = () => (
6 |
7 |

8 |
Suspense and Concurrent Mode in React
9 |
10 | "Code splitting and improving UX made easy."
11 |
12 |
13 | );
14 |
15 | export default Home;
16 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy-solution/src/pages/prague-image.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const PragueImage = () => (
4 |
5 | This is a page with image just for demonstration purpose:
6 |

7 |
8 | );
9 |
10 | export default PragueImage;
11 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/README.md:
--------------------------------------------------------------------------------
1 | # To run the application
2 |
3 | If you've just downloaded the code and you are running the application
4 | for the first time, go to the project directory and install all packages
5 |
6 | ```shell
7 | npm ci
8 | ```
9 |
10 | Then, you can run the app in the development mode:
11 |
12 | ```shell
13 | npm start
14 | ```
15 |
16 | The page will reload if you make edits.
17 | You will also see any lint errors in the console.
18 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "suspense-and-concurrent-mode",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "lodash": "^4.17.11",
7 | "react": "16.7.0-alpha.2",
8 | "react-cache": "^2.0.0-alpha.1",
9 | "react-dom": "16.7.0-alpha.2",
10 | "react-router-dom": "4.4.0-beta.7",
11 | "react-scripts": "2.1.1",
12 | "scheduler": "0.13.3",
13 | "serve": "^10.1.2"
14 | },
15 | "scripts": {
16 | "build": "SKIP_PREFLIGHT_CHECK=true react-scripts build",
17 | "eject": "react-scripts eject",
18 | "eslint": "eslint --ext .js --ext .jsx .",
19 | "lint": "npm run eslint",
20 | "serve": "./node_modules/serve/bin/serve.js -s build",
21 | "start": "SKIP_PREFLIGHT_CHECK=true PORT=3006 react-scripts start",
22 | "test": "react-scripts test"
23 | },
24 | "eslintConfig": {
25 | "extends": "react-app"
26 | },
27 | "browserslist": [
28 | ">0.2%",
29 | "not dead",
30 | "not ie <= 11",
31 | "not op_mini all"
32 | ],
33 | "devDependencies": {
34 | "babel-eslint": "^10.0.1",
35 | "eslint": "^5.9.0",
36 | "prop-types": "^15.7.2"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/04-suspense-and-async-mode/exercise-lazy/public/favicon.ico
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/src/components/spinner.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import './spinner.css';
4 |
5 | const Spinner = ({children}) => (
6 | <>
7 |
8 | {children}
9 | >
10 | );
11 |
12 | Spinner.propTypes = {
13 | children: PropTypes.node
14 | };
15 |
16 | Spinner.defaultProps = {
17 | children: null
18 | };
19 |
20 | export default Spinner;
21 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | body, html {
12 | background-color: #282c34;
13 | }
14 |
15 | code {
16 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
17 | monospace;
18 | }
19 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/src/pages/home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import logo from '../logo.svg';
4 |
5 | const Home = () => (
6 |
7 |

8 |
Suspense and Concurrent Mode in React
9 |
10 | "Code splitting and improving UX made easy."
11 |
12 |
13 | );
14 |
15 | export default Home;
16 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/exercise-lazy/src/pages/prague-image.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const PragueImage = () => (
4 |
5 | This is a page with image just for demonstration purpose:
6 |

7 |
8 | );
9 |
10 | export default PragueImage;
11 |
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/images/concurrent_lifecycle_methods.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/04-suspense-and-async-mode/images/concurrent_lifecycle_methods.jpeg
--------------------------------------------------------------------------------
/04-suspense-and-async-mode/images/concurrent_mode_explained.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/04-suspense-and-async-mode/images/concurrent_mode_explained.png
--------------------------------------------------------------------------------
/05-component-testing/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | *.final.test.tsx
26 |
--------------------------------------------------------------------------------
/05-component-testing/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/05-component-testing/public/favicon.ico
--------------------------------------------------------------------------------
/05-component-testing/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/05-component-testing/src/App.css:
--------------------------------------------------------------------------------
1 | .movie-list {
2 | padding: 20px;
3 | display: flex;
4 | flex-wrap: wrap;
5 | }
6 |
7 | .movie {
8 | margin: 10px;
9 | }
10 |
11 | .movie__header {
12 | display: flex;
13 | justify-content: space-between;
14 | }
15 |
16 | .movie__image-container {
17 | width: 500px;
18 | height: 281px;
19 | }
20 |
--------------------------------------------------------------------------------
/05-component-testing/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Provider } from 'react-redux'
3 |
4 | import './App.css';
5 | import MovieList from './MovieList';
6 | import {BrowserRouter as Router, Route, Switch} from 'react-router-dom'
7 | import configureStore from './store';
8 |
9 | class App extends Component<{}> {
10 | render() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | export default App;
24 |
--------------------------------------------------------------------------------
/05-component-testing/src/Fetcher.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode } from 'react';
2 |
3 | type State = {
4 | data: object | undefined
5 | loading: boolean
6 | }
7 |
8 | type Props = {
9 | url: string
10 | children: (api: {
11 | data?: TData
12 | loading: boolean | null
13 | }) => ReactNode
14 | }
15 |
16 | class Fetcher extends React.Component, State> {
17 | state = {
18 | data: undefined,
19 | loading: false,
20 | };
21 |
22 | componentDidMount() {
23 | this.setState({ loading: true });
24 |
25 | fetch(this.props.url)
26 | .then(response => {
27 | if (response.ok) {
28 | return response.json();
29 | } else {
30 | throw new Error('Something went wrong ...');
31 | }
32 | })
33 | .then(data => this.setState({ data, loading: false }))
34 | .catch(error => this.setState({ loading: false }));
35 | }
36 |
37 | render() {
38 | return this.props.children(this.state);
39 | }
40 | }
41 |
42 | export default Fetcher;
43 |
--------------------------------------------------------------------------------
/05-component-testing/src/Movie.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | type Props = {
4 | id: number
5 | title: string
6 | includedInWishlist: boolean
7 | image?: string | null
8 | onClick: (id: number) => void
9 | }
10 |
11 | const Movie: React.FunctionComponent = (props) => {
12 |
13 | const handleClick = () => {
14 | props.onClick(props.id)
15 | }
16 |
17 | return (
18 |
19 |
20 | {props.title}
21 |
22 | {props.includedInWishlist ? '❤️' : '🖤'}
23 |
24 |
25 |
26 | {props.image &&

}
27 |
28 |
29 | )
30 | }
31 |
32 | export default Movie
33 |
--------------------------------------------------------------------------------
/05-component-testing/src/__tests__/exercise.002.test.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {render, cleanup, fireEvent} from 'react-testing-library'
3 | import chai, {expect} from 'chai'
4 | import sinon from 'sinon'
5 |
6 | import chaiSinon from 'sinon-chai'
7 |
8 | import Movie from '../Movie'
9 |
10 | chai.use(chaiSinon)
11 |
12 | describe('Exercise 002', () => {
13 | const baseProps = {
14 | title: 'New Movie',
15 | id: 12,
16 | includedInWishlist: false,
17 | onClick: () => {}
18 | }
19 |
20 | afterEach(() => {
21 | cleanup()
22 | })
23 |
24 | it('should handle add wishlist item', () => {
25 | // const props = {
26 | // ...baseProps,
27 | // onClick: sinon.spy()
28 | // }
29 |
30 | // Render component
31 | // Fire click event
32 | // Check if the event was called with param id of the movie
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/05-component-testing/src/__tests__/exercise.004.test.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {render, cleanup, waitForElement, fireEvent} from 'react-testing-library'
3 | import {MemoryRouter} from 'react-router'
4 | import chai, {expect} from 'chai'
5 | import chaiDom from 'chai-dom'
6 |
7 | import App from '../App'
8 |
9 | chai.use(chaiDom)
10 |
11 | describe('Exercise 004', () => {
12 | afterEach(() => {
13 | cleanup()
14 | })
15 |
16 | it('should by able to add movie to wishlist', async () => {
17 | // Render component -
18 | // Wait for wishlist button to be displayed - await waitForElement(() => find the element)
19 | // Check if the button has black heart
20 | // Click on the button
21 | // Check if the button has red heart
22 | })
23 | })
24 |
--------------------------------------------------------------------------------
/05-component-testing/src/actions/wishlistAction.ts:
--------------------------------------------------------------------------------
1 | import { Action, ActionCreator } from "redux";
2 | export const ADD_WISHLIST_ITEM = 'ADD_WISHLIST_ITEM'
3 |
4 | export interface AddWishlistItemAction extends Action {
5 | payload: number
6 | }
7 |
8 | export type WishlistActions = AddWishlistItemAction
9 |
10 | export const addWishlistItem = (id: number) => ({
11 | type: ADD_WISHLIST_ITEM,
12 | payload: id
13 | })
14 |
--------------------------------------------------------------------------------
/05-component-testing/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/05-component-testing/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import {BrowserRouter as Router} from 'react-router-dom'
6 |
7 | // import * as serviceWorker from './serviceWorker';
8 |
9 | ReactDOM.render(, document.getElementById('root'));
10 |
11 | // If you want your app to work offline and load faster, you can change
12 | // unregister() to register() below. Note this comes with some pitfalls.
13 | // Learn more about service workers: https://bit.ly/CRA-PWA
14 | // serviceWorker.unregister();
15 |
--------------------------------------------------------------------------------
/05-component-testing/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/05-component-testing/src/reducers/index.ts:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import wishlistReducer, { WishlistState } from './wishlistReducer';
3 |
4 |
5 | const rootReducer = combineReducers({
6 | wishlistReducer: wishlistReducer
7 | });
8 |
9 | export type AppState = ReturnType
10 |
11 | export default rootReducer
12 |
--------------------------------------------------------------------------------
/05-component-testing/src/reducers/wishlistReducer.ts:
--------------------------------------------------------------------------------
1 | import { Reducer } from "redux";
2 | import {WishlistActions} from '../actions/wishlistAction'
3 |
4 | export interface WishlistState {
5 | readonly ids: number[]
6 | }
7 |
8 | const initialState: WishlistState = {
9 | ids: []
10 | }
11 |
12 | const wishlistReducer: Reducer = (state = initialState, action): WishlistState => {
13 | switch (action.type) {
14 | case 'ADD_WISHLIST_ITEM':
15 | if (state.ids.includes(action.payload)) {
16 | return state
17 | }
18 |
19 | return {
20 | ids: [...state.ids, action.payload]
21 | }
22 | default:
23 | return state
24 | }
25 | }
26 |
27 | export default wishlistReducer
28 |
--------------------------------------------------------------------------------
/05-component-testing/src/store.ts:
--------------------------------------------------------------------------------
1 | import { createStore } from 'redux';
2 | import rootReducer from './reducers';
3 |
4 | export default function configureStore() {
5 | return createStore(rootReducer);
6 | }
7 |
--------------------------------------------------------------------------------
/05-component-testing/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "preserve"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/06-graphql/backend/app.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const cors = require('cors')
3 |
4 | const graphqlHTTP = require("express-graphql");
5 |
6 | const graphqlSchema = require("./graphqlSchema")
7 |
8 | const app = express()
9 | app.use(cors())
10 |
11 | const port = 3000
12 | app.listen(port, () => console.log(`Server listening on port ${port}!`))
13 |
14 |
15 | app.use("/hello", function(req, res){
16 | res.send("hello!")
17 | })
18 |
19 | app.use("/graphql", function (req, res) {
20 | const graphqlFunc = graphqlHTTP({
21 | schema: graphqlSchema,
22 | graphiql: true,
23 | })
24 |
25 | return graphqlFunc(req, res)
26 | .catch(function (err) {
27 | console.log(err)
28 | })
29 | })
30 |
--------------------------------------------------------------------------------
/06-graphql/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "backend",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "start": "node app.js"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "axios": "^0.19.0",
13 | "cors": "^2.8.5",
14 | "express": "^4.17.1",
15 | "express-graphql": "^0.8.0",
16 | "graphql": "^14.3.1",
17 | "https-proxy-agent": "^2.2.1",
18 | "rickmortyapi": "^0.2.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/06-graphql/web/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | "@babel/preset-react",
4 | [
5 | "@babel/preset-env",
6 | {
7 | // see .browserslistrc
8 | useBuiltIns: "entry",
9 | corejs: 3
10 | }
11 | ]
12 | ],
13 | plugins: [
14 | "@babel/plugin-proposal-class-properties",
15 | "@babel/plugin-transform-regenerator"
16 | ]
17 | };
18 |
--------------------------------------------------------------------------------
/06-graphql/web/src/components/Character.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import "./Character.scss";
4 |
5 | export default function Character(props) {
6 |
7 | const {id, name, imageUrl} = props.data
8 |
9 | return (
10 |
11 |
{id} {name}
12 |
13 |
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/06-graphql/web/src/components/Character.scss:
--------------------------------------------------------------------------------
1 |
2 | .character {
3 | display: flex;
4 | flex-direction: column;
5 | padding: 10px;
6 | }
7 |
8 | .header {
9 |
10 | }
11 |
12 | .image {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/06-graphql/web/src/components/CharacterSheet.scss:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/06-graphql/web/src/graphqlRequest.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default function graphqlRequest(query){
4 | return axios
5 | .get(`http://localhost:3000/graphql/?query=${query}`)
6 | .then(result => result.data);
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/06-graphql/web/src/helpers/getRandomCharacterIds.js:
--------------------------------------------------------------------------------
1 | // adopted from https://github.com/afuh/rick-and-morty-api-site/blob/master/src/utils/hooks/useRandomChars.js
2 | export default function getRandomCharacterIds(total){
3 | const totalNumberOfCharacters = 493
4 | const arr = []
5 | const randomNum = () => Math.floor(Math.random() * totalNumberOfCharacters + 1)
6 |
7 | if (total === 1) {
8 | return randomNum()
9 | }
10 |
11 | while (arr.length < total) {
12 | const num = randomNum()
13 | if (arr.indexOf(num) > -1) {
14 | continue
15 | }
16 | arr[arr.length] = num
17 | }
18 |
19 | return arr
20 | }
21 |
--------------------------------------------------------------------------------
/06-graphql/web/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React workshop 6
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/06-graphql/web/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 |
4 |
5 | import CharacterSheet from "./components/CharacterSheet"
6 |
7 | const Index = () => (
8 |
9 |
10 |
11 | );
12 |
13 | ReactDOM.render(, document.getElementById("index"));
14 |
--------------------------------------------------------------------------------
/06-graphql/web/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const merge = require("webpack-merge");
3 | const common = require("./webpack.common");
4 |
5 | module.exports = merge(common, {
6 | mode: "development",
7 | devtool: "cheap-module-eval-source-map",
8 | watch: true,
9 | output: {
10 | publicPath: "/"
11 | },
12 | devServer: {
13 | contentBase: path.join(__dirname, "dist"),
14 | watchContentBase: true,
15 | publicPath: "/",
16 | inline: true,
17 | stats: "errors-only",
18 | proxy: {
19 | "/**": {
20 | target: "http://localhost:8080",
21 | pathRewrite: { "^/.*": "/" }
22 | }
23 | }
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/06-graphql/web/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const merge = require("webpack-merge");
2 | const common = require("./webpack.common");
3 |
4 | module.exports = merge(common, {
5 | mode: "production",
6 | output: {
7 | publicPath: "/static/"
8 | }
9 | });
10 |
--------------------------------------------------------------------------------
/07-firebase/excersise/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # env variables
9 | .env
10 |
11 | # testing
12 | /coverage
13 |
14 | # production
15 | /build
16 |
17 | # misc
18 | .DS_Store
19 | .env.local
20 | .env.development.local
21 | .env.test.local
22 | .env.production.local
23 |
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
--------------------------------------------------------------------------------
/07-firebase/excersise/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": false,
6 | "singleQuote": true,
7 | "trailingComma": "none",
8 | "bracketSpacing": false,
9 | "jsxBracketSameLine": true,
10 | "arrowParens": "always"
11 | }
12 |
--------------------------------------------------------------------------------
/07-firebase/excersise/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "firebase-excersise",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.4.0",
7 | "firebase": "^6.5.0",
8 | "prettier": "^1.15.3",
9 | "react": "^16.9.0",
10 | "react-dom": "^16.9.0",
11 | "react-router-dom": "^5.0.1",
12 | "react-scripts": "3.1.1",
13 | "recompose": "^0.30.0"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject",
20 | "prettier": "prettier --write './**/*.{js,json,css,md}'"
21 | },
22 | "eslintConfig": {
23 | "extends": "react-app"
24 | },
25 | "browserslist": {
26 | "production": [">0.2%", "not dead", "not op_mini all"],
27 | "development": [
28 | "last 1 chrome version",
29 | "last 1 firefox version",
30 | "last 1 safari version"
31 | ]
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/07-firebase/excersise/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/07-firebase/excersise/public/favicon.ico
--------------------------------------------------------------------------------
/07-firebase/excersise/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/07-firebase/excersise/public/logo192.png
--------------------------------------------------------------------------------
/07-firebase/excersise/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/07-firebase/excersise/public/logo512.png
--------------------------------------------------------------------------------
/07-firebase/excersise/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/07-firebase/excersise/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/Firebase/context.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const FirebaseContext = React.createContext(null)
4 |
5 | // Implement FirebaseContext.Consumer which then pass firebase instance to Component.
6 | export const withFirebase = (Component) => (props) =>
7 |
8 | export default FirebaseContext
9 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/Firebase/firebase.js:
--------------------------------------------------------------------------------
1 | import app from 'firebase/app'
2 | import 'firebase/auth'
3 | import 'firebase/database'
4 |
5 | const config = {
6 | apiKey: process.env.REACT_APP_API_KEY,
7 | authDomain: process.env.REACT_APP_AUTH_DOMAIN,
8 | databaseURL: process.env.REACT_APP_DATABASE_URL,
9 | projectId: process.env.REACT_APP_PROJECT_ID,
10 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
11 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID
12 | }
13 |
14 | class Firebase {
15 | constructor() {
16 | app.initializeApp(config)
17 |
18 | this.auth = app.auth()
19 | this.db = app.database()
20 | }
21 |
22 | // *** Auth API ***
23 |
24 | // *** User API ***
25 | }
26 |
27 | export default Firebase
28 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/Firebase/index.js:
--------------------------------------------------------------------------------
1 | import FirebaseContext, {withFirebase} from './context'
2 | import Firebase from './firebase'
3 |
4 | export default Firebase
5 |
6 | export {FirebaseContext, withFirebase}
7 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/Home/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Typography from '@material-ui/core/Typography'
3 |
4 | import {withAuthorization} from '../Session'
5 |
6 | const HomePage = () => (
7 |
8 |
9 | Home Page
10 |
11 |
12 | The Home page is accesible by every signed in user.
13 |
14 |
15 | )
16 |
17 | const condition = (authUser) => authUser !== null
18 |
19 | export default withAuthorization(condition)(HomePage)
20 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/Landing/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Typography from '@material-ui/core/Typography'
3 |
4 | const LandingPage = () => (
5 |
6 |
7 | Landing Page
8 |
9 |
10 | The Home page is accesible by every user.
11 |
12 |
13 | )
14 |
15 | export default LandingPage
16 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/Session/context.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const AuthUserContext = React.createContext(null)
4 |
5 | export default AuthUserContext
6 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/Session/index.js:
--------------------------------------------------------------------------------
1 | import AuthUserContext from './context'
2 | import withAuthentication from './withAuthentication'
3 | import withAuthorization from './withAuthorization'
4 |
5 | export {AuthUserContext, withAuthentication, withAuthorization}
6 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/Session/withAuthentication.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import AuthUserContext from './context'
3 | import {withFirebase} from '../Firebase'
4 |
5 | const withAuthentication = (Component) => {
6 | class WithAuthentication extends React.Component {
7 | constructor(props) {
8 | super(props)
9 |
10 | this.state = {
11 | authUser: null
12 | }
13 | }
14 |
15 | componentDidMount() {
16 | this.listener = this.props.firebase.auth.onAuthStateChanged(
17 | (authUser) => {
18 | authUser ? this.setState({authUser}) : this.setState({authUser: null})
19 | }
20 | )
21 | }
22 |
23 | componentWillUnmount() {
24 | this.listener()
25 | }
26 | render() {
27 | return (
28 |
29 |
30 |
31 | )
32 | }
33 | }
34 |
35 | return withFirebase(WithAuthentication)
36 | }
37 |
38 | export default withAuthentication
39 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/components/SignOut/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {compose} from 'recompose'
3 | import {withRouter} from 'react-router-dom'
4 | import Button from '@material-ui/core/Button'
5 | import {makeStyles} from '@material-ui/core/styles'
6 |
7 | import * as ROUTES from '../../constants/routes'
8 | import {withFirebase} from '../Firebase'
9 |
10 | const useStyles = makeStyles((theme) => ({
11 | menuButton: {
12 | marginRight: theme.spacing(2),
13 | color: '#ffffff'
14 | }
15 | }))
16 |
17 | const SignOutButton = ({firebase, history}) => {
18 | const classes = useStyles()
19 |
20 | // Call sign out of our authentication interface and route to landing page.
21 | const onSignOut = () => {}
22 |
23 | return (
24 |
27 | )
28 | }
29 |
30 | export default compose(
31 | withRouter,
32 | withFirebase
33 | )(SignOutButton)
34 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/constants/routes.js:
--------------------------------------------------------------------------------
1 | export const LANDING = '/'
2 | export const SIGN_UP = '/signup'
3 | export const SIGN_IN = '/signin'
4 | export const HOME = '/home'
5 | export const ACCOUNT = '/account'
6 | export const ADMIN = '/admin'
7 | export const PASSWORD_FORGET = '/pw-forget'
8 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/07-firebase/excersise/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 |
4 | import './index.css'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | import App from './components/App'
8 | import Firebase, {FirebaseContext} from './components/Firebase'
9 |
10 | ReactDOM.render(
11 |
12 |
13 | ,
14 | document.getElementById('root')
15 | )
16 |
17 | // If you want your app to work offline and load faster, you can change
18 | // unregister() to register() below. Note this comes with some pitfalls.
19 | // Learn more about service workers: https://bit.ly/CRA-PWA
20 | serviceWorker.unregister()
21 |
--------------------------------------------------------------------------------
/07-firebase/solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # env variables
9 | .env
10 |
11 | # testing
12 | /coverage
13 |
14 | # production
15 | /build
16 |
17 | # misc
18 | .DS_Store
19 | .env.local
20 | .env.development.local
21 | .env.test.local
22 | .env.production.local
23 |
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
--------------------------------------------------------------------------------
/07-firebase/solution/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": false,
6 | "singleQuote": true,
7 | "trailingComma": "none",
8 | "bracketSpacing": false,
9 | "jsxBracketSameLine": true,
10 | "arrowParens": "always"
11 | }
12 |
--------------------------------------------------------------------------------
/07-firebase/solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "firebase-solution",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.4.0",
7 | "firebase": "^6.5.0",
8 | "prettier": "^1.15.3",
9 | "react": "^16.9.0",
10 | "react-dom": "^16.9.0",
11 | "react-router-dom": "^5.0.1",
12 | "react-scripts": "3.1.1",
13 | "recompose": "^0.30.0"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject",
20 | "prettier": "prettier --write './**/*.{js,json,css,md}'"
21 | },
22 | "eslintConfig": {
23 | "extends": "react-app"
24 | },
25 | "browserslist": {
26 | "production": [
27 | ">0.2%",
28 | "not dead",
29 | "not op_mini all"
30 | ],
31 | "development": [
32 | "last 1 chrome version",
33 | "last 1 firefox version",
34 | "last 1 safari version"
35 | ]
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/07-firebase/solution/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/07-firebase/solution/public/favicon.ico
--------------------------------------------------------------------------------
/07-firebase/solution/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/07-firebase/solution/public/logo192.png
--------------------------------------------------------------------------------
/07-firebase/solution/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/07-firebase/solution/public/logo512.png
--------------------------------------------------------------------------------
/07-firebase/solution/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/07-firebase/solution/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/components/Firebase/context.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const FirebaseContext = React.createContext(null)
4 |
5 | export const withFirebase = (Component) => (props) => (
6 |
7 | {(firebase) => }
8 |
9 | )
10 |
11 | export default FirebaseContext
12 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/components/Firebase/index.js:
--------------------------------------------------------------------------------
1 | import FirebaseContext, {withFirebase} from './context'
2 | import Firebase from './firebase'
3 |
4 | export default Firebase
5 |
6 | export {FirebaseContext, withFirebase}
7 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/components/Home/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Typography from '@material-ui/core/Typography'
3 |
4 | import {withAuthorization} from '../Session'
5 |
6 | const HomePage = () => (
7 |
8 |
9 | Home Page
10 |
11 |
12 | The Home page is accesible by every signed in user.
13 |
14 |
15 | )
16 |
17 | const condition = (authUser) => authUser !== null
18 |
19 | export default withAuthorization(condition)(HomePage)
20 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/components/Landing/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Typography from '@material-ui/core/Typography'
3 |
4 | const LandingPage = () => (
5 |
6 |
7 | Landing Page
8 |
9 |
10 | The Home page is accesible by every user.
11 |
12 |
13 | )
14 |
15 | export default LandingPage
16 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/components/Session/context.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const AuthUserContext = React.createContext(null)
4 |
5 | export default AuthUserContext
6 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/components/Session/index.js:
--------------------------------------------------------------------------------
1 | import AuthUserContext from './context'
2 | import withAuthentication from './withAuthentication'
3 | import withAuthorization from './withAuthorization'
4 |
5 | export {AuthUserContext, withAuthentication, withAuthorization}
6 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/components/Session/withAuthentication.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import AuthUserContext from './context'
3 | import {withFirebase} from '../Firebase'
4 |
5 | const withAuthentication = (Component) => {
6 | class WithAuthentication extends React.Component {
7 | constructor(props) {
8 | super(props)
9 |
10 | this.state = {
11 | authUser: null
12 | }
13 | }
14 |
15 | componentDidMount() {
16 | this.listener = this.props.firebase.auth.onAuthStateChanged(
17 | (authUser) => {
18 | authUser ? this.setState({authUser}) : this.setState({authUser: null})
19 | }
20 | )
21 | }
22 |
23 | componentWillUnmount() {
24 | this.listener()
25 | }
26 | render() {
27 | return (
28 |
29 |
30 |
31 | )
32 | }
33 | }
34 |
35 | return withFirebase(WithAuthentication)
36 | }
37 |
38 | export default withAuthentication
39 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/components/SignOut/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {compose} from 'recompose'
3 | import {withRouter} from 'react-router-dom'
4 | import Button from '@material-ui/core/Button'
5 | import {makeStyles} from '@material-ui/core/styles'
6 |
7 | import * as ROUTES from '../../constants/routes'
8 | import {withFirebase} from '../Firebase'
9 |
10 | const useStyles = makeStyles((theme) => ({
11 | menuButton: {
12 | marginRight: theme.spacing(2),
13 | color: '#ffffff'
14 | }
15 | }))
16 |
17 | const SignOutButton = ({firebase, history}) => {
18 | const classes = useStyles()
19 |
20 | const onSignOut = () => {
21 | firebase.doSignOut()
22 | history.push(ROUTES.LANDING)
23 | }
24 |
25 | return (
26 |
29 | )
30 | }
31 |
32 | export default compose(
33 | withRouter,
34 | withFirebase
35 | )(SignOutButton)
36 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/constants/routes.js:
--------------------------------------------------------------------------------
1 | export const LANDING = '/'
2 | export const SIGN_UP = '/signup'
3 | export const SIGN_IN = '/signin'
4 | export const HOME = '/home'
5 | export const ACCOUNT = '/account'
6 | export const ADMIN = '/admin'
7 | export const PASSWORD_FORGET = '/pw-forget'
8 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/07-firebase/solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 |
4 | import './index.css'
5 | import * as serviceWorker from './serviceWorker'
6 |
7 | import App from './components/App'
8 | import Firebase, {FirebaseContext} from './components/Firebase'
9 |
10 | ReactDOM.render(
11 |
12 |
13 | ,
14 | document.getElementById('root')
15 | )
16 |
17 | // If you want your app to work offline and load faster, you can change
18 | // unregister() to register() below. Note this comes with some pitfalls.
19 | // Learn more about service workers: https://bit.ly/CRA-PWA
20 | serviceWorker.unregister()
21 |
--------------------------------------------------------------------------------
/08-testing-hooks/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/08-testing-hooks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "08-testing-hooks",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.1.0",
7 | "@testing-library/react": "^9.2.0",
8 | "enzyme": "^3.10.0",
9 | "enzyme-adapter-react-16": "^1.14.0",
10 | "react": "^16.10.1",
11 | "react-dom": "^16.10.1",
12 | "react-scripts": "3.1.2",
13 | "react-test-renderer": "^16.10.1"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": "react-app"
23 | },
24 | "browserslist": {
25 | "production": [
26 | ">0.2%",
27 | "not dead",
28 | "not op_mini all"
29 | ],
30 | "development": [
31 | "last 1 chrome version",
32 | "last 1 firefox version",
33 | "last 1 safari version"
34 | ]
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/08-testing-hooks/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/08-testing-hooks/public/favicon.ico
--------------------------------------------------------------------------------
/08-testing-hooks/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/08-testing-hooks/public/logo192.png
--------------------------------------------------------------------------------
/08-testing-hooks/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/08-testing-hooks/public/logo512.png
--------------------------------------------------------------------------------
/08-testing-hooks/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/08-testing-hooks/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/01/01-exercise.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Main = () => {
4 | const defaultColor = 'orange'
5 |
6 | return (
7 |
8 |
Adding State
9 |
10 |
11 |
12 | )
13 | }
14 |
15 | export default Main
16 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/01/01-exercise.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { render, unmountComponentAtNode } from 'react-dom'
3 | import { act } from "react-dom/test-utils"
4 | import Main from './01-exercise'
5 |
6 | let div
7 | beforeEach(() => {
8 | div = document.createElement('div')
9 | })
10 | afterEach(() => {
11 | unmountComponentAtNode(div)
12 | })
13 |
14 | test('default color', () => {
15 | act(() => {
16 | render(, div)
17 | })
18 | expect(div.querySelector('.Main-box').style.backgroundColor).toBe('orange')
19 | })
20 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/01/01-solution.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 |
3 | const Main = () => {
4 | const defaultColor = 'orange'
5 |
6 | const [color, setColor] = useState('')
7 | const handleChange = (event) => {
8 | setColor(event.target.value)
9 | }
10 |
11 | return (
12 |
13 |
Adding State
14 |
15 |
16 |
17 | )
18 | }
19 |
20 | export default Main
21 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/02/02-exercise.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 |
3 | export const validateColor = () => false
4 |
5 | const Main = () => {
6 | const defaultColor = 'orange'
7 |
8 | const [inputColor, setInputColor] = useState('')
9 | const handleChange = (event) => {
10 | const { value } = event.target
11 | setInputColor(value)
12 | if (validateColor(value)) {
13 | // TODO
14 | }
15 | }
16 |
17 | return (
18 |
19 |
TDD
20 |
21 |
22 | {'orange '}
23 |
24 |
25 | )
26 | }
27 |
28 | export default Main
29 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/02/02-solution.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 |
3 | export const validateColor = (value) => {
4 | const div = document.createElement('div')
5 | div.style.color = value
6 | return !!div.style.color
7 | }
8 |
9 | const Main = () => {
10 | const defaultColor = 'orange'
11 |
12 | const [inputColor, setInputColor] = useState('')
13 | const [validColor, setValidColor] = useState(defaultColor)
14 | const handleChange = (event) => {
15 | const { value } = event.target
16 | setInputColor(value)
17 | if (!value) {
18 | setValidColor(defaultColor)
19 | } else if (validateColor(value)) {
20 | setValidColor(value)
21 | }
22 | }
23 |
24 | return (
25 |
26 |
TDD
27 |
28 |
29 | {validColor}
30 |
31 |
32 | )
33 | }
34 |
35 | export default Main
36 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/04/04-exercise.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 |
3 | const Main = () => {
4 | const defaultColor = 'orange'
5 |
6 | const [color, setColor] = useState('')
7 | const handleChange = (event) => {
8 | setColor(event.target.value)
9 | }
10 |
11 | return (
12 |
13 |
Libraries for testing
14 |
15 |
16 |
17 | )
18 | }
19 |
20 | export default Main
21 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/04/04-solution.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 |
3 | const Main = () => {
4 | const defaultColor = 'orange'
5 |
6 | const [color, setColor] = useState('')
7 | const handleChange = (event) => {
8 | setColor(event.target.value)
9 | }
10 |
11 | return (
12 |
13 |
Libraries for testing
14 |
15 |
16 |
17 | )
18 | }
19 |
20 | export default Main
21 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/04/04-solution.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { render, fireEvent } from '@testing-library/react'
3 | import Main from './04-solution'
4 |
5 | test('default color', () => {
6 | const { container: div } = render()
7 | expect(div.querySelector('.Main-box').style.backgroundColor).toBe('orange')
8 | })
9 |
10 | test('modified color', () => {
11 | const { container: div } = render()
12 | const input = div.querySelector('input')
13 | expect(input).toHaveProperty('value', '')
14 |
15 | fireEvent.change(input, { target: { value: 'green' } })
16 | expect(input).toHaveProperty('value', 'green')
17 | expect(div.querySelector('.Main-box').style.backgroundColor).toBe('green')
18 | })
19 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/05/05-exercise.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 |
3 | const Main = () => {
4 | const [color, setColor] = useState('orange')
5 |
6 | // useEffect(() => {
7 | // window.fetch('https://jsonplaceholder.typicode.com/users/1').then((data) => {
8 | // setColor('green')
9 | // })
10 | // }, [])
11 |
12 | useEffect(() => {
13 | const fetchPromise = window.fetch('https://jsonplaceholder.typicode.com/users/1')
14 | const timeoutPromise = new Promise((resolve, reject) => {
15 | setTimeout(reject, 1000)
16 | })
17 | Promise.race([fetchPromise, timeoutPromise]).then((data) => {
18 | setColor('green')
19 | }).catch(() => {
20 | setColor('red')
21 | })
22 | }, [])
23 |
24 | return (
25 |
26 |
Fetch and timeout
27 |
28 |
29 | )
30 | }
31 |
32 | export default Main
33 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/05/05-exercise.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { render, unmountComponentAtNode } from 'react-dom'
3 | import { act } from "react-dom/test-utils"
4 | import Main from './05-exercise'
5 |
6 | let div
7 | beforeEach(() => {
8 | div = document.createElement('div')
9 | document.body.appendChild(div)
10 | })
11 | afterEach(() => {
12 | unmountComponentAtNode(div)
13 | div.remove()
14 | })
15 |
16 | test('default color', () => {
17 | act(() => {
18 | render(, div)
19 | })
20 | expect(div.querySelector('.Main-box').style.backgroundColor).toBe('orange')
21 | })
22 |
23 | test('modified color', () => {
24 | // ???
25 | })
26 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/05/05-solution.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 |
3 | const Main = () => {
4 | const [color, setColor] = useState('orange')
5 |
6 | useEffect(() => {
7 | const fetchPromise = window.fetch('https://jsonplaceholder.typicode.com/users/1')
8 | let cancellable
9 | const timeoutPromise = new Promise((resolve, reject) => {
10 | cancellable = setTimeout(reject, 1000)
11 | })
12 | Promise.race([fetchPromise, timeoutPromise]).then((data) => {
13 | setColor('green')
14 | }).catch(() => {
15 | setColor('red')
16 | })
17 | return () => {
18 | clearTimeout(cancellable)
19 | }
20 | }, [])
21 |
22 | return (
23 |
24 |
Fetch and timeout
25 |
26 |
27 | )
28 | }
29 |
30 | export default Main
31 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/06/06-solution.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | // import { useDispatch, useSelector } from 'react-redux'
3 | import { useDispatch, useSelector } from './react-redux'
4 |
5 | const fetchData = (dispatch) => window.fetch('/api/data').then(({ data }) => dispatch({ type: 'DATA_SUCCESS', data }))
6 | const dataSelector = (state) => state.api13.data
7 |
8 | const Main = () => {
9 | const { data } = useSelector(dataSelector)
10 | const dispatch = useDispatch()
11 | useEffect(() => {
12 | dispatch(fetchData)
13 | }, [dispatch])
14 |
15 | return !data ? ('Loading...') : (
16 | {data.map(({ id }) => - {id}
)}
17 | )
18 | }
19 |
20 | export default Main
--------------------------------------------------------------------------------
/08-testing-hooks/src/06/06-solution.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { render } from '@testing-library/react'
3 | import Main from './06-solution'
4 |
5 | // jest.mock('react-redux', () => ({
6 | jest.mock('./react-redux', () => ({
7 | useDispatch: () => jest.fn(),
8 | useSelector: () => ({ data: [{ id: 2 }] }),
9 | // useSelector: (selectorFn) => {
10 | // switch (selectorFn.name) {
11 | // case 'dataSelector':
12 | // return { data: [{ id: 2 }] }
13 | // }
14 | // },
15 | connect: () => (Component) => Component
16 | }))
17 |
18 | test('Main', () => {
19 | const { container } = render()
20 | expect(container.textContent).toBe('2')
21 | })
--------------------------------------------------------------------------------
/08-testing-hooks/src/06/react-redux.js:
--------------------------------------------------------------------------------
1 | export const useDispatch = () => undefined
2 | export const useSelector = () => undefined
--------------------------------------------------------------------------------
/08-testing-hooks/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/08-testing-hooks/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: https://bit.ly/CRA-PWA
12 | serviceWorker.unregister();
13 |
--------------------------------------------------------------------------------
/09-typescript-in-react/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/09-typescript-in-react/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 90,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": true,
7 | "bracketSpacing": false,
8 | "trailingComma": "none",
9 | "jsxBracketSameLine": true,
10 | "arrowParens": "always",
11 | "parser": "typescript",
12 | "overrides": [{
13 | "files": "*.md",
14 | "options": {
15 | "parser": "markdown",
16 | "proseWrap": "always",
17 | "printWidth": 80
18 | }
19 | }]
20 | }
--------------------------------------------------------------------------------
/09-typescript-in-react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typescript_app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@types/jest": "24.0.23",
7 | "@types/node": "12.12.11",
8 | "@types/react-dom": "16.9.4",
9 | "prop-types": "^15.7.2",
10 | "react": "^16.12.0",
11 | "react-dom": "^16.12.0",
12 | "react-router-dom": "^5.1.2",
13 | "react-scripts": "3.2.0",
14 | "typescript": "3.7.2"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test",
20 | "eject": "react-scripts eject"
21 | },
22 | "browserslist": {
23 | "production": [
24 | ">0.2%",
25 | "not dead",
26 | "not op_mini all"
27 | ],
28 | "development": [
29 | "last 1 chrome version",
30 | "last 1 firefox version",
31 | "last 1 safari version"
32 | ]
33 | },
34 | "devDependencies": {
35 | "@types/react": "^16.9.11",
36 | "@types/react-router-dom": "^5.1.2",
37 | "prettier": "^1.19.0"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/09-typescript-in-react/public/IMG_5437.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/09-typescript-in-react/public/IMG_5437.JPG
--------------------------------------------------------------------------------
/09-typescript-in-react/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/09-typescript-in-react/public/favicon.ico
--------------------------------------------------------------------------------
/09-typescript-in-react/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/09-typescript-in-react/public/logo192.png
--------------------------------------------------------------------------------
/09-typescript-in-react/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/msd-code-academy/react-workshop/3fba5ae04d3e9e96b7ed20734603dcf1e300261a/09-typescript-in-react/public/logo512.png
--------------------------------------------------------------------------------
/09-typescript-in-react/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/09-typescript-in-react/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/exercise-1/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './blog';
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/exercise-2/fetch-jokes.ts:
--------------------------------------------------------------------------------
1 | export type Joke = {
2 | id: string;
3 | icon_url: string;
4 | value: string;
5 | };
6 |
7 | const fetchJokes = async (query: string): Promise => {
8 | try {
9 | const result = await fetch(`https://api.chucknorris.io/jokes/search?query=${query}`);
10 | const resultJSON = await result.json();
11 | return resultJSON.result || [];
12 | } catch (error) {
13 | console.error(error);
14 | return [];
15 | }
16 | };
17 |
18 | export default fetchJokes;
19 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/exercise-2/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './jokes';
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/exercise-3/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './clock';
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/homepage/homepage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const HomePage = () => {
4 | // Place for playing with the code:
5 |
6 |
7 |
8 | return Home Page
;
9 | };
10 |
11 | export default HomePage;
12 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/homepage/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './homepage';
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
--------------------------------------------------------------------------------
/09-typescript-in-react/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/sandbox.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | enum Color {
4 | Red = 'red',
5 | Green = 'green',
6 | Blue = 'blue'
7 | }
8 |
9 | const myColor: Color = Color.Green;
10 | console.log(myColor);
--------------------------------------------------------------------------------
/09-typescript-in-react/src/solution-1/blog.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export type BlogPost = {
4 | title: string;
5 | text: string;
6 | id: number;
7 | };
8 |
9 | // Article component
10 | type ArticleProps = Omit;
11 |
12 | const Article: React.FC = ({title = '', text = ''}) => (
13 | <>
14 | {title}
15 | {text}
16 | >
17 | );
18 |
19 | // Blog component that displays multiple articles
20 | type BlogProps = {};
21 |
22 | const Blog: React.FC = () => {
23 | const myArticles: BlogPost[] = [
24 | {
25 | id: 1,
26 | title: 'TypeScript is awesome',
27 | text: 'Every day I do not use TypeScript a kitten dies.'
28 | },
29 | {
30 | id: 2,
31 | title: 'Jar Jar Binks was a sith lord',
32 | text: 'It all make sense when you think about it!'
33 | }
34 | ];
35 |
36 | return (
37 | <>
38 | My Blog
39 | {myArticles.map((article) => (
40 |
41 | ))}
42 | >
43 | );
44 | };
45 |
46 | export default Blog;
47 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/solution-1/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './blog';
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/solution-2/fetch-jokes.ts:
--------------------------------------------------------------------------------
1 | export type Joke = {
2 | id: string;
3 | icon_url: string;
4 | value: string;
5 | };
6 |
7 | const fetchJokes = async (query: string): Promise => {
8 | try {
9 | const result = await fetch(`https://api.chucknorris.io/jokes/search?query=${query}`);
10 | const resultJSON = await result.json();
11 | return resultJSON.result || [];
12 | } catch (error) {
13 | console.error(error);
14 | return [];
15 | }
16 | };
17 |
18 | export default fetchJokes;
19 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/solution-2/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './jokes';
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/solution-3/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './clock';
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/use-context/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './use-context';
--------------------------------------------------------------------------------
/09-typescript-in-react/src/use-context/use-context.tsx:
--------------------------------------------------------------------------------
1 | import React, {createContext, useContext, useState} from 'react';
2 |
3 | // Context object initiation
4 | type Theme = 'light' | 'dark';
5 | const ThemeContext = createContext('dark');
6 |
7 |
8 | // Consumer component
9 | const MyComponent = () => {
10 | const theme = useContext(ThemeContext);
11 | return The theme is {theme}
;
12 | }
13 |
14 |
15 | // Provider component
16 | const ComponentWithUseContext = () => {
17 | const [theme, setTheme] = useState('dark'); //<= we are explicitly telling useState to use the Theme type
18 |
19 | return (
20 |
21 |
22 | setTheme(theme === 'dark' ? 'light' : 'dark')}>
23 | Change the theme
24 |
25 |
26 | );
27 | }
28 |
29 | export default ComponentWithUseContext;
30 |
--------------------------------------------------------------------------------
/09-typescript-in-react/src/use-reducer/index.tsx:
--------------------------------------------------------------------------------
1 | export {default} from './use-reducer';
2 |
--------------------------------------------------------------------------------
/09-typescript-in-react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "react"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | 'browser': true,
4 | 'es6': true
5 | },
6 | extends: [
7 | 'plugin:react/recommended',
8 | 'prettier/@typescript-eslint',
9 | 'plugin:prettier/recommended'
10 | ],
11 | globals: {
12 | 'Atomics': 'readonly',
13 | 'SharedArrayBuffer': 'readonly'
14 | },
15 | parser: '@typescript-eslint/parser',
16 | parserOptions: {
17 | ecmaFeatures: {
18 | 'jsx': true
19 | },
20 | ecmaVersion: 2018,
21 | sourceType: 'module'
22 | },
23 | plugins: [
24 | 'react',
25 | '@typescript-eslint'
26 | ],
27 | rules: {
28 | 'react/prop-types': 0
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: true,
3 | trailingComma: 'all',
4 | singleQuote: true,
5 | printWidth: 120,
6 | tabWidth: 2,
7 | };
8 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Roman Klos
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/01-exercise-suspense/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 | import { fetchPeople } from '../utils/fetch';
3 | import { Person } from '../utils/types';
4 |
5 | // TODO: Create resource
6 |
7 | const People: FC<{}> = () => {
8 | // TODO: Read resource
9 |
10 | return {/* {people.map((person, index) => (
11 | - {person.name}
12 | ))} */}
;
13 | };
14 |
15 | const Exercise01: FC<{}> = () => {
16 | // TODO: Add Suspense with fallback
17 | return ;
18 | };
19 |
20 | export default Exercise01;
21 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/02-exercise-error-boundaries/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 | import { People } from './people';
3 |
4 | // TODO: Create ErrorBoundary component
5 |
6 | const Exercise02: FC<{}> = () => {
7 | // TODO: Add ErrorBoundary
8 | return (
9 | Loading people...}>
10 |
11 |
12 | );
13 | };
14 |
15 | export default Exercise02;
16 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/02-exercise-error-boundaries/people.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 | import { fetchPeople } from '../utils/fetch';
3 | import { Person } from '../utils/types';
4 | import { wrapPromise } from '../utils/wrapPromise';
5 |
6 | const peopleResource = wrapPromise(fetchPeople);
7 |
8 | export const People: FC<{}> = () => {
9 | const people = peopleResource.read();
10 |
11 | return (
12 |
13 | {people.map((person, index) => (
14 | - {person.name}
15 | ))}
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/03-exercise-loading-states/people.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'React';
2 | import { fetchPeople } from '../utils/fetch';
3 | import { wrapPromise } from '../utils/wrapPromise';
4 | import { Person } from '../utils/types';
5 |
6 | const createPeopleResource = () => {
7 | return wrapPromise(() => fetchPeople(100));
8 | };
9 |
10 | const peopleResource = createPeopleResource();
11 |
12 | export const People: FC<{
13 | onClick: (name: string) => void;
14 | }> = ({ onClick }) => {
15 | const people = peopleResource.read();
16 |
17 | return (
18 |
19 | Suggestions:
20 |
29 |
30 | );
31 | };
32 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/03-exercise-loading-states/person.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'React';
2 | import { Person } from '../utils/types';
3 | type PersonResource = { read: () => Person };
4 |
5 | export const PersonInfo: FC<{
6 | personResource: PersonResource;
7 | }> = ({ personResource }) => {
8 | const person = personResource.read();
9 |
10 | return (
11 |
12 |
{person.name}
13 |
Height: {person.height}
14 |
Weight: {person.mass}
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/03-exercise-loading-states/style.css:
--------------------------------------------------------------------------------
1 | .container--loading {
2 | opacity: 0.6;
3 | transition: opacity 0s;
4 | /* note: the transition delay is the same as the busyDelayMs config */
5 | transition-delay: 0.4s;
6 | }
7 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/04-exercise-suspense-list/leftNav.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 |
3 | const LeftNav: FC<{}> = () => LeftNav
;
4 |
5 | export default LeftNav;
6 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/04-exercise-suspense-list/mainContent.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 |
3 | const MainContent: FC<{}> = () => MainContent
;
4 |
5 | export default MainContent;
6 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/04-exercise-suspense-list/navBar.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 |
3 | const NavBar: FC<{}> = () => NavBar
;
4 |
5 | export default NavBar;
6 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/04-exercise-suspense-list/rightNav.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 |
3 | const RightNav: FC<{}> = () => RightNav
;
4 |
5 | export default RightNav;
6 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/04-exercise-suspense-list/spinner.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 |
3 | export const Spinner: FC<{}> = () => {
4 | return (
5 |
6 | Loading...
7 |
8 | );
9 | };
10 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/04-exercise-suspense-list/style.css:
--------------------------------------------------------------------------------
1 | /* .nav-bar {
2 |
3 | }
4 |
5 | .main-content {
6 |
7 | }
8 |
9 | .left-nav {
10 |
11 | }
12 |
13 | .right-nav {
14 |
15 | } */
16 |
17 | .main-container {
18 | display: flex;
19 | flex-direction: column;
20 | }
21 |
22 | .content-container {
23 | display: flex;
24 | flex-direction: row;
25 | }
26 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/app.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 |
3 | import Exercise01 from './01-exercise-suspense';
4 | import Exercise02 from './02-exercise-error-boundaries';
5 | import Exercise03 from './03-exercise-loading-states';
6 | import Exercise04 from './04-exercise-suspense-list';
7 |
8 | export const App: FC<{}> = () => {
9 | return (
10 | <>
11 |
12 | {/* */}
13 | {/* */}
14 | {/* */}
15 | >
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import { App } from './app';
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render();
7 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/utils/errorBoundary.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class ErrorBoundary extends React.Component {
4 | state = { error: null };
5 | static getDerivedStateFromError(error) {
6 | return { error };
7 | }
8 | componentDidCatch() {
9 | // log the error to the server
10 | }
11 | tryAgain = () => this.setState({ error: null });
12 | render() {
13 | return this.state.error ? (
14 |
15 | There was an error.
16 |
{this.state.error.message}
17 |
18 | ) : (
19 | this.props.children
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/utils/fetch.ts:
--------------------------------------------------------------------------------
1 | import { Person } from './types';
2 |
3 | export const sleep = (time: number) => new Promise(resolve => setTimeout(resolve, time));
4 |
5 | export const fetchPerson = async (name: string = '', delay: number = 3000): Promise => {
6 | const people = await fetch(`https://swapi.co/api/people/?search=${name}`);
7 | const peopleJSON = await people.json();
8 |
9 | const person = peopleJSON.results[0];
10 | if (!person) {
11 | throw new Error('Could not find person!');
12 | }
13 |
14 | await sleep(delay);
15 |
16 | return person;
17 | };
18 |
19 | export const fetchPeople = async (delay: number = 3000): Promise => {
20 | const people = await fetch('https://swapi.co/api/people/');
21 | const peopleJSON = await people.json();
22 |
23 | const peopleResults = peopleJSON.results;
24 |
25 | if (!peopleResults) {
26 | throw new Error('Could not find people!');
27 | }
28 |
29 | await sleep(delay);
30 |
31 | return peopleResults;
32 | };
33 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/utils/types.ts:
--------------------------------------------------------------------------------
1 | export interface Person {
2 | gender: string;
3 | hair_color: string;
4 | height: string;
5 | mass: string;
6 | name: string;
7 | skin_color: string;
8 | birth_year: string;
9 | eye_color: string;
10 | }
11 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/src/utils/wrapPromise.ts:
--------------------------------------------------------------------------------
1 | type Status = 'pending' | 'complete' | 'error';
2 |
3 | export const wrapPromise = (promiseFn: () => Promise): { read: () => T } => {
4 | let status: Status = 'pending';
5 | let result: T;
6 |
7 | const resourcePromise = promiseFn()
8 | .then(r => {
9 | status = 'complete';
10 | result = r;
11 | })
12 | .catch(e => {
13 | status = 'error';
14 | result = e;
15 | });
16 |
17 | return {
18 | read: () => {
19 | if (status === 'pending') throw resourcePromise;
20 | if (status === 'error') throw result;
21 |
22 | return result;
23 | },
24 | };
25 | };
26 |
--------------------------------------------------------------------------------
/10-suspense-for-data-fetching/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "react",
4 | "esModuleInterop": true,
5 | "target": "es2018",
6 | "module": "commonjs",
7 | "types": [
8 | "react/experimental",
9 | "react-dom/experimental"
10 | ]
11 | },
12 | "include": [
13 | "src"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 MSD Code Academy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------