├── 01 Services ├── src │ ├── rest-api │ │ ├── index.js │ │ └── github.js │ ├── index.css │ ├── App.test.js │ ├── index.js │ ├── App.css │ ├── App.js │ ├── logo.svg │ └── registerServiceWorker.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── .gitignore └── package.json ├── 04 Redux ├── src │ ├── rest-api │ │ ├── index.js │ │ └── github.js │ ├── pods │ │ └── organization │ │ │ ├── index.js │ │ │ ├── const.js │ │ │ ├── reducers.js │ │ │ ├── actions.js │ │ │ ├── container.js │ │ │ └── component.js │ ├── index.css │ ├── App.test.js │ ├── index.js │ ├── App.css │ ├── App.js │ ├── store.js │ ├── logo.svg │ └── registerServiceWorker.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── .gitignore └── package.json ├── 05 OwnProps ├── src │ ├── rest-api │ │ ├── index.js │ │ └── github.js │ ├── pods │ │ └── organization │ │ │ ├── index.js │ │ │ ├── const.js │ │ │ ├── reducers.js │ │ │ ├── actions.js │ │ │ ├── component.js │ │ │ └── container.js │ ├── index.css │ ├── App.test.js │ ├── index.js │ ├── App.css │ ├── App.js │ ├── store.js │ ├── logo.svg │ └── registerServiceWorker.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── .gitignore ├── package.json └── README.md ├── 03 ReactApp_Rest ├── src │ ├── rest-api │ │ ├── index.js │ │ └── github.js │ ├── index.css │ ├── App.test.js │ ├── index.js │ ├── App.css │ ├── App.js │ ├── pods │ │ └── organization │ │ │ ├── component.js │ │ │ └── container.js │ ├── logo.svg │ └── registerServiceWorker.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── .gitignore └── package.json ├── 02 ReactApp_Mocked ├── src │ ├── rest-api │ │ ├── index.js │ │ └── github.js │ ├── index.css │ ├── App.test.js │ ├── index.js │ ├── App.css │ ├── App.js │ ├── pods │ │ └── organization │ │ │ ├── component.js │ │ │ └── container.js │ ├── logo.svg │ └── registerServiceWorker.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── .gitignore └── package.json ├── 06 Recompose FComponents ├── src │ ├── rest-api │ │ ├── index.js │ │ └── github.js │ ├── pods │ │ ├── organization │ │ │ ├── index.js │ │ │ ├── const.js │ │ │ ├── reducers.js │ │ │ ├── actions.js │ │ │ ├── container.js │ │ │ └── component.js │ │ └── recompose-demo │ │ │ ├── cardExampleRecompose.js │ │ │ ├── openable.js │ │ │ └── cardExample.js │ ├── App.test.js │ ├── index.js │ ├── App.css │ ├── App.js │ ├── index.css │ ├── store.js │ └── registerServiceWorker.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── .gitignore ├── package.json └── README.md ├── 00 Boilerplate ├── src │ ├── index.css │ ├── App.test.js │ ├── index.js │ ├── App.css │ ├── App.js │ ├── logo.svg │ └── registerServiceWorker.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── .gitignore └── package.json ├── .gitignore ├── LICENSE └── readme.md /01 Services/src/rest-api/index.js: -------------------------------------------------------------------------------- 1 | export * from './github'; -------------------------------------------------------------------------------- /04 Redux/src/rest-api/index.js: -------------------------------------------------------------------------------- 1 | export * from './github'; -------------------------------------------------------------------------------- /05 OwnProps/src/rest-api/index.js: -------------------------------------------------------------------------------- 1 | export * from './github'; -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/rest-api/index.js: -------------------------------------------------------------------------------- 1 | export * from './github'; -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/rest-api/index.js: -------------------------------------------------------------------------------- 1 | export * from './github'; -------------------------------------------------------------------------------- /06 Recompose FComponents/src/rest-api/index.js: -------------------------------------------------------------------------------- 1 | export * from './github'; -------------------------------------------------------------------------------- /04 Redux/src/pods/organization/index.js: -------------------------------------------------------------------------------- 1 | export { organizationReducer } from './reducers'; -------------------------------------------------------------------------------- /05 OwnProps/src/pods/organization/index.js: -------------------------------------------------------------------------------- 1 | export { organizationReducer } from './reducers'; -------------------------------------------------------------------------------- /01 Services/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /04 Redux/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /05 OwnProps/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /00 Boilerplate/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/organization/index.js: -------------------------------------------------------------------------------- 1 | export { organizationReducer, repoReducer } from './reducers'; -------------------------------------------------------------------------------- /04 Redux/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/dev-workflow-demos/master/04 Redux/public/favicon.ico -------------------------------------------------------------------------------- /01 Services/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/dev-workflow-demos/master/01 Services/public/favicon.ico -------------------------------------------------------------------------------- /05 OwnProps/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/dev-workflow-demos/master/05 OwnProps/public/favicon.ico -------------------------------------------------------------------------------- /00 Boilerplate/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/dev-workflow-demos/master/00 Boilerplate/public/favicon.ico -------------------------------------------------------------------------------- /03 ReactApp_Rest/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/dev-workflow-demos/master/03 ReactApp_Rest/public/favicon.ico -------------------------------------------------------------------------------- /02 ReactApp_Mocked/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/dev-workflow-demos/master/02 ReactApp_Mocked/public/favicon.ico -------------------------------------------------------------------------------- /06 Recompose FComponents/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/dev-workflow-demos/master/06 Recompose FComponents/public/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist/ 4 | typings/ 5 | *.orig 6 | .idea/ 7 | */src/**/*.js.map 8 | **/.vscode/ 9 | .editorconfig 10 | yarn.lock 11 | *.log -------------------------------------------------------------------------------- /04 Redux/src/pods/organization/const.js: -------------------------------------------------------------------------------- 1 | 2 | export const actionsDefs = { 3 | LOAD_MEMBERS_REQUEST: 'LOAD_MEMBERS_REQUEST', 4 | LOAD_MEMBERS_REQUEST_COMPLETED: 'LOAD_MEMBERS_REQUEST_COMPLETED', 5 | } -------------------------------------------------------------------------------- /05 OwnProps/src/pods/organization/const.js: -------------------------------------------------------------------------------- 1 | 2 | export const actionsDefs = { 3 | LOAD_MEMBERS_REQUEST: 'LOAD_MEMBERS_REQUEST', 4 | LOAD_MEMBERS_REQUEST_COMPLETED: 'LOAD_MEMBERS_REQUEST_COMPLETED', 5 | } -------------------------------------------------------------------------------- /01 Services/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 | }); 9 | -------------------------------------------------------------------------------- /04 Redux/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 | }); 9 | -------------------------------------------------------------------------------- /05 OwnProps/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 | }); 9 | -------------------------------------------------------------------------------- /00 Boilerplate/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 | }); 9 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/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 | }); 9 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/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 | }); 9 | -------------------------------------------------------------------------------- /06 Recompose FComponents/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 | }); 9 | -------------------------------------------------------------------------------- /04 Redux/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 registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /00 Boilerplate/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 registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /01 Services/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 registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /05 OwnProps/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 registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/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 registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/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 registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /06 Recompose FComponents/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 registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /04 Redux/src/pods/organization/reducers.js: -------------------------------------------------------------------------------- 1 | import { actionsDefs } from './const' 2 | 3 | export const organizationReducer = (state = [], action) => { 4 | switch(action.type) { 5 | case actionsDefs.LOAD_MEMBERS_REQUEST_COMPLETED: 6 | return action.payload; 7 | break; 8 | } 9 | 10 | return state; 11 | } -------------------------------------------------------------------------------- /05 OwnProps/src/pods/organization/reducers.js: -------------------------------------------------------------------------------- 1 | import { actionsDefs } from './const' 2 | 3 | export const organizationReducer = (state = [], action) => { 4 | switch(action.type) { 5 | case actionsDefs.LOAD_MEMBERS_REQUEST_COMPLETED: 6 | return action.payload; 7 | break; 8 | } 9 | 10 | return state; 11 | } -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/organization/const.js: -------------------------------------------------------------------------------- 1 | 2 | export const actionsDefs = { 3 | LOAD_MEMBERS_REQUEST: 'LOAD_MEMBERS_REQUEST', 4 | LOAD_MEMBERS_REQUEST_COMPLETED: 'LOAD_MEMBERS_REQUEST_COMPLETED', 5 | LOAD_REPOS_REQUEST: 'LOAD_MEMBERS_REQUEST', 6 | LOAD_REPOS_REQUEST_COMPLETED: 'LOAD_REPOS_REQUEST_COMPLETED', 7 | }; 8 | -------------------------------------------------------------------------------- /04 Redux/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /01 Services/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /05 OwnProps/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /00 Boilerplate/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /01 Services/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /04 Redux/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /05 OwnProps/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /00 Boilerplate/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /06 Recompose FComponents/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /06 Recompose FComponents/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /01 Services/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^15.6.1", 7 | "react-dom": "^15.6.1", 8 | "react-scripts": "1.0.11" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } -------------------------------------------------------------------------------- /00 Boilerplate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^15.6.1", 7 | "react-dom": "^15.6.1", 8 | "react-scripts": "1.0.11" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject" 15 | } 16 | } -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/recompose-demo/cardExampleRecompose.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import {withState} from "recompose"; 3 | 4 | const TitledCard = ({isOpen, setOpen, title, text}) => ( 5 | 6 | setOpen(!isOpen)} title={title}/> 7 | <Body isOpen={isOpen}>{text}</Body> 8 | </Card> 9 | ); 10 | 11 | export default withState("isOpen", "setOpen", false)(TitledCard) 12 | -------------------------------------------------------------------------------- /04 Redux/src/rest-api/github.js: -------------------------------------------------------------------------------- 1 | const baseURL = 'https://api.github.com/orgs/lemoncode'; 2 | const membersURL = `${baseURL}/members`; 3 | const reposURL = `${baseURL}/repos`; 4 | 5 | export const fetchMembers = () => { 6 | 7 | return fetch(membersURL) 8 | .then((response) => response.json()); 9 | } 10 | 11 | export const fetchRepos = () => { 12 | 13 | return fetch(reposURL) 14 | .then((response) => response.json()); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /01 Services/src/rest-api/github.js: -------------------------------------------------------------------------------- 1 | const baseURL = 'https://api.github.com/orgs/lemoncode'; 2 | const membersURL = `${baseURL}/members`; 3 | const reposURL = `${baseURL}/repos`; 4 | 5 | export const fetchMembers = () => { 6 | 7 | return fetch(membersURL) 8 | .then((response) => response.json()); 9 | } 10 | 11 | export const fetchRepos = () => { 12 | 13 | return fetch(reposURL) 14 | .then((response) => response.json()); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /04 Redux/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /05 OwnProps/src/rest-api/github.js: -------------------------------------------------------------------------------- 1 | const baseURL = 'https://api.github.com/orgs/lemoncode'; 2 | const membersURL = `${baseURL}/members`; 3 | const reposURL = `${baseURL}/repos`; 4 | 5 | export const fetchMembers = () => { 6 | 7 | return fetch(membersURL) 8 | .then((response) => response.json()); 9 | } 10 | 11 | export const fetchRepos = () => { 12 | 13 | return fetch(reposURL) 14 | .then((response) => response.json()); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /00 Boilerplate/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /01 Services/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/rest-api/github.js: -------------------------------------------------------------------------------- 1 | const baseURL = 'https://api.github.com/orgs/lemoncode'; 2 | const membersURL = `${baseURL}/members`; 3 | const reposURL = `${baseURL}/repos`; 4 | 5 | export const fetchMembers = () => { 6 | 7 | return fetch(membersURL) 8 | .then((response) => response.json()); 9 | } 10 | 11 | export const fetchRepos = () => { 12 | 13 | return fetch(reposURL) 14 | .then((response) => response.json()); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/rest-api/github.js: -------------------------------------------------------------------------------- 1 | const baseURL = 'https://api.github.com/orgs/lemoncode'; 2 | const membersURL = `${baseURL}/members`; 3 | const reposURL = `${baseURL}/repos`; 4 | 5 | export const fetchMembers = () => { 6 | 7 | return fetch(membersURL) 8 | .then((response) => response.json()); 9 | } 10 | 11 | export const fetchRepos = () => { 12 | 13 | return fetch(reposURL) 14 | .then((response) => response.json()); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /05 OwnProps/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^15.6.1", 8 | "react-dom": "^15.6.1", 9 | "react-scripts": "1.0.11" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /06 Recompose FComponents/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-intro { 18 | font-size: large; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { transform: rotate(0deg); } 23 | to { transform: rotate(360deg); } 24 | } 25 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | import { OrganizationContainer } from './pods/organization/container' 5 | 6 | class App extends Component { 7 | 8 | constructor(props) { 9 | super(props); 10 | } 11 | 12 | render() { 13 | return ( 14 | <div className="App"> 15 | <OrganizationContainer/> 16 | </div> 17 | ); 18 | } 19 | } 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | import { OrganizationContainer } from './pods/organization/container' 5 | 6 | class App extends Component { 7 | 8 | constructor(props) { 9 | super(props); 10 | } 11 | 12 | render() { 13 | return ( 14 | <div className="App"> 15 | <OrganizationContainer/> 16 | </div> 17 | ); 18 | } 19 | } 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^15.6.1", 8 | "react-dom": "^15.6.1", 9 | "react-redux": "^5.0.6", 10 | "react-scripts": "1.0.11", 11 | "redux": "^3.7.2" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /04 Redux/src/pods/organization/actions.js: -------------------------------------------------------------------------------- 1 | import { actionsDefs } from './const'; 2 | import {fetchMembers} from '../../rest-api' 3 | 4 | export const loadMembersRequest = () => (dispatcher) =>{ 5 | const promise = fetchMembers(); 6 | 7 | promise.then( 8 | (data) => dispatcher(loadMemberRequestCompleted(data)) 9 | ); 10 | 11 | return promise; 12 | } 13 | 14 | export const loadMemberRequestCompleted = (members) => { 15 | return { 16 | type: actionsDefs.LOAD_MEMBERS_REQUEST_COMPLETED, 17 | payload: members 18 | } 19 | } -------------------------------------------------------------------------------- /05 OwnProps/src/pods/organization/actions.js: -------------------------------------------------------------------------------- 1 | import { actionsDefs } from './const'; 2 | import {fetchMembers} from '../../rest-api' 3 | 4 | export const loadMembersRequest = () => (dispatcher) =>{ 5 | const promise = fetchMembers(); 6 | 7 | promise.then( 8 | (data) => dispatcher(loadMemberRequestCompleted(data)) 9 | ); 10 | 11 | return promise; 12 | } 13 | 14 | export const loadMemberRequestCompleted = (members) => { 15 | return { 16 | type: actionsDefs.LOAD_MEMBERS_REQUEST_COMPLETED, 17 | payload: members 18 | } 19 | } -------------------------------------------------------------------------------- /04 Redux/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^15.6.1", 8 | "react-dom": "^15.6.1", 9 | "react-redux": "^5.0.6", 10 | "react-scripts": "1.0.11", 11 | "redux": "^3.7.2", 12 | "redux-thunk": "^2.2.0" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /05 OwnProps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^15.6.1", 8 | "react-dom": "^15.6.1", 9 | "react-redux": "^5.0.6", 10 | "react-scripts": "1.0.11", 11 | "redux": "^3.7.2", 12 | "redux-thunk": "^2.2.0" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/recompose-demo/openable.js: -------------------------------------------------------------------------------- 1 | import {withStateHandlers} from "recompose"; 2 | 3 | export const openable = withStateHandlers( 4 | // state 5 | { 6 | isOpen: false, 7 | }, { 8 | // Handler creator -> {...props, ...state} 9 | toggleOpen: ({isOpen, ...restProps}) => 10 | //handler - it's result will call setState of newly created hoc. 11 | () => ({ 12 | isOpen: !isOpen 13 | }), 14 | // optional 15 | open: () => ({isOpen: true}), 16 | close: () => ({isOpen: false}), 17 | } 18 | ); -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/organization/reducers.js: -------------------------------------------------------------------------------- 1 | import { actionsDefs } from './const' 2 | 3 | export const organizationReducer = (state = [], action) => { 4 | switch(action.type) { 5 | case actionsDefs.LOAD_MEMBERS_REQUEST_COMPLETED: 6 | return action.payload; 7 | default: 8 | return state; 9 | } 10 | }; 11 | 12 | export const repoReducer = (state = [], action) => { 13 | switch(action.type) { 14 | case actionsDefs.LOAD_REPOS_REQUEST_COMPLETED: 15 | return action.payload; 16 | default: 17 | return state; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /00 Boilerplate/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | class App extends Component { 6 | render() { 7 | return ( 8 | <div className="App"> 9 | <div className="App-header"> 10 | <img src={logo} className="App-logo" alt="logo" /> 11 | <h2>Welcome to React</h2> 12 | </div> 13 | <p className="App-intro"> 14 | To get started, edit <code>src/App.js</code> and save to reload. 15 | </p> 16 | </div> 17 | ); 18 | } 19 | } 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /01 Services/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | class App extends Component { 6 | render() { 7 | return ( 8 | <div className="App"> 9 | <div className="App-header"> 10 | <img src={logo} className="App-logo" alt="logo" /> 11 | <h2>Welcome to React</h2> 12 | </div> 13 | <p className="App-intro"> 14 | To get started, edit <code>src/App.js</code> and save to reload. 15 | </p> 16 | </div> 17 | ); 18 | } 19 | } 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /06 Recompose FComponents/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpleapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "lodash": "^4.17.4", 7 | "prop-types": "^15.5.10", 8 | "react": "^15.6.1", 9 | "react-dom": "^15.6.1", 10 | "react-redux": "^5.0.6", 11 | "react-scripts": "1.0.11", 12 | "recompose": "^0.25.0", 13 | "redux": "^3.7.2", 14 | "redux-thunk": "^2.2.0" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test --env=jsdom", 20 | "eject": "react-scripts eject" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/recompose-demo/cardExample.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export default class TitledCard extends React.Component { 4 | state = { 5 | isOpen: false, 6 | }; 7 | 8 | render () { 9 | const {title, text} = this.props; 10 | const {isOpen} = this.state; 11 | 12 | return ( 13 | <Card> 14 | <Title toggleOpen={this.toggleOpen} title={title}/> 15 | <Body isOpen={isOpen}>{text}</Body> 16 | </Card> 17 | ); 18 | } 19 | 20 | toggleOpen = () => this.setState({isOpen: !this.state.isOpen}); 21 | } -------------------------------------------------------------------------------- /06 Recompose FComponents/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import './App.css'; 4 | import configureStore from './store'; 5 | import { OrganizationContainer } from './pods/organization/container' 6 | 7 | const WrappedProvider = ({ children }) => ( 8 | <Provider store={configureStore({})}>{children}</Provider> 9 | ); 10 | 11 | class App extends Component { 12 | render() { 13 | return ( 14 | <div className="App"> 15 | <WrappedProvider> 16 | <OrganizationContainer/> 17 | </WrappedProvider> 18 | </div> 19 | ); 20 | } 21 | } 22 | 23 | export default App; 24 | -------------------------------------------------------------------------------- /06 Recompose FComponents/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | 7 | .card { 8 | padding: 10px; 9 | margin: 10px; 10 | background: white; 11 | box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5); 12 | 13 | list-style: none; 14 | } 15 | 16 | 17 | 18 | .organization { 19 | width: 50%; 20 | margin: 0 auto; 21 | } 22 | 23 | .card li { 24 | display: flex; 25 | align-items: center; 26 | justify-content: center; 27 | border-bottom: 1px solid #eee; 28 | padding: 10px; 29 | } 30 | 31 | .card li:last-of-type { 32 | border-bottom: none; 33 | } 34 | 35 | .card img { 36 | border-radius: 50%; 37 | margin-right: 10px; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /04 Redux/src/pods/organization/container.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { OrganizationComponent } from './component' 4 | import { loadMembersRequest } from './actions'; 5 | 6 | 7 | 8 | const mapStateToProps = (state) => ({ 9 | members: state.organization, 10 | }); 11 | 12 | const mapDispatchToProps = (dispatch) => ({ 13 | fetchMembers: () => dispatch(loadMembersRequest()) 14 | }) 15 | 16 | export const OrganizationContainer = connect(mapStateToProps, 17 | mapDispatchToProps, 18 | )(OrganizationComponent); 19 | 20 | export default OrganizationContainer; 21 | -------------------------------------------------------------------------------- /04 Redux/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import logo from './logo.svg'; 4 | import './App.css'; 5 | import configureStore from './store'; 6 | import { OrganizationContainer } from './pods/organization/container' 7 | 8 | const WrappedProvider = ({ children }) => ( 9 | <Provider store={configureStore({})}>{children}</Provider> 10 | ); 11 | 12 | class App extends Component { 13 | 14 | constructor(props) { 15 | super(props); 16 | } 17 | 18 | render() { 19 | return ( 20 | <div className="App"> 21 | <WrappedProvider> 22 | <OrganizationContainer/> 23 | </WrappedProvider> 24 | </div> 25 | ); 26 | } 27 | } 28 | 29 | export default App; 30 | -------------------------------------------------------------------------------- /05 OwnProps/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import logo from './logo.svg'; 4 | import './App.css'; 5 | import configureStore from './store'; 6 | import { OrganizationContainer } from './pods/organization/container' 7 | 8 | const WrappedProvider = ({ children }) => ( 9 | <Provider store={configureStore({})}>{children}</Provider> 10 | ); 11 | 12 | class App extends Component { 13 | 14 | constructor(props) { 15 | super(props); 16 | } 17 | 18 | render() { 19 | return ( 20 | <div className="App"> 21 | <WrappedProvider> 22 | <OrganizationContainer/> 23 | </WrappedProvider> 24 | </div> 25 | ); 26 | } 27 | } 28 | 29 | export default App; 30 | -------------------------------------------------------------------------------- /04 Redux/src/pods/organization/component.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const MemberListItem = ({member}) => ( 5 | <li> 6 | <span>{member.login}</span> 7 | </li> 8 | ); 9 | 10 | 11 | export class OrganizationComponent extends Component { 12 | 13 | componentDidMount() { 14 | this.props.fetchMembers(); 15 | } 16 | 17 | render() { 18 | return ( 19 | <ul> 20 | { 21 | this.props.members.map((member) => 22 | <MemberListItem key={member.id} member={member} /> 23 | ) 24 | } 25 | </ul> 26 | ); 27 | } 28 | } 29 | 30 | OrganizationComponent.propTypes = { 31 | members : PropTypes.array.isRequired, 32 | fetchMembers : PropTypes.func.isRequired, 33 | } -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/pods/organization/component.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const MemberListItem = ({member}) => ( 5 | <li> 6 | <span>{member.login}</span> 7 | </li> 8 | ); 9 | 10 | 11 | export class OrganizationComponent extends Component { 12 | 13 | componentDidMount() { 14 | this.props.fetchMembers(); 15 | } 16 | 17 | render() { 18 | return ( 19 | <ul> 20 | { 21 | this.props.members.map((member) => 22 | <MemberListItem key={member.id} member={member} /> 23 | ) 24 | } 25 | </ul> 26 | ); 27 | } 28 | } 29 | 30 | OrganizationComponent.propTypes = { 31 | members : PropTypes.array.isRequired, 32 | fetchMembers : PropTypes.func.isRequired, 33 | } -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/pods/organization/component.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const MemberListItem = ({member}) => ( 5 | <li> 6 | <span>{member.login}</span> 7 | </li> 8 | ); 9 | 10 | 11 | export class OrganizationComponent extends Component { 12 | 13 | componentDidMount() { 14 | this.props.fetchMembers(); 15 | } 16 | 17 | render() { 18 | return ( 19 | <ul> 20 | { 21 | this.props.members.map((member) => 22 | <MemberListItem key={member.id} member={member} /> 23 | ) 24 | } 25 | </ul> 26 | ); 27 | } 28 | } 29 | 30 | OrganizationComponent.propTypes = { 31 | members : PropTypes.array.isRequired, 32 | fetchMembers : PropTypes.func.isRequired, 33 | } -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/pods/organization/container.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { OrganizationComponent } from './component' 3 | import { fetchMembers } from '../../rest-api' 4 | 5 | export class OrganizationContainer extends Component { 6 | 7 | constructor(props) { 8 | super(props); 9 | 10 | this.state = { 11 | members : [], 12 | } 13 | } 14 | 15 | fetchTeamMembers = () => { 16 | fetchMembers().then((members) => 17 | this.setState({ 18 | members: members, 19 | }) 20 | ); 21 | } 22 | 23 | render() { 24 | return ( 25 | <OrganizationComponent 26 | members={this.state.members} 27 | fetchMembers={this.fetchTeamMembers} 28 | /> 29 | ); 30 | } 31 | } 32 | 33 | export default OrganizationContainer; 34 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/pods/organization/container.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { OrganizationComponent } from './component' 3 | import { fetchMembers } from '../../rest-api' 4 | 5 | export class OrganizationContainer extends Component { 6 | 7 | constructor(props) { 8 | super(props); 9 | 10 | this.state = { 11 | members : [], 12 | } 13 | } 14 | 15 | fetchTeamMembers = () => { 16 | this.setState({ 17 | members: [ 18 | { login: 'john' }, 19 | { login: 'peter' }, 20 | { login: 'mark' }, 21 | ], 22 | }) 23 | } 24 | 25 | render() { 26 | return ( 27 | <OrganizationComponent 28 | members={this.state.members} 29 | fetchMembers={this.fetchTeamMembers} 30 | /> 31 | ); 32 | } 33 | } 34 | 35 | export default OrganizationContainer; 36 | -------------------------------------------------------------------------------- /04 Redux/src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import { combineReducers } from 'redux'; 3 | import {organizationReducer} from './pods/organization' 4 | import reduxThunk from 'redux-thunk'; 5 | 6 | export default function configureStore(initialState = {}) { 7 | const middlewares = [ 8 | reduxThunk 9 | ]; 10 | 11 | const enhancers = [ 12 | applyMiddleware(...middlewares), 13 | ]; 14 | 15 | const composeEnhancers = 16 | typeof window === 'object' && 17 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? 18 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose; 19 | 20 | const store = createStore( 21 | createReducer(), 22 | composeEnhancers(...enhancers), 23 | ); 24 | 25 | return store; 26 | } 27 | 28 | function createReducer() { 29 | return combineReducers({ 30 | organization : organizationReducer, 31 | }); 32 | } -------------------------------------------------------------------------------- /05 OwnProps/src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import { combineReducers } from 'redux'; 3 | import {organizationReducer} from './pods/organization' 4 | import reduxThunk from 'redux-thunk'; 5 | 6 | export default function configureStore(initialState = {}) { 7 | const middlewares = [ 8 | reduxThunk 9 | ]; 10 | 11 | const enhancers = [ 12 | applyMiddleware(...middlewares), 13 | ]; 14 | 15 | const composeEnhancers = 16 | typeof window === 'object' && 17 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? 18 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose; 19 | 20 | const store = createStore( 21 | createReducer(), 22 | composeEnhancers(...enhancers), 23 | ); 24 | 25 | return store; 26 | } 27 | 28 | function createReducer() { 29 | return combineReducers({ 30 | organization : organizationReducer, 31 | }); 32 | } -------------------------------------------------------------------------------- /06 Recompose FComponents/src/rest-api/github.js: -------------------------------------------------------------------------------- 1 | const baseURL = 'https://api.github.com/orgs/lemoncode'; 2 | const membersURL = `${baseURL}/members`; 3 | const reposURL = `${baseURL}/repos`; 4 | 5 | const mockedMembers = [{ 6 | login: 'Offline User 1', 7 | avatar_url: '/avatar.jpg', 8 | description: 'Awesome description', 9 | }]; 10 | 11 | const mockedRepos = [{ 12 | name: 'Offline Repo 1', 13 | }]; 14 | 15 | const handleReposne = (mock) => (response) => { 16 | return response.status > 400 ? mock : response.json(); 17 | }; 18 | 19 | //TODO WJ: Catch status 403, Return mock! 20 | export const fetchMembers = () => { 21 | return fetch(membersURL) 22 | .then(handleReposne(mockedMembers)) 23 | .catch(() => mockedMembers); 24 | }; 25 | 26 | export const fetchRepos = () => { 27 | return fetch(reposURL) 28 | .then(handleReposne(mockedRepos)) 29 | .catch(() => mockedRepos); 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /06 Recompose FComponents/src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import { combineReducers } from 'redux'; 3 | import {organizationReducer, repoReducer} from './pods/organization' 4 | import reduxThunk from 'redux-thunk'; 5 | 6 | export default function configureStore(initialState = {}) { 7 | const middlewares = [ 8 | reduxThunk 9 | ]; 10 | 11 | const enhancers = [ 12 | applyMiddleware(...middlewares), 13 | ]; 14 | 15 | const composeEnhancers = 16 | typeof window === 'object' && 17 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? 18 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose; 19 | 20 | const store = createStore( 21 | createReducer(), 22 | composeEnhancers(...enhancers), 23 | ); 24 | 25 | return store; 26 | } 27 | 28 | function createReducer() { 29 | return combineReducers({ 30 | organization : organizationReducer, 31 | repo : repoReducer, 32 | }); 33 | } -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/organization/actions.js: -------------------------------------------------------------------------------- 1 | import { actionsDefs } from './const'; 2 | import {fetchMembers, fetchRepos} from '../../rest-api' 3 | 4 | export const loadMembersRequest = () => (dispatcher) =>{ 5 | const promise = fetchMembers(); 6 | 7 | promise.then( 8 | (data) => dispatcher(loadMemberRequestCompleted(data)) 9 | ); 10 | 11 | return promise; 12 | } 13 | 14 | export const loadMemberRequestCompleted = (members) => { 15 | return { 16 | type: actionsDefs.LOAD_MEMBERS_REQUEST_COMPLETED, 17 | payload: members 18 | } 19 | } 20 | 21 | export const loadReposRequest = () => (dispatcher) =>{ 22 | const promise = fetchRepos(); 23 | 24 | promise.then( 25 | (data) => dispatcher(loadReposRequestCompleted(data)) 26 | ); 27 | 28 | return promise; 29 | } 30 | 31 | export const loadReposRequestCompleted = (repos) => { 32 | return { 33 | type: actionsDefs.LOAD_REPOS_REQUEST_COMPLETED, 34 | payload: repos 35 | } 36 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Lemoncode 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 | -------------------------------------------------------------------------------- /05 OwnProps/src/pods/organization/component.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const MemberListItem = ({member}) => ( 5 | <li> 6 | <span>{member.login}</span> 7 | </li> 8 | ); 9 | 10 | const RepoListItem = ({repo}) => ( 11 | <li> 12 | <span>{repo.name}</span> 13 | </li> 14 | ); 15 | 16 | 17 | export class OrganizationComponent extends Component { 18 | 19 | componentDidMount() { 20 | this.props.fetchMembers(); 21 | this.props.fetchRepos(); 22 | } 23 | 24 | render() { 25 | return ( 26 | <div> 27 | <ul> 28 | { 29 | this.props.members.map((member) => 30 | <MemberListItem key={member.id} member={member} /> 31 | ) 32 | } 33 | </ul> 34 | <br/> 35 | <ul> 36 | { 37 | this.props.repos.map((repo) => 38 | <RepoListItem key={repo.id} repo={repo} /> 39 | ) 40 | } 41 | </ul> 42 | </div> 43 | ); 44 | } 45 | } 46 | 47 | OrganizationComponent.propTypes = { 48 | members : PropTypes.array.isRequired, 49 | fetchMembers : PropTypes.func.isRequired, 50 | repos : PropTypes.array.isRequired, 51 | fetchRepos : PropTypes.func.isRequired, 52 | } -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/organization/container.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { lifecycle, compose } from 'recompose'; 4 | import { OrganizationComponent } from './component' 5 | import { loadMembersRequest, loadReposRequest } from './actions'; 6 | 7 | const mapStateToProps = (state) => ({ 8 | members: state.organization, 9 | repos: state.repo, 10 | }); 11 | 12 | const mapDispatchToProps = (dispatch) => ({ 13 | fetchMembers: () => dispatch(loadMembersRequest()), 14 | fetchRepos: () => dispatch(loadReposRequest()) 15 | }); 16 | 17 | // #3 18 | // //Should be imported 19 | // const Loader = () => <div>Loading</div>; 20 | 21 | // const showLoader = (test) => branch( 22 | // test, 23 | // renderComponent(Loader) 24 | // ); 25 | 26 | export const OrganizationContainer = compose( 27 | connect(mapStateToProps, mapDispatchToProps), 28 | //#2 29 | lifecycle({ 30 | componentDidMount() { 31 | this.props.fetchMembers(); 32 | this.props.fetchRepos(); 33 | } 34 | }), 35 | //#3 Wait till props have values 36 | // showLoader((props) => !props.members.length || !props.repos.length) 37 | )(OrganizationComponent); 38 | 39 | export default OrganizationContainer; 40 | -------------------------------------------------------------------------------- /05 OwnProps/src/pods/organization/container.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { OrganizationComponent } from './component' 4 | import { loadMembersRequest } from './actions'; 5 | 6 | 7 | // Temporary container once we add redux support we will remove it 8 | export class OrganizationContainer extends Component { 9 | constructor(props) { 10 | super(props); 11 | 12 | this.state = { 13 | repos: [], 14 | } 15 | } 16 | 17 | fetchRepos = () => { 18 | this.setState({ 19 | repos: [ 20 | {id: 1, name: "my fake repo A"}, 21 | {id: 2, name: "my fake repo B"}, 22 | ], 23 | }); 24 | } 25 | 26 | render = () => 27 | <InnerOrganizationContainer repos={this.state.repos} fetchRepos={this.fetchRepos}/> 28 | } 29 | 30 | export default OrganizationContainer; 31 | 32 | const mapStateToProps = (state, ownProps) => ({ 33 | ...ownProps, 34 | members: state.organization, 35 | }); 36 | 37 | const mapDispatchToProps = (dispatch) => ({ 38 | fetchMembers: () => dispatch(loadMembersRequest()) 39 | }) 40 | 41 | const InnerOrganizationContainer = connect(mapStateToProps, 42 | mapDispatchToProps, 43 | )(OrganizationComponent); 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /06 Recompose FComponents/src/pods/organization/component.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import {openable} from "../recompose-demo/openable"; 4 | 5 | // const MemberListItem = ({member}) => ( 6 | // <li> 7 | // <img src={member.avatar_url} width={30} height={30}/> 8 | // <span>{member.login}</span> 9 | // </li> 10 | // ); 11 | 12 | //TODO WJ: Talk about this if time available 13 | const MemberListItem = openable(({isOpen, toggleOpen, member}) => ( 14 | <li key={member.login}> 15 | <img src={member.avatar_url} width={30} height={30}/> 16 | 17 | <div> 18 | <span onClick={toggleOpen}>{member.login}</span> 19 | {isOpen && ( 20 | <div>{member.description}</div> 21 | )} 22 | </div> 23 | </li> 24 | )); 25 | 26 | const RepoListItem = ({repo}) => ( 27 | <li> 28 | <span>{repo.name}</span> 29 | </li> 30 | ); 31 | 32 | const memberToListItem = (member) => <MemberListItem key={member.id} member={member} />; 33 | const repoToListItem = (repo) => <RepoListItem key={repo.id} repo={repo} />; 34 | 35 | export const OrganizationComponent = ({members, repos}) => ( 36 | <div className={'organization'}> 37 | <ul className={'card'}> 38 | {members.map(memberToListItem)} 39 | </ul> 40 | <br/> 41 | <ul className={'card'}> 42 | {repos.map(repoToListItem)} 43 | </ul> 44 | </div> 45 | ); 46 | 47 | OrganizationComponent.propTypes = { 48 | members : PropTypes.array.isRequired, 49 | repos : PropTypes.array.isRequired, 50 | }; 51 | -------------------------------------------------------------------------------- /04 Redux/public/index.html: -------------------------------------------------------------------------------- 1 | <!doctype html> 2 | <html lang="en"> 3 | <head> 4 | <meta charset="utf-8"> 5 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 6 | <meta name="theme-color" content="#000000"> 7 | <!-- 8 | manifest.json provides metadata used when your web app is added to the 9 | homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ 10 | --> 11 | <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> 12 | <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> 13 | <!-- 14 | Notice the use of %PUBLIC_URL% in the tags above. 15 | It will be replaced with the URL of the `public` folder during the build. 16 | Only files inside the `public` folder can be referenced from the HTML. 17 | 18 | Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will 19 | work correctly both with client-side routing and a non-root public URL. 20 | Learn how to configure a non-root public URL by running `npm run build`. 21 | --> 22 | <title>React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /00 Boilerplate/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /01 Services/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /05 OwnProps/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /06 Recompose FComponents/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /01 Services/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /04 Redux/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /05 OwnProps/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /00 Boilerplate/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /05 OwnProps/README.md: -------------------------------------------------------------------------------- 1 | # Sample scope 2 | 3 | Now that we have introduced redux, we realized we have to add a new feature to our component, but we want to focus first on UI, api calls rather than start with 4 | the whole React / Redux plumbing. 5 | 6 | What can we do? We will: 7 | 8 | - Rename OrganizationContainer to InnerOrganization. 9 | - Create a wrapper component that will contain the mocked entry, and that will instantiate InnerOrganizationContainer. 10 | - Pass the new properties via OwnProps. 11 | - Update the component. 12 | - Are we done? Time to add redux support... (next sample) 13 | 14 | 15 | # Steps 16 | 17 | - Let's start by renaming our _OrganizationContainer_ to _InnerOrganizationContainer_ and remove the _export_ keyword 18 | 19 | ```diff 20 | 21 | - export const OrganizationContainer = connect(mapStateToProps, 22 | + export const InnerOrganizationContainer = connect(mapStateToProps, 23 | mapDispatchToProps, 24 | )(OrganizationComponent); 25 | 26 | - export default OrganizationContainer; 27 | ``` 28 | 29 | - Now let's add a temporary container, we will call it _OrganizationContainer_ 30 | 31 | _./src/pods/organization/container_ 32 | 33 | ```javascript 34 | // Temporary container once we add redux support we will remove it 35 | export class OrganizationContainer extends Component { 36 | constructor(props) { 37 | super(props); 38 | 39 | this.state = { 40 | repos: [], 41 | } 42 | } 43 | 44 | fetchRepos = () => { 45 | this.setState({ 46 | repos: [ 47 | {name: "my fake repo A"}, 48 | {name: "my fake repo B"}, 49 | ], 50 | }); 51 | } 52 | 53 | render() { 54 | 55 | } 56 | } 57 | ``` 58 | 59 | 60 | 61 | - Now we can inject the property to the _innerOrganizationComponent_ via own props. 62 | 63 | _./src/pods/organization/container.js_ 64 | ```diff 65 | export default OrganizationContainer; 66 | 67 | - const mapStateToProps = (state) => ({ 68 | + const mapStateToProps = (state, ownProps) => ({ 69 | + ...ownProps 70 | members: state.organization, 71 | }); 72 | 73 | ``` 74 | 75 | - Now let's go the Organization presentational component and add the new property and call back: 76 | 77 | _./src/pods/organization/component.js_ 78 | 79 | ```diff 80 | OrganizationComponent.propTypes = { 81 | members : PropTypes.array.isRequired, 82 | fetchMembers : PropTypes.func.isRequired, 83 | + repos : PropTypes.array.isRequired, 84 | + fetchRepos : PropTypes.func.isRequired, 85 | } 86 | ``` 87 | 88 | - Let's call _fetchRepos_ on the _ComponentDidMount_ as we did with _fetchMembers()_ 89 | 90 | 91 | _./src/pods/organization/component.js_ 92 | 93 | ```diff 94 | componentDidMount() { 95 | this.props.fetchMembers(); 96 | + this.props.fetchRepos(); 97 | } 98 | ``` 99 | 100 | - Let's add a _RepoListItem_ simple component 101 | 102 | _./src/pods/organization/component.js_ 103 | 104 | ```javascript 105 | const RepoListItem = ({repo}) => ( 106 |
  • 107 | {repo.name} 108 |
  • 109 | ); 110 | ``` 111 | 112 | - Finally let's create a new unordered list and display the list of repos. 113 | 114 | _./src/pods/organization/component.js_ 115 | 116 | ```diff 117 | export class OrganizationComponent extends Component { 118 | 119 | componentDidMount() { 120 | this.props.fetchMembers(); 121 | } 122 | 123 | render() { 124 | return ( 125 | +
    126 |
      127 | { 128 | this.props.members.map((member) => 129 | 130 | ) 131 | } 132 |
    133 | +
    134 | +
      135 | + { 136 | + this.props.repos.map((repo) => 137 | + 138 | + ) 139 | + } 140 | +
    141 | +
    142 | ); 143 | } 144 | } 145 | 146 | ``` 147 | -------------------------------------------------------------------------------- /01 Services/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /04 Redux/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /05 OwnProps/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /00 Boilerplate/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /03 ReactApp_Rest/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /02 ReactApp_Mocked/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /06 Recompose FComponents/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (!isLocalhost) { 36 | // Is not local host. Just register service worker 37 | registerValidSW(swUrl); 38 | } else { 39 | // This is running on localhost. Lets check if a service worker still exists or not. 40 | checkValidServiceWorker(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /06 Recompose FComponents/README.md: -------------------------------------------------------------------------------- 1 | # Sample scope 2 | 3 | We assume that Functional Components are best components - hence we want to change our Class to function. 4 | 5 | *src/pods/organization/component.js* 6 | ```diff 7 | - export class OrganizationComponent extends Component { 8 | 9 | - componentDidMount() { 10 | - this.props.fetchMembers(); 11 | - this.props.fetchRepos(); 12 | - } 13 | - 14 | - render() { 15 | - return ( 16 | -
    17 | -
      18 | - { 19 | - this.props.members.map((member) => 20 | - 21 | - ) 22 | - } 23 | -
    24 | -
    25 | -
      26 | - { 27 | - this.props.repos.map((repo) => 28 | - 29 | - ) 30 | - } 31 | -
    32 | -
    33 | - ); 34 | - } 35 | - } 36 | 37 | + const Organization = ({members, repos}) => ( 38 | +
    39 | +
      40 | + { 41 | + members.map((member) => 42 | + 43 | + ) 44 | + } 45 | +
    46 | +
    47 | +
      48 | + { 49 | + repos.map((repo) => 50 | + 51 | + ) 52 | + } 53 | +
    54 | +
    55 | + ); 56 | ``` 57 | 58 | 59 | This way we have FC but no longer have `componentDidMount` hook. 60 | 61 | So in *pods/organization/container.js* 62 | 63 | We change 64 | 65 | ```diff javascript 66 | + import {compose, lifecycle} from 'recompose' 67 | 68 | - export const OrganizationContainer = connect(mapStateToProps, mapDispatchToProps)(OrganizationComponent); 69 | 70 | + export const OrganizationContainer = compose( 71 | + connect(mapStateToProps, mapDispatchToProps), 72 | + lifecycle({ 73 | + componentDidMount() { 74 | + this.props.fetchMembers(); 75 | + this.props.fetchRepos(); 76 | + } 77 | + }), 78 | + )(OrganizationComponent); 79 | ``` 80 | 81 | Attaching lifecycle hoc with our expected `componentDidMount` hook. To the container, making the container logic for fetching data separate from our component ui logic. 82 | 83 | If we wanted additionally to add loaded while there are pending fetches we could write code like this 84 | 85 | ```javascript 86 | //components/showLoader.js 87 | const Loader = () =>
    Loading
    ; 88 | 89 | const showLoader = (test) => branch( 90 | test, 91 | renderComponent(Loader) 92 | ); 93 | 94 | ``` 95 | 96 | With usage: 97 | ```javascript 98 | export const OrganizationContainer = compose( 99 | connect(mapStateToProps, mapDispatchToProps), 100 | lifecycle({ 101 | componentDidMount() { 102 | this.props.fetchMembers(); 103 | this.props.fetchRepos(); 104 | } 105 | }), 106 | )(OrganizationComponent); 107 | ``` 108 | 109 | ------------------ 110 | 111 | We have just improved the example with removal of hooks methods from ui component. But What if you had inner state to manage. 112 | 113 | `recompose` has also hoc for that `withState` and `withStateHandler`. 114 | 115 | ```typescript 116 | declare function withState ( 117 | stateName: string, 118 | stateUpdaterName: string, 119 | initialState: any | (props: Object) => any 120 | ): HigherOrderComponent 121 | ``` 122 | 123 | Which is shown in example *pods\recompose-demo\cardExampleRecompose.js* That is the result of refactoring with recompose *pods\recompose-demo\cardExample.js* 124 | 125 | ```javascript 126 | import * as React from "react"; 127 | import {withState} from "recompose"; 128 | 129 | const TitledCard = ({isOpen, setOpen, title, text}) => ( 130 | 131 | setOpen(!isOpen)} title={title}/> 132 | <Body isOpen={isOpen}>{text}</Body> 133 | </Card> 134 | ); 135 | 136 | export default withState("isOpen", "setOpen", false)(TitledCard) 137 | ``` 138 | 139 | In short you pass `stateKey` that of the innerState. You pass name of the function that is setter for given field. And as a third argument initialValue. 140 | 141 | 142 | If you dislake creating a toggleOpen function handlers that has a logic of toggling the state we can use `withStateHandlers` 143 | 144 | ```typescript 145 | declare function withStateHandlers ( 146 | initialState: Object | (props: Object) => any, 147 | stateUpdaters: { 148 | [key: string]: (state:Object, props:Object) => (...payload: any[]) => Object 149 | } 150 | ): HigherOrderComponent 151 | ``` 152 | 153 | and create 154 | 155 | *pods\recompose-demo\openable.js* 156 | 157 | ```javascript 158 | import {withStateHandlers} from "recompose"; 159 | 160 | export const openable = withStateHandlers( 161 | // Initial state 162 | { 163 | isOpen: false, 164 | }, { 165 | // Handler creator -> {...props, ...state} 166 | toggleOpen: ({isOpen, ...restProps}) => 167 | //handler - it's result will be used to call setState of newly created hoc. 168 | () => ({ 169 | isOpen: !isOpen 170 | }), 171 | } 172 | ); 173 | ``` 174 | In this example `toggleOpen()` will mean `this.setState({isOpen: !isOpen})` 175 | 176 | Essentially allowing for 177 | 178 | ```jsx 179 | const TitledCard = ({isOpen, toggleOpen, title, text}) => ( 180 | <Card> 181 | <Title toggleOpen={toggleOpen} title={title}/> 182 | <Body isOpen={isOpen}>{text}</Body> 183 | </Card> 184 | ); 185 | 186 | export default openable(TitledCard); 187 | ``` 188 | 189 | With same result as previous solution, but more clean and composable approach. That gives you reusable 'openable' innerStateHandler, that you can use to add behavior of openClose to any component. Essentially allowing for Functional Components with InnerState. 190 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 02 React App 2 | 3 | In this sample we are going to setup a basic React application, it will: 4 | 5 | - Load a list of members belongign a team from Github. 6 | - Display it in table like format. 7 | 8 | We will take as starting point sample _01 Services_. 9 | 10 | Summary steps: 11 | 12 | - Create a _./src/pods/Organization/container_ component, 13 | . 14 | - Create a _./src/pods/Organization/OrganizationComponent_. 15 | - Instantiate this component on the _app.js_ 16 | - In componentWillMount load the data from fetch members. 17 | - Create a _membersrow_ component. 18 | - Create a _members_ component. 19 | - use in in our _./src/pods/Organization/OrganizationComponent_ 20 | 21 | # Prerequisites 22 | 23 | Ensure all the packages has been installed: 24 | 25 | ``` 26 | yarn install 27 | ``` 28 | 29 | ## Steps to build it 30 | 31 | 32 | - Create a container component 33 | 34 | _./src/pods/Organization/container.jsx_ 35 | 36 | ```javascript 37 | import React, { Component } from 'react'; 38 | 39 | export class OrganizationContainer extends Component { 40 | render() { 41 | return ( 42 | <h1>Hello from container</h1> 43 | ); 44 | } 45 | } 46 | 47 | export default OrganizationContainer; 48 | ``` 49 | 50 | - We will expose it to the app via an index file 51 | 52 | _./src/pods/organization/index.js_ 53 | ```javascript 54 | export * from './container'; 55 | ``` 56 | 57 | - Let's instantiate this container in the app.js file: 58 | 59 | _./src/App.js_ 60 | 61 | ```diff 62 | import React, { Component } from 'react'; 63 | import logo from './logo.svg'; 64 | import './App.css'; 65 | 66 | class App extends Component { 67 | render() { 68 | return ( 69 | <div className="App"> 70 | - <div className="App-header"> 71 | - <img src={logo} className="App-logo" alt="logo" /> 72 | - <h2>Welcome to React</h2> 73 | - </div> 74 | - <p className="App-intro"> 75 | - To get started, edit <code>src/App.js</code> and save to reload. 76 | - </p> 77 | </div> 78 | ); 79 | } 80 | } 81 | 82 | export default App; 83 | ``` 84 | 85 | - Let's add state to this component and add the list of members, and Create a method that will return just mock data (we will have data to 86 | build & test the child components) 87 | 88 | 89 | _./src/pods/Organization/container.jsx_ 90 | 91 | ```diff 92 | import React, { Component } from 'react'; 93 | 94 | export class OrganizationContainer extends Component { 95 | 96 | +constructor(props) { 97 | + super(props); 98 | + 99 | + this.state = { 100 | + members : [], 101 | + } 102 | +} 103 | 104 | + fetchTeamMembers() { 105 | + this.setState({ 106 | + members : [ 107 | + { 108 | + id: 1457223, 109 | + login: 'testuser1' 110 | + }, 111 | + { 112 | + id: 1852223, 113 | + login: 'testuser2' 114 | + }, 115 | + ], 116 | + }) 117 | + } 118 | 119 | render() { 120 | return ( 121 | <h1>Hello from container</h1> 122 | ); 123 | } 124 | } 125 | 126 | export default OrganizationContainer; 127 | ``` 128 | 129 | - In the child component let's consume this method and a property to hold the 130 | members array. 131 | 132 | ```javascript 133 | import React, { Component } from 'react'; 134 | import PropTypes from 'prop-types'; 135 | 136 | export class OrganizationComponent extends Component { 137 | 138 | render() { 139 | return ( 140 | <h3>Hello from component</h3> 141 | ); 142 | } 143 | } 144 | 145 | OrganizationComponent.propTypes = { 146 | members : PropTypes.array.isRequired, 147 | fetchMembers : PropTypes.func.isRequired, 148 | } 149 | ``` 150 | 151 | 152 | - Let's tie them together. 153 | 154 | ```javascript 155 | import React, { Component } from 'react'; 156 | +import { OrganizationComponent } from './component' 157 | 158 | export class OrganizationContainer extends Component { 159 | 160 | //... 161 | 162 | render() { 163 | return ( 164 | + <OrganizationComponent 165 | + members={this.state.members} 166 | + fetchMembers={this.fetchTeamMembers} 167 | + /> 168 | ); 169 | } 170 | } 171 | 172 | export default OrganizationContainer; 173 | ``` 174 | 175 | - Now our child component will hook to componenDidMount and make the call 176 | to load the members list, then render it (simple ul/li). 177 | 178 | ```diff 179 | import React, { Component } from 'react'; 180 | import PropTypes from 'prop-types'; 181 | 182 | export class OrganizationComponent extends Component { 183 | 184 | + componentDidMount() { 185 | + this.props.fetchMembers(); 186 | + } 187 | 188 | render() { 189 | return ( 190 | - <h3>Hello from component</h3> 191 | + <ul> 192 | + { 193 | + this.props.members.map((member) => 194 | + <li key={member.id}> 195 | + <span>{member.login}</span> 196 | + </li> 197 | + ) 198 | + } 199 | + </ul> 200 | ); 201 | } 202 | } 203 | 204 | OrganizationComponent.propTypes = { 205 | members : PropTypes.array.isRequired, 206 | fetchMembers : PropTypes.func.isRequired, 207 | } 208 | ``` 209 | - Cool, we can just see how the component behave using mock data, why not using real data? We only 210 | need to update the container, children components won't need any change. 211 | 212 | ```diff 213 | import React, { Component } from 'react'; 214 | import { OrganizationComponent } from './component' 215 | + import { fetchMembers } from '../../rest-api' 216 | 217 | export class OrganizationContainer extends Component { 218 | 219 | constructor(props) { 220 | super(props); 221 | 222 | this.state = { 223 | members : [], 224 | } 225 | } 226 | 227 | fetchTeamMembers = () => { 228 | - this.setState({ 229 | - members : [ 230 | - { 231 | - id: 1457223, 232 | - login: 'testuser1' 233 | - }, 234 | - { 235 | - id: 1852223, 236 | - login: 'testuser2' 237 | - }, 238 | - ], 239 | - }) 240 | 241 | + fetchTeamMembers = () => { 242 | + fetchMembers().then((members) => 243 | + this.setState({ 244 | + members: members, 245 | + }) 246 | + ); 247 | } 248 | 249 | 250 | } 251 | 252 | render() { 253 | return ( 254 | <OrganizationComponent 255 | members={this.state.members} 256 | fetchMembers={this.fetchTeamMembers} 257 | /> 258 | ); 259 | } 260 | } 261 | 262 | export default OrganizationContainer; 263 | ``` 264 | 265 | ## Next step 266 | 267 | Now that we have our simple react build, let's see how easy is to integrate it 268 | with redux. 269 | 270 | 271 | --------------------------------------------------------------------------------