├── .editorconfig ├── .env.development ├── .env.production ├── .eslintignore ├── .eslintrc.js ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.VN.md ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json ├── server.js ├── server └── routes │ └── index.js ├── src ├── actions │ ├── action-types.js │ └── index.js ├── components │ ├── common │ │ └── loading │ │ │ ├── Loading.jsx │ │ │ └── Loading.scss │ ├── layout │ │ ├── App.jsx │ │ ├── App.scss │ │ ├── App.test.js │ │ ├── body │ │ │ ├── Body.jsx │ │ │ └── Body.scss │ │ ├── footer │ │ │ ├── Footer.jsx │ │ │ └── Footer.scss │ │ └── header │ │ │ ├── Header.jsx │ │ │ └── Header.scss │ └── pages │ │ ├── demo-animate-css │ │ ├── DemoAnimateCss.jsx │ │ └── DemoAnimateCss.scss │ │ ├── demo-bootstrap │ │ └── DemoBootstrap.jsx │ │ ├── demo-jquery │ │ ├── DemoJquery.jsx │ │ └── DemoJquery.scss │ │ ├── demo-loadable-component │ │ ├── DemoLoadableComponent.jsx │ │ └── LoadableDemoComponent.jsx │ │ ├── demo-react-reveal │ │ └── DemoReactReveal.jsx │ │ ├── demo-react-router │ │ ├── DemoReactRouter.jsx │ │ ├── Images.jsx │ │ ├── LoadableImage.jsx │ │ ├── Text.jsx │ │ ├── UserList.jsx │ │ └── UserProfile.jsx │ │ ├── demo-react-scrollchor │ │ ├── DemoReactScrollchor.jsx │ │ └── DemoReactScrollchor.scss │ │ ├── demo-react-table │ │ ├── DemoReactTable.jsx │ │ ├── ModalEditTodo.jsx │ │ └── style.scss │ │ ├── demo-reactstrap │ │ └── DemoReactstrap.jsx │ │ ├── demo-redux │ │ ├── DemoRedux.jsx │ │ ├── FormAddItem.jsx │ │ └── ItemTable.jsx │ │ └── lifecycle-component.jsx ├── environments │ ├── env.development.js │ ├── env.production.js │ └── index.js ├── index.js ├── lib │ ├── animate.css.js │ ├── bootstrap.js │ ├── font-awesome.js │ ├── index.js │ └── jquery.js ├── reducers │ ├── index.js │ ├── items.js │ ├── todos.js │ └── users.js ├── registerServiceWorker.js ├── services │ ├── auth-service.js │ ├── db-service.js │ └── util-service.js └── styles │ ├── _animate.scss │ ├── _classes.scss │ ├── _mixins.scss │ ├── _variables.scss │ └── index.scss ├── test.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # Howto with your editor: http://editorconfig.org/#download 4 | # Sublime: https://github.com/sindresorhus/editorconfig-sublime 5 | 6 | # top-most EditorConfig file 7 | root = true 8 | 9 | # Unix-style newlines with a newline ending every file 10 | [**] 11 | end_of_line = lf 12 | insert_final_newline = true 13 | 14 | # Standard at: https://github.com/felixge/node-style-guide 15 | [**.{js,json,jsx}] 16 | trim_trailing_whitespace = true 17 | indent_style = space 18 | indent_size = 2 19 | quote_type = single 20 | curly_bracket_next_line = false 21 | spaces_around_operators = true 22 | space_after_control_statements = true 23 | space_after_anonymous_functions = true 24 | spaces_in_brackets = false 25 | 26 | # No Standard. Please document a standard if different from .js 27 | [**.{yml,css,scss}] 28 | trim_trailing_whitespace = true 29 | indent_style = tab 30 | indent_size = 2 31 | 32 | [**.html] 33 | trim_trailing_whitespace = true 34 | indent_style = space 35 | indent_size = 2 36 | 37 | # No standard. Please document a standard if different from .js 38 | [**.md] 39 | indent_style = tab 40 | 41 | # Standard at: 42 | [Makefile] 43 | indent_style = tab 44 | 45 | # The indentation in package.json will always need to be 2 spaces 46 | # https://github.com/npm/npm/issues/4718 47 | [{package, bower}.json] 48 | indent_style = space 49 | indent_size = 2 50 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | REACT_APP_ENV=development -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | REACT_APP_ENV=production -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | coverage/* 3 | dist/* 4 | dll/* 5 | build/* 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": [ 3 | "airbnb", 4 | "plugin:jsx-a11y/recommended" 5 | ], 6 | "parser": "babel-eslint", 7 | "parserOptions": { 8 | "ecmaVersion": 9, 9 | "sourceType": "module", 10 | "ecmaFeatures": { 11 | "experimentalObjectRestSpread": true, 12 | "allowImportExportEverywhere": true, 13 | "jsx": true 14 | } 15 | }, 16 | "plugins": [ 17 | "react", 18 | "jsx-a11y", 19 | "import" 20 | ], 21 | "env": { 22 | browser: true, 23 | node: true, 24 | node: true, 25 | es6: true, 26 | browser: true, 27 | jasmine: true, 28 | mocha: true, 29 | jquery: true 30 | }, 31 | "rules": { 32 | 'camelcase': 0, 33 | 'comma-dangle': [2, 'never'], 34 | 'comma-spacing': [2, { before: false, after: true }], 35 | 'consistent-return': 0, 36 | 'curly': 0, 37 | 'default-case': 0, 38 | 'eqeqeq': [2, 'smart'], 39 | 'func-names': 0, 40 | 'guard-for-in': 2, 41 | 'indent': [2, 2, { SwitchCase: 1 }], 42 | 'key-spacing': [2, { beforeColon: false, afterColon: true }], 43 | 'keyword-spacing': [2, { before: true, after: true }], 44 | 'max-len': 0, 45 | 'new-cap': 0, 46 | 'no-bitwise': 0, 47 | 'no-caller': 2, 48 | 'no-console': 0, 49 | 'no-else-return': 0, 50 | 'no-empty-class': 0, 51 | 'no-multi-spaces': 2, 52 | 'no-param-reassign': 0, 53 | 'no-shadow': 0, 54 | 'no-spaced-func': 2, 55 | 'no-throw-literal': 2, 56 | 'no-trailing-spaces': 2, 57 | 'no-undef': 2, 58 | 'no-unneeded-ternary': 2, 59 | 'no-unreachable': 2, 60 | 'no-underscore-dangle': 0, 61 | 'no-unused-expressions': 0, 62 | 'no-unused-vars': 0, 63 | 'no-use-before-define': [1, 'nofunc'], 64 | 'no-var': 0, 65 | 'object-curly-spacing': [2, 'always'], 66 | 'one-var': [0, 'never'], 67 | 'one-var-declaration-per-line': [2, 'always'], 68 | 'padded-blocks': 0, 69 | 'space-before-function-paren': [2, { 70 | 'anonymous': 'always', 71 | 'named': 'never', 72 | 'asyncArrow': 'always' 73 | }], 74 | 'space-in-parens': [2, 'never'], 75 | 'spaced-comment': [2, 'always'], 76 | 'strict': 0, 77 | 'quote-props': 0, 78 | 'quotes': [1, 'single'], 79 | 'wrap-iife': [2, 'outside'], 80 | 'vars-on-top': 0, 81 | 'global-require': 0, 82 | 'no-plusplus': 0, 83 | 'eqeqeq': 0, 84 | 'no-case-declarations': 0, 85 | 'class-methods-use-this': 0, 86 | 'prefer-destructuring': 0, 87 | 'no-alert': 0, 88 | 'no-mixed-operators': 0, 89 | 'object-property-newline': 0, 90 | 'no-nested-ternary': 0, 91 | // import plugin 92 | 'import/no-mutable-exports': 0, 93 | 'import/extensions': 0, 94 | 'import/first': 0, 95 | 'import/no-named-as-default': 0, 96 | // react plugin 97 | 'react/jsx-filename-extension': [1, { "extensions": [".js", ".jsx"] }], 98 | 'react/prefer-stateless-function': 0, 99 | 'react/forbid-prop-types': 0, 100 | 'react/jsx-max-props-per-line': 0, 101 | // jsx-a11y plugin 102 | 'jsx-a11y/href-no-hash': 0, 103 | 'jsx-a11y/anchor-is-valid': 0, 104 | 'jsx-a11y/img-redundant-alt': 0, 105 | 'jsx-a11y/label-has-for': 0 106 | }, 107 | 'globals': { 108 | by: true, 109 | browser: true, 110 | element: true, 111 | inject: true, 112 | io: true, 113 | moment: true, 114 | Modernizr: true, 115 | Promise: true, 116 | __TESTING__: true, 117 | _: false, 118 | ApplicationConfiguration: true 119 | } 120 | }; 121 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ### Code of conduct 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Expected behavior 2 | 3 | 4 | ### Actual behavior 5 | 6 | 7 | ### Steps to reproduce the behavior 8 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Your checklist for this pull request 2 | 3 | ### Description 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # production 61 | /build 62 | /dist 63 | 64 | # misc 65 | .DS_Store 66 | .env.local 67 | .env.development.local 68 | .env.test.local 69 | .env.production.local 70 | 71 | npm-debug.log* 72 | yarn-debug.log* 73 | yarn-error.log* 74 | 75 | # auto generated files (sass, less, ...) 76 | src/**/*.css -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 node-oracle-sql 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 | -------------------------------------------------------------------------------- /README.VN.md: -------------------------------------------------------------------------------- 1 | # react-configure 2 | 3 | Chào mọi người, đây là bài viết chia sẻ kinh nghiệm của bản thân mình khi tìm hiểu về công cụ create-react-app cho việc lập trình ReactJS trở nên dễ dàng hơn. 4 | Trong bài viết này, mình sẽ nói về những điều có thể cần thiết cần phải tinh chỉnh trước khi bắt đầu 1 dự án React của các bạn, cụ thể là sử dụng [create-react-app](https://github.com/facebook/create-react-app) với các thư viện [redux](https://redux.js.org/docs/basics/UsageWithReact.html), 5 | react-redux, 6 | redux-thunk, 7 | react-router, 8 | react-router-dom, 9 | sass, 10 | code spliting, 11 | jQuery, 12 | bootstrap, 13 | react-loadable, 14 | react-scrollchor, 15 | react-intl, 16 | react-select, 17 | react-datepicker, 18 | react-table, 19 | moment, 20 | ... 21 | 22 | 23 | Đây là demo về 1 số phần mình làm: [https://huynhsamha.github.io/react-configure/](https://huynhsamha.github.io/react-configure/) 24 | 25 | 26 | 27 | 28 | - [Bắt đầu với `create-react-app`](#bắt-đầu-với-create-react-app) 29 | - [Thiết lập biến môi trường (environment variables)](#thiết-lập-biến-môi-trường-environment-variables) 30 | - [Post-Processing CSS](#post-processing-css) 31 | - [CSS Preprocessor (Sass, Less etc.)](#css-preprocessor-sass-less-etc) 32 | - [Tạo server Node.JS](#tạo-server-nodejs) 33 | - [Use `express` to initialization](#use-express-to-initialization) 34 | - [Configuration](#configuration) 35 | - [Install dependencies package](#install-dependencies-package) 36 | - [Install package `cors`](#install-package-cors) 37 | - [Start server-client](#start-server-client) 38 | - [Environment cho react app](#environment-cho-react-app) 39 | - [Cấu trúc thư mục `src` trong react app](#cấu-trúc-thư-mục-src-trong-react-app) 40 | - [Styles](#styles) 41 | - [Library and packages](#library-and-packages) 42 | - [Utility service](#utility-service) 43 | - [Reducers - Actions](#reducers---actions) 44 | - [Components](#components) 45 | - [Layout Components](#layout-components) 46 | - [Common Components](#common-components) 47 | - [Pages Components](#pages-components) 48 | - [jQuery](#jquery) 49 | - [Installation](#installation) 50 | - [How to use?](#how-to-use) 51 | - [Recommend](#recommend) 52 | - [Bootstrap 3, 4](#bootstrap-3-4) 53 | - [Sử dụng cùng với jquery](#sử-dụng-cùng-với-jquery) 54 | - [Installation](#installation-1) 55 | - [How to use?](#how-to-use-1) 56 | - [Sử dụng thông qua React Component - `reactstrap`](#sử-dụng-thông-qua-react-component---reactstrap) 57 | - [Installation and Usage](#installation-and-usage) 58 | - [Font Awesome](#font-awesome) 59 | - [Thông qua `index.html`](#thông-qua-indexhtml) 60 | - [Sử dụng npm package](#sử-dụng-npm-package) 61 | - [Animate.css](#animatecss) 62 | - [Install and configure](#install-and-configure) 63 | - [Custom duration time](#custom-duration-time) 64 | - [How to use](#how-to-use) 65 | - [Demo](#demo) 66 | - [`react-router-dom` (router)](#react-router-dom-router) 67 | - [`react-loadable` (code-splitting)](#react-loadable-code-splitting) 68 | - [Installation, Usage](#installation-usage) 69 | - [Test Loadable Components - code-splitting](#test-loadable-components---code-splitting) 70 | - [`react-intl` - API cho format date, number and string](#react-intl---api-cho-format-date-number-and-string) 71 | - [Features - các tính năng](#features---các-tính-năng) 72 | - [Document](#document) 73 | - [Usage in this tutorial](#usage-in-this-tutorial) 74 | - [Redux: `redux, react-redux, redux-thunk`](#redux-redux-react-redux-redux-thunk) 75 | - [Installation](#installation-2) 76 | - [Usage](#usage) 77 | - [Fetch Data API to server node](#fetch-data-api-to-server-node) 78 | - [Create `services` to get API](#create-services-to-get-api) 79 | - [UI Awesome with React Component](#ui-awesome-with-react-component) 80 | - [Reveal Component on scroll: use `react-reveal`](#reveal-component-on-scroll-use-react-reveal) 81 | - [Installation](#installation-3) 82 | - [Support](#support) 83 | - [Reveal with React](#reveal-with-react) 84 | - [Animated.css with React](#animatedcss-with-react) 85 | - [How to use?](#how-to-use-2) 86 | - [Scroll animted to target - react-scrollchor](#scroll-animted-to-target---react-scrollchor) 87 | - [Installation](#installation-4) 88 | - [How to use?](#how-to-use-3) 89 | - [Datatable with `react-table`](#datatable-with-react-table) 90 | - [VS Code Extensions](#vs-code-extensions) 91 | - [Icons, Colors, View](#icons-colors-view) 92 | - [Snippets](#snippets) 93 | - [Intellisence](#intellisence) 94 | - [Lint Code, Formater](#lint-code-formater) 95 | - [Edit, Preview README - Markdown files](#edit-preview-readme---markdown-files) 96 | - [VS Code User Settings](#vs-code-user-settings) 97 | 98 | 99 | 100 | 101 | 102 | # Bắt đầu với `create-react-app` 103 | Nếu bạn mới bắt đầu sử dụng react hoặc chưa biết đến create-react-app thì mình nghĩ bạn nên sử dụng thằng này để làm quen với react, vì nó đã làm sẵn mọi thứ giúp ta, ta chỉ cần làm theo những gì ta muốn với công cụ này. 104 | 105 | Trước tiên, bạn nên cài package `create-react-app` mức global từ npm . 106 | `npm install create-react-app -g` 107 | hoặc nếu bạn dùng Ubuntu hay một số hệ điều hành khác, nó yêu cầu quyền root, bạn thêm `sudo` vào trước lệnh để thực thi. 108 | 109 | 1. Tạo mới project: `create-react-app react-app` 110 | 2. `npm start` or `yarn start`: start môi trường dev. 111 | 3. `npm build` or `yarn build` build production. 112 | 113 | Trong bài này, mình sử dụng `yarn`, các bạn có thể sử dụng `npm` cũng được theo đúng cú pháp của `npm`. 114 | 115 | 116 | 117 | 118 | # Thiết lập biến môi trường (environment variables) 119 | Tạo các file lưu trữ biến môi trường, những file này theo như create-react-app nói nó sẽ nhận ra các biên được khai báo trong các file này. 120 | 121 | 1. Trong terminal tại root của project: `touch .env .env.development .env.production` 122 | 2. In `.env.development`: `REACT_APP_ENV=development` 123 | 3. In `.env.production` : `REACT_APP_ENV=production` 124 | 125 | **Note:** chỉ mầy biến với prefix là `REACT_APP_` thì thằng `create-react-app` mới hiểu và đọc được, còn sử dụng nó thì mình nói sau. 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | # Post-Processing CSS 134 | Khi viết CSS, ta thường quan tâm đến các thuộc tính hỗ trợ trên nhiều trình duyệt . Tuy nhiên `create-react-app` sẽ lo cho ta việc này, do đó ta có thể yên tâm khi viết CSS 1 cách đơn giản. 135 | Đây là lời trích từ document của react: 136 | 137 | > This project setup minifies your CSS and adds vendor prefixes to it automatically through Autoprefixer so you don’t need to worry about it. 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | # CSS Preprocessor (Sass, Less etc.) 146 | Nếu bạn nào đã dùng qua SASS , LESS, SCSS thì cũng biết sự lợi hại và tiện ích của những thằng này. Do đó nếu có thể tích hợp vào React thì khá thú vị. 147 | `create-react-app` cũng hỗ trợ ta việc này, bằng cách thực hiện các bước sau: 148 | 149 | 1. In terminal: `yarn add node-sass-chokidar npm-run-all` 150 | 2. In file `package.json`: 151 | ```json 152 | { 153 | "scripts": { 154 | - "start": "react-scripts start", 155 | - "build": "react-scripts build", 156 | + "start": "npm-run-all -p watch-css start-js", 157 | + "build": "npm-run-all build-css build-js", 158 | + "start-js": "react-scripts start", 159 | + "build-js": "react-scripts build", 160 | + "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive", 161 | + "build-css": "node-sass-chokidar src/ -o src/", 162 | } 163 | } 164 | ``` 165 | 3. In file `.gitignore`: 166 | 167 | ``` 168 | # auto generated files (sass, less, ...) 169 | src/**/*.css 170 | ``` 171 | 172 | Lúc này khi ta start lên, khi có thay đổi gì ở file sass, thì nó sẽ tự build lại các file css cho ta và browser tự động được refresh. 173 | 174 | Còn trong file .gitignore, ta thêm các file tự động sinh ra do sass để tránh gây conflict không cần thiết khi nhiều người commit. 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | # Tạo server Node.JS 185 | Nhiều lúc, ta cũng muốn sử dụng node cho thằng react :) 186 | ## Use `express` to initialization 187 | 188 | ```bash 189 | mkdir server 190 | cd server 191 | express 192 | ``` 193 | 194 | ## Configuration 195 | 196 | 1. Rename `app.js` to `server.js` 197 | 2. Join `server.js` and `./bin/www` 198 | 3. Move `server.js` to root app 199 | 4. Insert dependencies in `package.json` (which is generated by `express`) to `package.json` in root (which is generated by `create-react-app`) 200 | 5. Remove dependencies not use (`serve-favicon`, `jade`, `ejs`, etc.) 201 | 6. Remove all file in `server`, execpt `routes/index.js` 202 | 7. Correct and customize file `server.js` 203 | 204 | 205 | ## Install dependencies package 206 | 207 | `yarn` 208 | 209 | ## Install package `cors` 210 | 211 | Ta install package `cors` để cross từ port 3000 localhost tới port 4200 localhost. 212 | + `localhost:3000` (client-side, là port thằng react) 213 | + `localhost:4200` (server-side, là port của node express) 214 | 215 | `yarn add cors` 216 | 217 | ## Start server-client 218 | 219 | `yarn start` or `npm start`: start client side (react): `localhost:3000` 220 | 221 | `node server`: start server-side (node express): `localhost:4200` 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | # Environment cho react app 232 | Lúc ta phát triển (dev), ta sử dụng node ở port 4200, còn react ở port 3000, do đó để react có thể gọi request đến port 4200, ngoài sử dụng `cors` như ở trên, ta cũng cần sử dụng biên môi trường (đã thiết lập ở bước trên) để lấy dữ liệu từ server node. Ngoài ra ta cũng có thể dùng proxy (tham khảo thêm google cách này). 233 | 234 | Như đã nói ở trên, chỉ các biến `REACT_APP_` được khai báo trong các file tương ứng thì react mới biết được. Cụ thể ta dùng biến `REACT_APP_ENV` để phân biệt môi trường của server, nếu là production thì không cần phinh phức. 235 | 236 | 1. Create environment files: 237 | In your terminal: 238 | ```bash 239 | mkdir src/environments 240 | cd src/environments 241 | touch env.development.js env.production.js index.js 242 | ``` 243 | 2. Edit the files as source code. `baseUrl` is url to server. 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | # Cấu trúc thư mục `src` trong react app 252 | 253 | ## Styles 254 | Tạo thư mục `styles` trong `src/` để chứa các biến variables, mixins, classes, common styles, or theme, etc. cho app react: 255 | + `_variables.scss`: khai báo các variables . 256 | + `_mixins.scss`: khai báo các mixins (dùng sass hoặc less) 257 | + `_classes.scss`: khai báo 1 số class hữu ích. 258 | + `index.scss`: import các file `_` vào file này, để file `index.scss` ở ngoài thư thư mục tương ứng, còn trong file `index.js`, ta import style này vào `./styles/index.css` 259 | + Nếu app của bạn sử dụng theme (như AdminLTE, Bootstrap, Material, Angular, Datatables, Charts, ...), ta ghi đề những style cần với file prefix là `_` và import vô `index.scss` 260 | 261 | ## Library and packages 262 | Trong thư mục `src`, ta tạo thư mục `lib` để chứa các thư viện và package ta dùng trong app, chẳng hạn như jQuery, Bootstrap, Font-Awesome, Ionicons, Material, ... 263 | + Tạo file `index.js` trong `lib` để import các file trong thư mục này 264 | + Trong file `index.js` ngoài thư mục app của ta, ta import thư mục `lib` vừa tạo chỉ bằng dòng `import './lib';` 265 | 266 | 267 | ## Utility service 268 | Ta cũng tạo thư mục `services` để chứa các tiện ích của app. Việc triển khai thư mục này ta sẽ bàn sau. 269 | 270 | ## Reducers - Actions 271 | Nếu ta sử dụng `redux`, ta cũng cần tạo 2 thư mục `actions` và `reducers`. Cụ thể triển khai ta sẽ bàn sau. 272 | 273 | ## Components 274 | Ta tạo `components` để chứa các components của app, trong đó ta chia ra thành: 275 | 276 | ### Layout Components 277 | Tạo thư mục `layout` để chứa luồng thực thi của app. Trong `layout` ta tạo hai file `App.js` và `App.scss`, ngoài ra còn chứa các thư mục `Header`, `Footer`, `Sidebar`, `Menu`, `Body` tương ứng cho việc điều hướng app. 278 | 279 | 280 | ### Common Components 281 | Ta tạo `common` để chứa các components dùng chung được sử dụng nhiều lần như `Loading`, `Modal`, `Alert`, `Notification`, `Box`, ... 282 | 283 | ### Pages Components 284 | Tạo `pages` để chứa các trang của 1 single page app, như `Home`, `Dashboard`, `Profile`, `Form`, `Terms of Service`, `Support`, `Page not found`, `Error page`,.. 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | # jQuery 293 | 294 | ## Installation 295 | 1. In terminal: `yarn add jquery` 296 | 2. In terminal: `touch src/lib/jquery.js`: tạo file jquery config 297 | 3. COnfig file này như sau: 298 | 299 | ```js 300 | import $ from 'jquery'; 301 | 302 | // config jquery variables for other lib use jQuery (such as bootstrap) 303 | window.$ = $; 304 | window.jQuery = $; 305 | ``` 306 | 307 | ## How to use? 308 | 1. In `lib/index.js`, import by: `import './jquery';` 309 | 2. In `index.js` at ngoài app, `import './lib';` (nếu như bạn chưa import). 310 | 3. Trong mỗi component, để sử dungj jquery mà react không báo lỗi, ta cần import: `import $ from 'jquery';` 311 | 4. jquery chỉ sử dụng kể từ `componentDidMount()` trong vòng đời của 1 component react: 312 | 5. [View Demo here](https://huynhsamha.github.io/react-configure/jquery) 313 | 6. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-jquery/DemoJquery.jsx) 314 | 315 | 316 | ```javascript 317 | componentDidMount() { 318 | // jQuery should declare at here 319 | $(document).ready(() => { 320 | $('#alert').click(() => alert('This is alert be jQuery')); 321 | }); 322 | } 323 | ``` 324 | 325 | 326 | ## Recommend 327 | Chỉ nên dùng jquery khi thực sự cần thiết. vì react đã hỗ trợ khá đủ. 328 | 329 | 330 | 331 | 332 | 333 | 334 | # Bootstrap 3, 4 335 | 336 | 337 | ## Sử dụng cùng với jquery 338 | ### Installation 339 | 1. In terminal: `yarn add bootstrap` (thêm @version cho version bạn sử dụng) 340 | 2. In terminal: `mkdir src/lib` (nếu đã tạo thì bỏ qua) 341 | 3. In terminal: `touch src/lib/bootstrap.js` 342 | 4. Cấu hình file này như sau (mình đang dùng bootstrap 4): 343 | 344 | ```javascript 345 | import 'bootstrap/dist/css/bootstrap.min.css'; 346 | import 'bootstrap/dist/js/bootstrap.bundle.min.js'; 347 | ``` 348 | 349 | ### How to use? 350 | 1. In `lib/index.js`, import by: `import './bootstrap';` 351 | 2. In `index.js` at root, `import './lib';` (if you don't have). 352 | 3. Trong component, ta có thể sử dụng bootstrap 3, 4 như document của bootstrap. 353 | 4. View demo with component `DemoBootstrap`. 354 | 5. [View Demo here](https://huynhsamha.github.io/react-configure/bootstrap) 355 | 6. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-bootstrap/DemoBootstrap.jsx) 356 | 357 | 358 | 359 | 360 | ## Sử dụng thông qua React Component - `reactstrap` 361 | `reactstrap` là một package react cho bootstrap, tương đối ổn so với bootstrap nhưng không phải là hoàn thiện. 362 | Bạn có thể google package này để xem qua doc của nó. 363 | 364 | Cũng có nhiều framework khác cho react, xây dụng sẵn các component cần thiết cho react, bạn có thể google các framewro hoặc package tương ứng. 365 | 366 | ### Installation and Usage 367 | 1. In terminal: `yarn add reactstrap@next` 368 | 2. Only import Component to use as reactstrap document 369 | 3. View demo with component `DemoReactstrap`. 370 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/reactstrap) 371 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-reactstrap/DemoReactstrap.jsx) 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | # Font Awesome 381 | ## Thông qua `index.html` 382 | Ta có thể include trực tiếp thông qua `index/html` bằng cdn, hoặc download rồi include vào. 383 | 384 | ## Sử dụng npm package 385 | 386 | 1. In terminal: `yarn add font-awesome` 387 | 2. Create file `lib/font-awesome.js` and add line `import 'font-awesome/css/font-awesome.min.css';` 388 | 3. In `lib/index.js`, import by: `import './font-awesome';` 389 | 4. In `index.js` at root, `import './lib';` (if you don't have). 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | # Animate.css 399 | ## Install and configure 400 | 1. `yarn add animate.css` 401 | 2. In `lib/` tạo `animate-css.js` và thêm `import 'animate.css';` 402 | 3. In `index.js`, import bằng `import './animate-css';` 403 | 404 | ## Custom duration time 405 | 1. Tùy chỉnh thời gian animation bằng scss config trong `style/`: 406 | 2. Tạo file `_animate.scss` như source code 407 | 3. In `index.scss`: `@import './animate.scss';` 408 | 4. File này sẽ tạo ra các class sau: 409 | ``` 410 | .animated.duration-100 411 | .animated.duration-200 412 | ... 413 | .animated.duration-1100 414 | .animated.duration-1200 415 | ... 416 | .animated.duration-3000 417 | ``` 418 | 419 | ## How to use 420 | Example: 421 | ```html 422 | 423 |
ABCDEFGHIJKLMNOP
424 |
ABCDEFGHIJKLMNOP
425 |
ABCDEFGHIJKLMNOP
426 | 427 |
ABCDEFGHIJKLMNOP
428 |
ABCDEFGHIJKLMNOP
429 |
ABCDEFGHIJKLMNOP
430 | 431 |
ABCDEFGHIJKLMNOP
432 |
ABCDEFGHIJKLMNOP
433 | ``` 434 | 435 | 436 | ## Demo 437 | + View demo at component `DemoAnimateCss` 438 | + [View Demo here](https://huynhsamha.github.io/react-configure/animate-css) 439 | + [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-animate-css/DemoAnimateCss.jsx) 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | # `react-router-dom` (router) 449 | `react-router-dom` được sử dụng cho 1 Single Page Application (SPA). 450 | 451 | 1. In terminal: `yarn add react-router-dom` 452 | 2. Bạn xem implement trong `components/layout/body` 453 | 3. Cũng có thể xem ở `components/pages/demo-react-router` 454 | 4. Documents is available at [React Router Dom](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-dom) 455 | 456 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/react-router) 457 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-router/DemoReactRouter.jsx) 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | # `react-loadable` (code-splitting) 466 | `code-splitting` là một kỹ thuật tăng tốc độ của single page app. Nó sẽ lazy loading, tức chờ cho điến khi người dùng click vào component đó nó mới thực sự load component đó lên. Điều này giúp ứng dụng của ta load nhanh ở lần chạy đầu tiên khi người dùng chưa cần vào các component này. 467 | 468 | create-react-app cũng hỗ trợ ta trong việc code-splitting, do đó ta không nên bỏ qua kỹ thuật này, 469 | ## Installation, Usage 470 | 471 | `react-loadable` hỗ trợ code-splitting: 472 | + `create-react-app` sẽ bundle script file mới, khi được gọi, nó mới load file này. 473 | 474 | 1. In terminal: `yarn add react-loadable react-router-dom` 475 | 2. Tạo 1 Loading component (view components/common/loading/) 476 | 3. Khi sử dụng Loadable với loading component, các thuộc tính cần quan tâm cho component này: 477 | `{ isLoading: true, pastDelay: false, timedOut: false, error: null }` 478 | 4. View `components/page/demo-loadable-component` to sample implement. 479 | 5. Component `DemoLoadableComponent` (is not loadable) and `LoadableDemoComponent` (is loadable) 480 | 481 | ## Test Loadable Components - code-splitting 482 | 1. Inspect element trong trình duyệt 483 | 2. Chọn tab network 484 | 3. Click filter JS 485 | 4. Refresh page 486 | 5. lúc đầu chỉ thấy file `bundle.js` và 1 số file js khác. 487 | 6. Click component hỗ trợ loadable, ta sẽ thấy `*.chunk.js` is loaded. Đây là lazy loading component 488 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/react-loadable) 489 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-router/DemoReactRouter.jsx) 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | # `react-intl` - API cho format date, number and string 500 | Internationalize React apps. Thư viện này cung cấp các React components and API để format dates, numbers, and strings, bao gồm pluralization (số nhiều) và handling translations (chuyến đổi). 501 | 502 | ## Features - các tính năng 503 | + Display numbers with separators. 504 | + Display dates and times correctly. 505 | + Display dates relative to "now". 506 | + Pluralize labels in strings. 507 | + Support for 150+ languages. 508 | + Runs in the browser and Node.js. 509 | + Built on standards. 510 | 511 | ## Document 512 | You can view document at here: [https://github.com/yahoo/react-intl](https://github.com/yahoo/react-intl) 513 | 514 | 515 | ## Usage in this tutorial 516 | 1. In `index.js`, ta import và dùng provider cho App component: 517 | 518 | ```jsx 519 | import { IntlProvider } from 'react-intl'; 520 | 521 | ReactDOM.render( 522 | 523 | 524 | 525 | 526 | 527 | , 528 | 529 | document.getElementById('root') 530 | ); 531 | ``` 532 | 533 | 2. Trong từng component, ta import component of `react-intl` để sử dụng. Bạn có thể xem demo sử dụng ở demo phần redux. 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | # Redux: `redux, react-redux, redux-thunk` 544 | Redux là 1 kỹ thuật ta không thể bỏ qua khi làm việc với react. 545 | ## Installation 546 | `yarn add redux react-redux redux-thunk` 547 | 548 | ## Usage 549 | 1. In `src`, tạo: 550 | + `actions/action-types.js`: định nghĩa tên action 551 | + `actions/index.js`: định nghĩa các action 552 | + `reducers/`: khai báo các reducer 553 | + `reducers/[name].js`: định nghĩa các action cụ thể. 554 | + `reducers/index.js`: combine các reducer của redux, sau đó sẽ được createStore. 555 | 556 | 2. In `index.js`: 557 | + `import { Provider } from 'react-redux';`: dùng Provider để store redux 558 | + `import { createStore, applyMiddleware } from 'redux';`: dùng createStore và middleware `thunk` cho createStore 559 | + `import thunk from 'redux-thunk';`: middleware cho createStore, support async function 560 | + `import allReducers from './reducers';`: reducers sau khi combined 561 | + `const store = createStore(allReducers, applyMiddleware(thunk));`: createStore với combined reducer, và apply middleware thunk 562 | + Hiện tại bạn không cần quan tâm reducers `Users`, ta sẽ sử dụng cái này sau. 563 | 564 | 3. In `reducers/index.js`: combine reducers: 565 | + In this tutorial, I demo with Items and Users (users is used for other section demo). 566 | ```js 567 | import { combineReducers } from 'redux'; 568 | 569 | import Items from './items'; 570 | import Users from './users'; 571 | 572 | const reducers = combineReducers({ 573 | Items, 574 | Users 575 | }); 576 | 577 | export default reducers; 578 | ``` 579 | 580 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/redux) 581 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-redux/DemoRedux.jsx) 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | # Fetch Data API to server node 597 | ## Create `services` to get API 598 | 1. `mkdir src/services` (if you have not) 599 | 2. `touch db-service.js auth-service.js` (db- to get database, auth- to authentication user) 600 | 3. Example with `db-service.js`: 601 | + `import Env from './../environments';`: to get `baseUrl` with environments 602 | + `export default class DbService` as static class 603 | + set baseUrl to get API: 604 | ```jsx 605 | static baseUrl() { return Env.baseUrl; } 606 | static parseUrl(url) { return DbService.baseUrl() + url; } 607 | ``` 608 | 609 | Example `get` API: 610 | ```js 611 | static getItems = () => { 612 | let url = DbService.parseUrl('/api/items'); 613 | console.log(url); 614 | return fetch(url).then(res => res.json()); 615 | } 616 | ``` 617 | 618 | Example `Post` API: 619 | ```js 620 | static addItem = (item) => { 621 | let url = DbService.parseUrl('/api/items'); 622 | return fetch(url, { 623 | method: 'POST', 624 | headers: { 625 | 'Accept': 'application/json', 626 | 'Content-Type': 'application/json' 627 | }, 628 | body: JSON.stringify(item) 629 | }).then(res => res.json()); 630 | } 631 | ``` 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | # UI Awesome with React Component 647 | 648 | 649 | ## Reveal Component on scroll: use `react-reveal` 650 | 651 | Tạo animation khi người dụng scroll tới element. Khá hữu ích. 652 | 653 | ### Installation 654 | `yarn add react-reveal` 655 | 656 | ### Support 657 | 658 | #### Reveal with React 659 | ``` 660 | Fade 661 | Flip 662 | Rotate 663 | Zoom 664 | Bounce 665 | Slide 666 | Roll 667 | 668 | left/right/top/bottom 669 | fadeOut 670 | ``` 671 | #### Animated.css with React 672 | ``` 673 | Jump 674 | Flash 675 | HeadShake 676 | Jello 677 | Pulse 678 | RubberBand 679 | Shake 680 | Spin 681 | Swing 682 | Tada 683 | ``` 684 | 685 | ### How to use? 686 | 1. Use http://www.react-reveal.com/examples/. 687 | 2. View demo with component `DemoReactReveal`. 688 | 689 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/react-reveal) 690 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-reveal/DemoReactReveal.jsx) 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | ## Scroll animted to target - react-scrollchor 701 | 702 | Tạo animation khi người dùng click và chuyển tới 1 element nào đó. 703 | 704 | ### Installation 705 | `yarn add react-scrollchor` 706 | 707 | 708 | ### How to use? 709 | 1. Use https://github.com/bySabi/react-scrollchor 710 | 2. View demo with component `DemoReactScrollchor`. 711 | 712 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/react-scrollchor) 713 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-scrollchor/DemoReactScrollchor.jsx) 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | # Datatable with `react-table` 722 | 1. Xem demo: [Demo](https://huynhsamha.github.io/react-configure/react-table) 723 | 2. Xem implementation trong [`demo-react-table` - Implementation](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-table/DemoReactTable.jsx) 724 | 3. Ta dùng [`react-table`](https://react-table.js.org/#/story/readme) with features: 725 | + Lightweight at 11kb (and just 2kb more for styles) 726 | + Fully customizable (JSX, templates, state, styles, callbacks) 727 | + Client-side & Server-side pagination 728 | + Multi-sort 729 | + Filters 730 | + Pivoting & Aggregation 731 | + Minimal design & easily themeable 732 | + Fully controllable via optional props and callbacks 733 | 4. Mình cũng dùng thêm `react-select` và `react-datepicker` với `moment`. You can view docs for these package here: 734 | + [`react-select` - Demo](http://jedwatson.github.io/react-select/) 735 | + [`react-select` - Docs](https://github.com/JedWatson/react-select) 736 | + [`react-datepicker` - Demo](https://reactdatepicker.com/) 737 | + [`react-datepicker` - Docs](https://github.com/Hacker0x01/react-datepicker) 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | # VS Code Extensions 749 | Làm việc với react thì không thể thiếu các extension cần thiết nếu bạn đang sử dụng visual studio code (VS Code) 750 | 751 | Các bạn chỉ đơn giản install extension và config nếu cần thiết. 752 | 753 | ## Icons, Colors, View 754 | - [vscode-icons](https://marketplace.visualstudio.com/items?itemName=robertohuertasm.vscode-icons) 755 | - [Bracket Pair Colorizer](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer) 756 | 757 | ## Snippets 758 | - [ES7 React/Redux/GraphQL/React-Native snippets](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets) 759 | - [JavaScript (ES6) code snippets](https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets) 760 | - [Bootstrap 3 Snippets](https://marketplace.visualstudio.com/items?itemName=wcwhitehead.bootstrap-3-snippets) 761 | - [Bootstrap 4 & Font awesome snippets](https://marketplace.visualstudio.com/items?itemName=thekalinga.bootstrap4-vscode) 762 | - [Font-awesome codes for html](https://marketplace.visualstudio.com/items?itemName=medzhidov.font-awesome-codes-html) 763 | - [Font-awesome codes for css](https://marketplace.visualstudio.com/items?itemName=medzhidov.font-awesome-codes-css) 764 | - [HTML Snippets](https://marketplace.visualstudio.com/items?itemName=abusaidm.html-snippets) 765 | - [HTML CSS suppport](https://marketplace.visualstudio.com/items?itemName=ecmel.vscode-html-css) 766 | 767 | ## Intellisence 768 | - [npm](https://marketplace.visualstudio.com/items?itemName=eg2.vscode-npm-script) 769 | - [npm Intellisence](https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense) 770 | - [Path Intellisense](https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense) 771 | - [SCSS IntelliSence](https://marketplace.visualstudio.com/items?itemName=mrmlnc.vscode-scss) 772 | - [Auto Close Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag) 773 | - [Auto Rename Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag) 774 | - [IntelliSense for CSS class names](https://marketplace.visualstudio.com/items?itemName=Zignd.html-css-class-completion) 775 | 776 | ## Lint Code, Formater 777 | - [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) 778 | - [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) 779 | - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) 780 | - [TSLint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint) 781 | - [Sass](https://marketplace.visualstudio.com/items?itemName=robinbentley.sass-indented) 782 | - [Sass Formatter](https://marketplace.visualstudio.com/items?itemName=sasa.vscode-sass-format) 783 | - [Beautify css/sass/scss/less](https://marketplace.visualstudio.com/items?itemName=michelemelluso.code-beautifier) 784 | 785 | 786 | ## Edit, Preview README - Markdown files 787 | - [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) 788 | - [Markdown Preview Enhanced](https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced) 789 | - [Markdown PDF](https://marketplace.visualstudio.com/items?itemName=yzane.markdown-pdf) 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | # VS Code User Settings 822 | Cũng nên setting một số config cho VS Code, tạo nên coding style chuẩn: 823 | 824 | 1. Enter `Ctrl + Shift P` 825 | 2. Search `user settings` 826 | 3. Choose `Preferences: Open User Settings` and enter. 827 | 4. Edit your file `User Settings` by following lines: 828 | (you can search in `Default Settings` and customize your style) 829 | 830 | ```json 831 | { 832 | "workbench.iconTheme": "vscode-icons", 833 | "workbench.startupEditor": "newUntitledFile", 834 | "window.zoomLevel": 0, 835 | "editor.fontSize": 13, 836 | "eslint.autoFixOnSave": true, 837 | "tslint.autoFixOnSave": true, 838 | "editor.formatOnSave": false, 839 | "editor.renderWhitespace": "boundary", 840 | "editor.quickSuggestions": { 841 | "other": true, 842 | "comments": true, 843 | "strings": true 844 | }, 845 | "terminal.integrated.cursorStyle": "line", 846 | "terminal.integrated.fontSize": 13, 847 | "terminal.integrated.fontFamily": "", 848 | "vsicons.projectDetection.autoReload": true, 849 | } 850 | ``` 851 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-configure 2 | 3 | 4 | Necessary configure for [create-react-app](https://github.com/facebook/create-react-app) with [redux](https://redux.js.org/docs/basics/UsageWithReact.html), 5 | react-redux, 6 | redux-thunk, 7 | react-router, 8 | react-router-dom, 9 | sass, 10 | code spliting, 11 | jQuery, 12 | bootstrap, 13 | react-loadable, 14 | react-scrollchor, 15 | react-intl, 16 | react-select, 17 | react-datepicker, 18 | react-table, 19 | moment, 20 | ... 21 | 22 | 23 | 24 | ![vn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) [**Vietnamese version here**](https://github.com/huynhsamha/react-configure/blob/master/README.VN.md) 25 | 26 | 27 | 28 | 29 | ## Table of contents: 30 | - [Start with `create-react-app`](#start-with-create-react-app) 31 | - [Config environment variables](#config-environment-variables) 32 | - [Post-Processing CSS:](#post-processing-css) 33 | - [CSS Preprocessor (Sass, Less, etc.)](#css-preprocessor-sass-less-etc) 34 | - [Create Node.JS server](#create-nodejs-server) 35 | - [Use `express` to initialization](#use-express-to-initialization) 36 | - [Configuration](#configuration) 37 | - [Install dependencies package](#install-dependencies-package) 38 | - [Install package `cors`](#install-package-cors) 39 | - [Start server-client](#start-server-client) 40 | - [Environment for react app](#environment-for-react-app) 41 | - [Organize `src` react app](#organize-src-react-app) 42 | - [Styles](#styles) 43 | - [Library and packages](#library-and-packages) 44 | - [Utility service](#utility-service) 45 | - [Reducers - Actions](#reducers---actions) 46 | - [Components](#components) 47 | - [Layout Components](#layout-components) 48 | - [Common Components](#common-components) 49 | - [Pages Components](#pages-components) 50 | - [jQuery](#jquery) 51 | - [Installation](#installation) 52 | - [How to use?](#how-to-use) 53 | - [Recommend](#recommend) 54 | - [Bootstrap 3, 4](#bootstrap-3-4) 55 | - [Use along with jQuery](#use-along-with-jquery) 56 | - [Installation](#installation) 57 | - [How to use?](#how-to-use) 58 | - [Use via React Component - `reactstrap`](#use-via-react-component---reactstrap) 59 | - [Installation and Usage](#installation-and-usage) 60 | - [Recommend](#recommend) 61 | - [Font Awesome](#font-awesome) 62 | - [Add via `index.html`](#add-via-indexhtml) 63 | - [Add via npm package](#add-via-npm-package) 64 | - [Animate.css](#animatecss) 65 | - [Install and configure](#install-and-configure) 66 | - [Custom duration time](#custom-duration-time) 67 | - [How to use](#how-to-use) 68 | - [Demo](#demo) 69 | - [`react-router-dom` (router)](#react-router-dom-router) 70 | - [`react-loadable` (code-splitting)](#react-loadable-code-splitting) 71 | - [Installation, Usage](#installation-usage) 72 | - [Test Loadable Components - code-splitting](#test-loadable-components---code-splitting) 73 | - [`react-intl` - API to format date, number and string](#react-intl---api-to-format-date-number-and-string) 74 | - [Features](#features) 75 | - [Document](#document) 76 | - [Usage in this tutorial](#usage-in-this-tutorial) 77 | - [Redux: `redux, react-redux, redux-thunk`](#redux-redux-react-redux-redux-thunk) 78 | - [Installation](#installation) 79 | - [Usage](#usage) 80 | - [Fetch Data API to server node](#fetch-data-api-to-server-node) 81 | - [Create `services` to get API](#create-services-to-get-api) 82 | - [UI Awesome with React Component](#ui-awesome-with-react-component) 83 | - [Reveal Component on scroll: use `react-reveal`](#reveal-component-on-scroll-use-react-reveal) 84 | - [Installation](#installation) 85 | - [Support](#support) 86 | - [Reveal with React](#reveal-with-react) 87 | - [Animated.css with React](#animatedcss-with-react) 88 | - [How to use?](#how-to-use) 89 | - [Scroll animated to target - react-scrollchor](#scroll-animated-to-target---react-scrollchor) 90 | - [Installation](#installation) 91 | - [How to use?](#how-to-use) 92 | - [Datatable with `react-table`](#datatable-with-react-table) 93 | - [VS Code Extensions](#vs-code-extensions) 94 | - [Icons, Colors, View](#icons-colors-view) 95 | - [Snippets](#snippets) 96 | - [Intellisence](#intellisence) 97 | - [Lint Code, Formater](#lint-code-formater) 98 | - [Edit, Preview README - Markdown files](#edit-preview-readme---markdown-files) 99 | - [VS Code User Settings](#vs-code-user-settings) 100 | 101 | 102 | 103 | 104 | # Start with `create-react-app` 105 | In this step, you should have `create-react-app` is installed globally. 106 | 107 | 1. Create a new app: `create-react-app react-app` 108 | 2. use `npm start` or `yarn start` to start development 109 | 3. use `npm build` or `yarn build` to build production 110 | 111 | In this tutorial, I will use `yarn`, you can also use `npm`. 112 | 113 | 114 | 115 | 116 | # Config environment variables 117 | Create environment files, `create-react-app` will use them. 118 | 119 | 1. In terminal at root: `touch .env .env.development .env.production` 120 | 2. In `.env.development`: `REACT_APP_ENV=development` 121 | 3. In `.env.production` : `REACT_APP_ENV=production` 122 | 123 | You can also set new environment variable. 124 | **Note:** only variable with prefix `REACT_APP_` can use in `create-react-app` 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | # Post-Processing CSS: 133 | As `create-react-app` said: 134 | 135 | > This project setup minifies your CSS and adds vendor prefixes to it automatically through Autoprefixer so you don’t need to worry about it. 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | # CSS Preprocessor (Sass, Less, etc.) 144 | 145 | 1. In terminal: `yarn add node-sass-chokidar npm-run-all` 146 | 2. In file `package.json`: 147 | ```json 148 | { 149 | "scripts": { 150 | - "start": "react-scripts start", 151 | - "build": "react-scripts build", 152 | + "start": "npm-run-all -p watch-css start-js", 153 | + "build": "npm-run-all build-css build-js", 154 | + "start-js": "react-scripts start", 155 | + "build-js": "react-scripts build", 156 | + "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive", 157 | + "build-css": "node-sass-chokidar src/ -o src/", 158 | } 159 | } 160 | ``` 161 | 3. In file `.gitignore`: 162 | 163 | ``` 164 | # auto generated files (sass, less, ...) 165 | src/**/*.css 166 | ``` 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | # Create Node.JS server 177 | Optional if you need a node.js server 178 | 179 | ## Use `express` to initialization 180 | 181 | ```bash 182 | mkdir server 183 | cd server 184 | express 185 | ``` 186 | 187 | ## Configuration 188 | 189 | 1. Rename `app.js` to `server.js` 190 | 2. Join `server.js` and `./bin/www` 191 | 3. Move `server.js` to root app 192 | 4. Insert dependencies in `package.json` (which is generated by `express`) to `package.json` in root (which is generated by `create-react-app`) 193 | 5. Remove dependencies not use (`serve-favicon`, `jade`, `ejs`, etc.) 194 | 6. Remove all file in `server`, except `routes/index.js` 195 | 7. Correct and customize file `server.js` 196 | 197 | 198 | ## Install dependencies package 199 | 200 | `yarn` 201 | 202 | ## Install package `cors` 203 | 204 | For development, use package `cors` to cross `localhost:3000` (client-side, is react app) to `localhost:4200` (server-side, is node express) 205 | 206 | `yarn add cors` 207 | 208 | ## Start server-client 209 | 210 | `yarn start` or `npm start`: start client side (react): `localhost:3000` 211 | 212 | `node server`: start server-side (node express): `localhost:4200` 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | # Environment for react app 223 | In development, because we use node server at port 4200, but client side is port 3000, so we should check out environment variable `REACT_APP_ENV` (which created in above steps) to fetch data from the server. 224 | 225 | 1. Create environment files: 226 | In your terminal: 227 | ```bash 228 | mkdir src/environments 229 | cd src/environments 230 | touch env.development.js env.production.js index.js 231 | ``` 232 | 2. Edit the files as source code. `baseUrl` is url to server. 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | # Organize `src` react app 241 | 242 | ## Styles 243 | Create `styles` in `src/` to contain variables, mixins, classes, common styles, or theme, etc. for your app: 244 | + `_variables.scss`: declare variables for style. 245 | + `_mixins.scss`: declare mixins for style 246 | + `_classes.scss`: declare some util classes for style 247 | + `index.scss`: import `_` files to this file, you should move `index.scss` (in root) to this folder and in `index.js`, you only import `./styles/index.css` 248 | + You also override some theme (such as AdminLTE, Bootstrap, Material, Angular, Datatables, Charts, ...) with files `_` and import to `index.scss` 249 | 250 | ## Library and packages 251 | Create `lib` in `src` to contain some library or package you use in this app, or config something with these packages (such as jQuery, Bootstrap, Font-Awesome, Ionicons, Material, ...): 252 | + You also create `index.js` in `lib` to import these files in folder. 253 | + In `index.js` in root, you only import by one line: `import './lib';` 254 | 255 | ## Utility service 256 | Create `services` to contain your services for app. Guides are below sections 257 | 258 | ## Reducers - Actions 259 | Create `actions`, `reducers` to do with `redux`. Guides are below sections 260 | 261 | ## Components 262 | Create `components` to contain components in app: 263 | Guides for these components is below sections 264 | 265 | ### Layout Components 266 | - Create `layout` in `components` to contain layout of app (flow). 267 | - Your `App.js`, `App.scss` also in here, which import `Header`, `Footer`, `Sidebar`, `Menu`, `Body`,... for Navigations and Router 268 | 269 | ### Common Components 270 | Create `common` in `components` to contain some components which are used a lot of times. Such as `Loading`, `Modal`, `Alert`, `Notification`, `Box`, ... 271 | 272 | ### Pages Components 273 | Create `pages` in `components` to contain some pages in app, which is route in component `Body`, such as `Home`, `Dashboard`, `Profile`, `Form`, `Terms of Service`, `Support`, `Page not found`, `Error page`,... 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | # jQuery 282 | 283 | ## Installation 284 | 1. In terminal: `yarn add jquery` 285 | 2. In terminal: `touch src/lib/jquery.js` 286 | 3. Edit created file by the following lines: 287 | 288 | ```js 289 | import $ from 'jquery'; 290 | 291 | // config jquery variables for other lib use jQuery (such as bootstrap) 292 | window.$ = $; 293 | window.jQuery = $; 294 | ``` 295 | 296 | ## How to use? 297 | 1. In `lib/index.js`, import by: `import './jquery';` 298 | 2. In `index.js` at root, `import './lib';` (if you don't have). 299 | 3. In the component, to use jQuery, you should import: `import $ from 'jquery';` 300 | 4. To use jquery function, only use from `componentDidMount()` in Lifecycle React components: 301 | 5. [View Demo here](https://huynhsamha.github.io/react-configure/jquery) 302 | 6. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-jquery/DemoJquery.jsx) 303 | 304 | 305 | ```javascript 306 | componentDidMount() { 307 | // jQuery should declare at here 308 | $(document).ready(() => { 309 | $('#alert').click(() => alert('This is alert be jQuery')); 310 | }); 311 | } 312 | ``` 313 | 314 | 315 | ## Recommend 316 | Not use jQuery if it's not needed 317 | 318 | 319 | 320 | 321 | 322 | 323 | # Bootstrap 3, 4 324 | 325 | 326 | ## Use along with jQuery 327 | ### Installation 328 | 1. In terminal: `yarn add bootstrap` (add @version you choose) 329 | 2. In terminal: `mkdir src/lib` (if you have `lib`, skip this step) 330 | 3. In terminal: `touch src/lib/bootstrap.js` 331 | 4. Edit created file as lines (In this tutorial, I use bootstrap 4): 332 | 333 | ```javascript 334 | import 'bootstrap/dist/css/bootstrap.min.css'; 335 | import 'bootstrap/dist/js/bootstrap.bundle.min.js'; 336 | ``` 337 | 338 | ### How to use? 339 | 1. In `lib/index.js`, import by: `import './bootstrap';` 340 | 2. In `index.js` at root, `import './lib';` (if you don't have). 341 | 3. In the component, you can use bootstrap 3, 4 as document available 342 | 4. View demo with component `DemoBootstrap`. 343 | 5. [View Demo here](https://huynhsamha.github.io/react-configure/bootstrap) 344 | 6. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-bootstrap/DemoBootstrap.jsx) 345 | 346 | 347 | 348 | 349 | ## Use via React Component - `reactstrap` 350 | 351 | ### Installation and Usage 352 | 1. In terminal: `yarn add reactstrap@next` 353 | 2. Only import Component to use as reactstrap document 354 | 3. View demo with component `DemoReactstrap`. 355 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/reactstrap) 356 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-reactstrap/DemoReactstrap.jsx) 357 | 358 | ## Recommend 359 | 1. I think you should use `reactstrap` if you want to use some component in react, with event handlers. 360 | 2. If you need some style in bootstrap, you can use directly and don't need to use `jQuery` 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | # Font Awesome 369 | ## Add via `index.html` 370 | 371 | You can include via file `index.html` in folder `public` via `CDN` or download and `link stylesheet` 372 | 373 | 374 | ## Add via npm package 375 | 376 | 1. In terminal: `yarn add font-awesome` 377 | 2. Create file `lib/font-awesome.js` and add line `import 'font-awesome/css/font-awesome.min.css';` 378 | 3. In `lib/index.js`, import by: `import './font-awesome';` 379 | 4. In `index.js` at root, `import './lib';` (if you don't have). 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | # Animate.css 389 | ## Install and configure 390 | 1. `yarn add animate.css` 391 | 2. In `lib/` create file `animate-css.js` and add `import 'animate.css';` 392 | 3. In `index.js`, also import by line `import './animate-css';` 393 | 394 | ## Custom duration time 395 | 1. Custom duration of animation by file scss config in `style/`: 396 | 2. Create file `_animate.scss` as source code 397 | 3. In `index.scss`: `@import './animate.scss';` 398 | 4. This file will create classes style to custom time duration: 399 | ``` 400 | .animated.duration-100 401 | .animated.duration-200 402 | ... 403 | .animated.duration-1100 404 | .animated.duration-1200 405 | ... 406 | .animated.duration-3000 407 | ``` 408 | 409 | ## How to use 410 | Example: 411 | ```html 412 | 413 |
ABCDEFGHIJKLMNOP
414 |
ABCDEFGHIJKLMNOP
415 |
ABCDEFGHIJKLMNOP
416 | 417 |
ABCDEFGHIJKLMNOP
418 |
ABCDEFGHIJKLMNOP
419 |
ABCDEFGHIJKLMNOP
420 | 421 |
ABCDEFGHIJKLMNOP
422 |
ABCDEFGHIJKLMNOP
423 | ``` 424 | 425 | 426 | ## Demo 427 | + View demo at component `DemoAnimateCss` 428 | + [View Demo here](https://huynhsamha.github.io/react-configure/animate-css) 429 | + [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-animate-css/DemoAnimateCss.jsx) 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | # `react-router-dom` (router) 439 | `react-router-dom` is used for route Single Page Application (SPA), not loading again page. 440 | 441 | 1. In terminal: `yarn add react-router-dom` 442 | 2. You can view implement in `components/layout/body` 443 | 3. You also view implement in `components/pages/demo-react-router` 444 | 4. The Document is available at [React Router Dom](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-dom) 445 | 446 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/react-router) 447 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-router/DemoReactRouter.jsx) 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | # `react-loadable` (code-splitting) 456 | 457 | ## Installation, Usage 458 | 459 | `react-loadable` is useful for code-splitting: 460 | + Lazy load components until it's called by user, it speeds up your Single Page App (SPA). 461 | + `create-react-app` will bundle a new script file, when it's called, it will import this file to app. 462 | 463 | 1. In terminal: `yarn add react-loadable react-router-dom` 464 | 2. Create Loading component (view components/common/loading/) 465 | 3. When use Loadable with loading component, it will add props to this component, such as: 466 | `{ isLoading: true, pastDelay: false, timedOut: false, error: null }` 467 | 4. View `components/page/demo-loadable-component` to sample implement. 468 | 5. Component `DemoLoadableComponent` (is not loadable) and `LoadableDemoComponent` (is loadable) 469 | 470 | ## Test Loadable Components - code-splitting 471 | 1. Inspect element in the browser 472 | 2. Choose tab network 473 | 3. Click filter JS 474 | 4. Refresh page 475 | 5. First only `bundle.js` and some js file 476 | 6. Click component which loadable, you see `*.chunk.js` is loaded. That is lazy loading component 477 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/react-loadable) 478 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-router/DemoReactRouter.jsx) 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | # `react-intl` - API to format date, number and string 489 | Internationalize React apps. This library provides React components and an API to format dates, numbers, and strings, including pluralization and handling translations. 490 | 491 | ## Features 492 | + Display numbers with separators. 493 | + Display dates and times correctly. 494 | + Display dates relative to "now". 495 | + Pluralize labels in strings. 496 | + Support for 150+ languages. 497 | + Runs in the browser and Node.js. 498 | + Built on standards. 499 | 500 | ## Document 501 | You can view the document here: [https://github.com/yahoo/react-intl](https://github.com/yahoo/react-intl) 502 | 503 | 504 | ## Usage in this tutorial 505 | 1. In `index.js`, we import and use provider for App component: 506 | 507 | ```jsx 508 | import { IntlProvider } from 'react-intl'; 509 | 510 | ReactDOM.render( 511 | 512 | 513 | 514 | 515 | 516 | , 517 | 518 | document.getElementById('root') 519 | ); 520 | ``` 521 | 522 | 2. In specific component, you can import component of `react-intl` to use. You can view 1 demo about this in demo redux with format date. 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | # Redux: `redux, react-redux, redux-thunk` 533 | 534 | ## Installation 535 | `yarn add redux react-redux redux-thunk` 536 | 537 | ## Usage 538 | 1. In `src`, create dir and files: 539 | + `actions/action-types.js`: declare action name as const 540 | + `actions/index.js`: declare actions for redux 541 | + `reducers/`: declare reducers 542 | + `reducers/[name].js`: declare action for a specific object. 543 | + `reducers/index.js`: to combine reducer with redux, after that is to createStore. 544 | 545 | 2. In `index.js`: 546 | + `import { Provider } from 'react-redux';`: use Provider to store redux 547 | + `import { createStore, applyMiddleware } from 'redux';`: use createStore and middleware `thunk` with createStore 548 | + `import thunk from 'redux-thunk';`: middleware for createStore, support async function 549 | + `import allReducers from './reducers';`: reducers after combined 550 | + `const store = createStore(allReducers, applyMiddleware(thunk));`: createStore with combined reducer, and apply middleware thunk 551 | + You don't care about other reducers, such as `Users` 552 | 553 | 3. In `reducers/index.js`: combine reducers: 554 | + In this tutorial, I demo with Items and Users (users is used for other section demos). 555 | ```js 556 | import { combineReducers } from 'redux'; 557 | 558 | import Items from './items'; 559 | import Users from './users'; 560 | 561 | const reducers = combineReducers({ 562 | Items, 563 | Users 564 | }); 565 | 566 | export default reducers; 567 | ``` 568 | 569 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/redux) 570 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-redux/DemoRedux.jsx) 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | # Fetch Data API to the server node 586 | ## Create `services` to get API 587 | 1. `mkdir src/services` (if you have not) 588 | 2. `touch db-service.js auth-service.js` (db- to get database, auth- to authentication user) 589 | 3. Example with `db-service.js`: 590 | + `import Env from './../environments';`: to get `baseUrl` with environments 591 | + `export default class DbService` as static class 592 | + set baseUrl to get API: 593 | ```jsx 594 | static baseUrl() { return Env.baseUrl; } 595 | static parseUrl(url) { return DbService.baseUrl() + url; } 596 | ``` 597 | 598 | Example `get` API: 599 | ```js 600 | static getItems = () => { 601 | let url = DbService.parseUrl('/api/items'); 602 | console.log(url); 603 | return fetch(url).then(res => res.json()); 604 | } 605 | ``` 606 | 607 | Example `Post` API: 608 | ```js 609 | static addItem = (item) => { 610 | let url = DbService.parseUrl('/api/items'); 611 | return fetch(url, { 612 | method: 'POST', 613 | headers: { 614 | 'Accept': 'application/json', 615 | 'Content-Type': 'application/json' 616 | }, 617 | body: JSON.stringify(item) 618 | }).then(res => res.json()); 619 | } 620 | ``` 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | # UI Awesome with React Component 636 | 637 | 638 | ## Reveal Component on scroll: use `react-reveal` 639 | 640 | Animation to show component when user scroll to view. 641 | 642 | ### Installation 643 | `yarn add react-reveal` 644 | 645 | ### Support 646 | 647 | #### Reveal with React 648 | ``` 649 | Fade 650 | Flip 651 | Rotate 652 | Zoom 653 | Bounce 654 | Slide 655 | Roll 656 | 657 | left/right/top/bottom 658 | fadeOut 659 | ``` 660 | #### Animated.css with React 661 | ``` 662 | Jump 663 | Flash 664 | HeadShake 665 | Jello 666 | Pulse 667 | RubberBand 668 | Shake 669 | Spin 670 | Swing 671 | Tada 672 | ``` 673 | 674 | ### How to use? 675 | 1. Use http://www.react-reveal.com/examples/. 676 | 2. View demo with component `DemoReactReveal`. 677 | 678 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/react-reveal) 679 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-reveal/DemoReactReveal.jsx) 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | ## Scroll animated to target - react-scrollchor 690 | 691 | Animation to scroll to a component when user clicks to the link. 692 | 693 | ### Installation 694 | `yarn add react-scrollchor` 695 | 696 | 697 | ### How to use? 698 | 1. Use https://github.com/bySabi/react-scrollchor 699 | 2. View demo with component `DemoReactScrollchor`. 700 | 701 | 4. [View Demo here](https://huynhsamha.github.io/react-configure/react-scrollchor) 702 | 5. [View Implementation here](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-scrollchor/DemoReactScrollchor.jsx) 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | # Datatable with `react-table` 711 | 1. View demo for this guide here: [Demo](https://huynhsamha.github.io/react-configure/react-table) 712 | 2. View implementation in [`demo-react-table` - Implementation](https://github.com/huynhsamha/react-configure/blob/master/src/components/pages/demo-react-table/DemoReactTable.jsx) 713 | 3. In this guide, we use [`react-table`](https://react-table.js.org/#/story/readme) with features: 714 | + Lightweight at 11kb (and just 2kb more for styles) 715 | + Fully customizable (JSX, templates, state, styles, callbacks) 716 | + Client-side & Server-side pagination 717 | + Multi-sort 718 | + Filters 719 | + Pivoting & Aggregation 720 | + Minimal design & easily themeable 721 | + Fully controllable via optional props and callbacks 722 | 4. In this guide, we also use `react-select` and `react-datepicker` with `moment`. You can view docs for these packages here: 723 | + [`react-select` - Demo](http://jedwatson.github.io/react-select/) 724 | + [`react-select` - Docs](https://github.com/JedWatson/react-select) 725 | + [`react-datepicker` - Demo](https://reactdatepicker.com/) 726 | + [`react-datepicker` - Docs](https://github.com/Hacker0x01/react-datepicker) 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | # VS Code Extensions 738 | I think the following extensions are helpful for development: 739 | 740 | ## Icons, Colors, View 741 | - [vscode-icons](https://marketplace.visualstudio.com/items?itemName=robertohuertasm.vscode-icons) 742 | - [Bracket Pair Colorizer](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer) 743 | 744 | ## Snippets 745 | - [ES7 React/Redux/GraphQL/React-Native snippets](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets) 746 | - [JavaScript (ES6) code snippets](https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets) 747 | - [Bootstrap 3 Snippets](https://marketplace.visualstudio.com/items?itemName=wcwhitehead.bootstrap-3-snippets) 748 | - [Bootstrap 4 & Font awesome snippets](https://marketplace.visualstudio.com/items?itemName=thekalinga.bootstrap4-vscode) 749 | - [Font-awesome codes for html](https://marketplace.visualstudio.com/items?itemName=medzhidov.font-awesome-codes-html) 750 | - [Font-awesome codes for css](https://marketplace.visualstudio.com/items?itemName=medzhidov.font-awesome-codes-css) 751 | - [HTML Snippets](https://marketplace.visualstudio.com/items?itemName=abusaidm.html-snippets) 752 | - [HTML CSS support](https://marketplace.visualstudio.com/items?itemName=ecmel.vscode-html-css) 753 | 754 | ## Intellisence 755 | - [npm](https://marketplace.visualstudio.com/items?itemName=eg2.vscode-npm-script) 756 | - [npm Intellisence](https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense) 757 | - [Path Intellisense](https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense) 758 | - [SCSS IntelliSence](https://marketplace.visualstudio.com/items?itemName=mrmlnc.vscode-scss) 759 | - [Auto Close Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag) 760 | - [Auto Rename Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag) 761 | - [IntelliSense for CSS class names](https://marketplace.visualstudio.com/items?itemName=Zignd.html-css-class-completion) 762 | 763 | ## Lint Code, Formater 764 | - [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) 765 | - [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) 766 | - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) 767 | - [TSLint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint) 768 | - [Sass](https://marketplace.visualstudio.com/items?itemName=robinbentley.sass-indented) 769 | - [Sass Formatter](https://marketplace.visualstudio.com/items?itemName=sasa.vscode-sass-format) 770 | - [Beautify css/sass/scss/less](https://marketplace.visualstudio.com/items?itemName=michelemelluso.code-beautifier) 771 | 772 | 773 | ## Edit, Preview README - Markdown files 774 | - [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) 775 | - [Markdown Preview Enhanced](https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced) 776 | - [Markdown PDF](https://marketplace.visualstudio.com/items?itemName=yzane.markdown-pdf) 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | # VS Code User Settings 809 | 810 | I think you also setting your VSCode by following steps: 811 | 812 | 1. Enter `Ctrl + Shift P` 813 | 2. Search `user settings` 814 | 3. Choose `Preferences: Open User Settings` and enter. 815 | 4. Edit your file `User Settings` by following lines: 816 | (you can search in `Default Settings` and customize your style) 817 | 818 | ```json 819 | { 820 | "workbench.iconTheme": "vscode-icons", 821 | "workbench.startupEditor": "newUntitledFile", 822 | "window.zoomLevel": 0, 823 | "editor.fontSize": 13, 824 | "eslint.autoFixOnSave": true, 825 | "tslint.autoFixOnSave": true, 826 | "editor.formatOnSave": false, 827 | "editor.renderWhitespace": "boundary", 828 | "editor.quickSuggestions": { 829 | "other": true, 830 | "comments": true, 831 | "strings": true 832 | }, 833 | "terminal.integrated.cursorStyle": "line", 834 | "terminal.integrated.fontSize": 13, 835 | "terminal.integrated.fontFamily": "", 836 | "vsicons.projectDetection.autoReload": true, 837 | } 838 | ``` 839 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-app", 3 | "version": "1.0.0", 4 | "private": true, 5 | "homepage": "https://huynhsamha.github.io/react-configure", 6 | "scripts": { 7 | "start": "npm-run-all -p watch-css start-js", 8 | "build": "npm-run-all build-css build-js", 9 | "start-js": "react-scripts start", 10 | "build-js": "react-scripts build", 11 | "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive", 12 | "build-css": "node-sass-chokidar src/ -o src/", 13 | "test": "react-scripts test --env=jsdom", 14 | "eject": "react-scripts eject", 15 | "eslint": "eslint --ext=js --ext=jsx server.js src/ server/", 16 | "eslint:fix": "eslint --ext=js --ext=jsx server.js src/ server/ --fix", 17 | "predeploy": "yarn build", 18 | "deploy": "gh-pages -d build" 19 | }, 20 | "dependencies": { 21 | "animate.css": "^3.6.1", 22 | "babel-eslint": "^8.2.1", 23 | "body-parser": "~1.18.2", 24 | "bootstrap": "^4.0.0", 25 | "cookie-parser": "~1.4.3", 26 | "cors": "^2.8.4", 27 | "debug": "~2.6.9", 28 | "express": "~4.15.5", 29 | "font-awesome": "^4.7.0", 30 | "jquery": "^3.3.1", 31 | "match-sorter": "^2.2.0", 32 | "moment": "^2.20.1", 33 | "morgan": "~1.9.0", 34 | "node-sass-chokidar": "0.0.3", 35 | "npm-run-all": "^4.1.2", 36 | "prop-types": "^15.6.0", 37 | "react": "^16.2.0", 38 | "react-datepicker": "^1.1.0", 39 | "react-dom": "^16.2.0", 40 | "react-intl": "^2.4.0", 41 | "react-loadable": "^5.3.1", 42 | "react-redux": "^5.0.6", 43 | "react-reveal": "^1.0.0", 44 | "react-router-dom": "^4.2.2", 45 | "react-scripts": "1.1.0", 46 | "react-scrollchor": "^4.2.1", 47 | "react-select": "^1.2.1", 48 | "react-table": "^6.7.6", 49 | "reactstrap": "^5.0.0-beta", 50 | "redux": "^3.7.2", 51 | "redux-thunk": "^2.2.0", 52 | "uniqid": "^4.1.1" 53 | }, 54 | "devDependencies": { 55 | "eslint": "^4.17.0", 56 | "eslint-config-airbnb": "^16.1.0", 57 | "eslint-plugin-import": "^2.8.0", 58 | "eslint-plugin-jsx-a11y": "^6.0.3", 59 | "eslint-plugin-react": "^7.6.1", 60 | "gh-pages": "^1.1.0" 61 | }, 62 | "engines": { 63 | "node": ">=6.10.0 <=10.21.0", 64 | "npm": ">=3.10.8" 65 | }, 66 | "keywords": [ 67 | "react", 68 | "create-react-app", 69 | "code-splitting", 70 | "redux", 71 | "redux-thunk", 72 | "reactjs", 73 | "react-router", 74 | "react-redux", 75 | "react-router-dom", 76 | "starter-kit", 77 | "sass", 78 | "step", 79 | "react-loadable", 80 | "react-scrollchor", 81 | "scroll", 82 | "react-intl", 83 | "animate.css", 84 | "animate", 85 | "react-select", 86 | "moment", 87 | "momentjs", 88 | "react-datepicker", 89 | "datepicker", 90 | "create-react-app-configure", 91 | "react-configure" 92 | ] 93 | } 94 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huynhsamha/react-configure/076320259ff3524da352cfb9b62068d12affb627/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 |
33 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var path = require('path'); 5 | var logger = require('morgan'); 6 | var cookieParser = require('cookie-parser'); 7 | var bodyParser = require('body-parser'); 8 | var http = require('http'); 9 | var cors = require('cors'); 10 | 11 | var app = express(); 12 | 13 | app.use(logger('dev')); 14 | app.use(bodyParser.json()); 15 | app.use(bodyParser.urlencoded({ extended: false })); 16 | app.use(cookieParser()); 17 | app.use(express.static(path.join(__dirname, 'build'))); // use for deploy production with build/ 18 | 19 | app.use(cors()); 20 | 21 | var route = require('./server/routes'); 22 | 23 | app.use(route); 24 | 25 | // catch 404 and forward to error handler 26 | app.use((req, res, next) => { 27 | var err = new Error('Not Found'); 28 | err.status = 404; 29 | next(err); 30 | }); 31 | 32 | // error handler 33 | app.use((err, req, res, next) => { 34 | // set locals, only providing error in development 35 | res.locals.message = err.message; 36 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 37 | 38 | // render the error page 39 | res.status(err.status || 500); 40 | res.render('error'); 41 | }); 42 | 43 | var port = process.env.PORT || '4200'; 44 | app.set('port', port); 45 | 46 | var server = http.createServer(app); 47 | 48 | server.listen(port, () => console.log(`Running on localhost:${port}`)); 49 | -------------------------------------------------------------------------------- /server/routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | 3 | var router = express.Router(); 4 | 5 | /* GET home page. */ 6 | router.get('/', (req, res, next) => { 7 | res.render('index', { title: 'Express' }); 8 | }); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /src/actions/action-types.js: -------------------------------------------------------------------------------- 1 | export default { 2 | ADD_ITEM: 'ADD_ITEM', 3 | REMOVE_ITEM: 'REMOVE_ITEM', 4 | MOVE_ITEM: 'MOVE_ITEM', 5 | 6 | REMOVE_USER: 'REMOVE_USER', 7 | 8 | ADD_TODO: 'ADD_TODO', 9 | REMOVE_TODO: 'REMOVE_TODO', 10 | DONE_TODO: 'DONE_TODO', 11 | MODIFY_TODO: 'MODIFY_TODO' 12 | }; 13 | -------------------------------------------------------------------------------- /src/actions/index.js: -------------------------------------------------------------------------------- 1 | import actionTypes from './action-types'; 2 | 3 | export const addItem = item => ({ 4 | type: actionTypes.ADD_ITEM, 5 | item 6 | }); 7 | 8 | export const removeItem = id => ({ 9 | type: actionTypes.REMOVE_ITEM, 10 | id 11 | }); 12 | 13 | export const editItem = (id, newItem) => ({ 14 | type: actionTypes.EDIT_ITEM, 15 | id, 16 | newItem 17 | }); 18 | 19 | export const moveItem = (id, isUp) => ({ 20 | type: actionTypes.MOVE_ITEM, 21 | id, 22 | isUp 23 | }); 24 | 25 | export const removeUser = id => ({ 26 | type: actionTypes.REMOVE_USER, 27 | id 28 | }); 29 | 30 | 31 | export const addTodo = newTodo => ({ 32 | type: actionTypes.ADD_TODO, 33 | newTodo 34 | }); 35 | 36 | export const removeTodo = id => ({ 37 | type: actionTypes.REMOVE_TODO, 38 | id 39 | }); 40 | 41 | export const doneTodo = (id, isDone) => ({ 42 | type: actionTypes.DONE_TODO, 43 | id, isDone 44 | }); 45 | 46 | export const modifyTodo = (id, newTodo) => ({ 47 | type: actionTypes.MODIFY_TODO, 48 | id, newTodo 49 | }); 50 | -------------------------------------------------------------------------------- /src/components/common/loading/Loading.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import './Loading.css'; 5 | 6 | const propTypes = { 7 | error: PropTypes.bool, 8 | timeOut: PropTypes.bool, 9 | pastDelay: PropTypes.bool 10 | }; 11 | 12 | const defaultProps = { 13 | error: false, timeOut: false, pastDelay: false 14 | }; 15 | 16 | class Loading extends Component { 17 | constructor(props) { 18 | super(props); 19 | 20 | this.state = {}; 21 | } 22 | 23 | render() { 24 | /** 25 | * console.log(this.props); 26 | * {isLoading: true, pastDelay: false, timedOut: false, error: null} 27 | */ 28 | if (this.props.error) { 29 | return
Error
; 30 | } else if (this.props.timeOut) { 31 | return
Time out
; 32 | } else if (!this.props.pastDelay) { 33 | // delay Loading Component show on screen 200ms (be default, can be set in Loadable) 34 | // if after 200ms, component has just loaded, Loading will show. 35 | return null; 36 | } 37 | return ( 38 |
39 |
40 | Loading... 41 |
42 |
43 | ); 44 | } 45 | } 46 | 47 | Loading.propTypes = propTypes; 48 | Loading.defaultProps = defaultProps; 49 | 50 | export default Loading; 51 | -------------------------------------------------------------------------------- /src/components/common/loading/Loading.scss: -------------------------------------------------------------------------------- 1 | .Loading { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | width: 100%; 6 | height: 100%; 7 | background-color: rgba(0,0,0,0.7); 8 | .LoadingText { 9 | color: white; 10 | font-size: 25px; 11 | position: absolute; 12 | top: 50%; 13 | left: 50%; 14 | transform: translate(-50%, -50%); 15 | } 16 | } -------------------------------------------------------------------------------- /src/components/layout/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './App.css'; 3 | 4 | import Header from './header/Header'; 5 | import Footer from './footer/Footer'; 6 | import Body from './body/Body'; 7 | 8 | class App extends Component { 9 | 10 | constructor(props) { 11 | super(props); 12 | 13 | this.state = {}; 14 | } 15 | 16 | render() { 17 | return ( 18 |
19 |
20 | 21 |
23 | ); 24 | } 25 | } 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /src/components/layout/App.scss: -------------------------------------------------------------------------------- 1 | .App { 2 | height: 100%; 3 | width: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/layout/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/components/layout/body/Body.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'; 3 | 4 | import LifeCycleReactComponent from './../../pages/lifecycle-component'; 5 | import DemoJquery from './../../pages/demo-jquery/DemoJquery'; 6 | import DemoBootstrap from './../../pages/demo-bootstrap/DemoBootstrap'; 7 | import DemoReactstrap from './../../pages/demo-reactstrap/DemoReactstrap'; 8 | import DemoLoadableComponent from './../../pages/demo-loadable-component/LoadableDemoComponent'; 9 | import DemoReactRouter from './../../pages/demo-react-router/DemoReactRouter'; 10 | import DemoReactReveal from './../../pages/demo-react-reveal/DemoReactReveal'; 11 | import DemoReactScrollchor from './../../pages/demo-react-scrollchor/DemoReactScrollchor'; 12 | import DemoRedux from './../../pages/demo-redux/DemoRedux'; 13 | import DemoAnimateCss from './../../pages/demo-animate-css/DemoAnimateCss'; 14 | import DemoReactTable from './../../pages/demo-react-table/DemoReactTable'; 15 | 16 | import('./Body.css').then().catch(err => console.log(err)); 17 | 18 | export default class Body extends Component { 19 | render() { 20 | return ( 21 |
22 | 23 |
24 |
25 |
26 |
    27 |
  • Demo Jquery
  • 28 |
  • Demo Bootstrap
  • 29 |
  • Demo Reactstrap
  • 30 |
  • Demo React Router
  • 31 |
  • Demo react-loadable
  • 32 |
  • Demo react-reveal
  • 33 |
  • Demo react-scrollchor
  • 34 |
  • Demo Redux
  • 35 |
  • Demo animate.css
  • 36 |
  • Demo react-table
  • 37 |
  • Go to link not found
  • 38 |
39 | 40 |
41 | 42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
404 Page Not Found
} /> 56 |
57 |
58 |
59 |
60 |
61 |
62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/components/layout/body/Body.scss: -------------------------------------------------------------------------------- 1 | .Body { 2 | width: 100%; 3 | margin: 0 auto; 4 | line-height: 1.5; 5 | padding: 30px 0px; 6 | 7 | .Body-left { 8 | border-right: #cacaca 1.5px solid; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/layout/footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './Footer.css'; 3 | 4 | export default class Footer extends Component { 5 | 6 | render() { 7 | return ( 8 |
9 | Footer 10 |
11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/layout/footer/Footer.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/variables.scss'; 2 | .Footer { 3 | position: fixed; 4 | bottom: 0; 5 | left: 0; 6 | width: 100%; 7 | min-height: 30px; 8 | line-height: 30px; 9 | background-color: $blue; 10 | text-align: center; 11 | font-family: $font-family-Open-Sans; 12 | font-weight: 900; 13 | font-size: $font-size-medium; 14 | color: white; 15 | letter-spacing: 2px; 16 | text-transform: uppercase; 17 | z-index: $z-index-max; 18 | } 19 | -------------------------------------------------------------------------------- /src/components/layout/header/Header.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import './Header.css'; 3 | 4 | export default class Header extends Component { 5 | render() { 6 | return ( 7 |
8 | Header 9 |
10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/layout/header/Header.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/variables.scss'; 2 | .Header { 3 | width: 100%; 4 | height: 30px; 5 | line-height: 30px; 6 | background-color: $green; 7 | text-align: center; 8 | font-family: $font-family-Open-Sans; 9 | font-weight: 900; 10 | font-size: $font-size-medium; 11 | color: white; 12 | z-index: $z-index-max; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/pages/demo-animate-css/DemoAnimateCss.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import('./DemoAnimateCss.css'); 5 | 6 | export default class DemoAnimateCss extends Component { 7 | constructor(props) { 8 | super(props); 9 | 10 | document.title = 'Demo Animate.css'; 11 | } 12 | 13 | render() { 14 | return ( 15 |
16 | 17 |
18 |
19 |
20 | bounceIn 1.0s 21 |
22 |
23 |
24 |
25 | bounceInUp 2.5s 26 |
27 |
28 |
29 |
30 | bounceOut 2.9s 31 |
32 |
33 |
34 | 35 | 36 |
37 |
38 |
39 | fadeIn 1.2s 40 |
41 |
42 |
43 |
44 | fadeInUp 0.7s 45 |
46 |
47 |
48 |
49 | fadeOutDown 2.7s 50 |
51 |
52 |
53 | 54 | 55 |
56 |
57 |
58 | lightSpeedIn 1.7s 59 |
60 |
61 |
62 |
63 | rotateIn 1.0s 64 |
65 |
66 |
67 |
68 | zoomIn 1.4s 69 |
70 |
71 |
72 | 73 | 74 |
75 |
76 |
77 | jackInTheBox 3.0s 78 |
79 |
80 |
81 |
82 | rollIn 2.9s 83 |
84 |
85 |
86 |
87 | bounceOut 1.3s 88 |
89 |
90 |
91 | 92 | 93 |
94 |
95 |
96 | flash 2.3s 97 |
98 |
99 |
100 |
101 | rubberBand 2.6s 102 |
103 |
104 |
105 |
106 | jello 2.5s 107 |
108 |
109 |
110 | 111 | 112 |
113 |
114 |
115 | shake 2.9s 116 |
117 |
118 |
119 |
120 | tada 2.6s 121 |
122 |
123 |
124 |
125 | wobble 2.5s 126 |
127 |
128 |
129 |
130 | ); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/components/pages/demo-animate-css/DemoAnimateCss.scss: -------------------------------------------------------------------------------- 1 | .Animate-CSS { 2 | .box { 3 | margin-top: 15px; 4 | height: 70px; 5 | line-height: 70px; 6 | text-align: center; 7 | padding: 10px; 8 | div.animated { 9 | background-color: #99c1fa; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/pages/demo-bootstrap/DemoBootstrap.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import $ from 'jquery'; 4 | import 'bootstrap'; 5 | /** 6 | * import 'bootstrap'; is unnecessary 7 | * If import, we can see method Bootstrap from $ variable 8 | * such as: $('#modalAlert').modal('hide'); 9 | * We still use this method if not import. 10 | */ 11 | 12 | export default class DemoBootstrap extends Component { 13 | constructor(props) { 14 | super(props); 15 | 16 | document.title = 'Demo Bootstrap'; 17 | this.onClickReceviceAlert = this.onClickReceviceAlert.bind(this); 18 | } 19 | 20 | componentDidMount() { 21 | $('#btnToggle').tooltip(); 22 | } 23 | 24 | onClickReceviceAlert() { 25 | alert('This is alert'); 26 | $('#modalAlert').modal('hide'); 27 | } 28 | 29 | render() { 30 | return ( 31 |
32 | 44 | 45 | 64 |
65 | ); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/components/pages/demo-jquery/DemoJquery.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import $ from 'jquery'; 4 | 5 | import('./DemoJquery.css'); 6 | 7 | export default class DemoJquery extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | document.title = 'Demo Jquery'; 12 | } 13 | 14 | componentDidMount() { 15 | $('#btnToggle').click(() => { 16 | console.log('Toggle'); 17 | const $banner = $('#banner'); 18 | $banner.slideToggle(); 19 | }); 20 | } 21 | 22 | render() { 23 | return ( 24 |
25 | 26 |
27 | 34 |
35 | ); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/components/pages/demo-jquery/DemoJquery.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/variables.scss'; 2 | 3 | .DemoJquery { 4 | .jq-button { 5 | $bg: #134bd0; 6 | padding: 6px 20px; 7 | background-color: $bg; 8 | border-radius: 30px; 9 | border: 2px $bg solid; 10 | color: white; 11 | transition-duration: 0.2s; 12 | outline: none; 13 | margin-bottom: 20px; 14 | cursor: pointer; 15 | &:hover { 16 | background-color: white; 17 | border-radius: 0px; 18 | padding: 6px 50px; 19 | color: $bg; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/pages/demo-loadable-component/DemoLoadableComponent.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export default class DemoLoadableComponent extends Component { 4 | constructor(props) { 5 | super(props); 6 | 7 | document.title = 'Loadable Component'; 8 | } 9 | 10 | render() { 11 | return ( 12 |
Loadable Component
13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/components/pages/demo-loadable-component/LoadableDemoComponent.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Loadable from 'react-loadable'; 3 | import Loading from './../../common/loading/Loading'; 4 | 5 | const LoadableComponent = Loadable({ 6 | loader: () => import('./DemoLoadableComponent.jsx'), 7 | loading: Loading, 8 | delay: 300, // default is 200 9 | timeout: 10000 10 | }); 11 | 12 | export default class LoadableDemoComponent extends Component { 13 | render() { 14 | return ; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-reveal/DemoReactReveal.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Fade, Flip, Rotate, Zoom, Slide, Roll, Bounce, LightSpeed } from 'react-reveal'; 3 | 4 | const style = { 5 | width: '84%', 6 | margin: '25px auto', 7 | textAlign: 'justify' 8 | }; 9 | 10 | export default class DemoReactReveal extends Component { 11 | constructor(props) { 12 | super(props); 13 | 14 | document.title = 'React Reveal'; 15 | 16 | const text = 'One of the best ways to learn how to do anything new (including software APIs!) is to get your hands dirty as quickly as possible. These examples will show you how to perform tasks ranging from something as simple as applying DataTables to an HTML table, right the way through to doing server-side processing with pipelining and custom plug-in functions.'; 17 | 18 | this.repeat = []; 19 | for (let i = 0; i < 1000; i++) this.repeat.push({ id: i, text }); 20 | } 21 | 22 | render() { 23 | return ( 24 |
25 | {this.repeat.map((o, i) => { 26 | const step = 50; 27 | if (i < step) { 28 | return ( 29 | 37 |

{o.text}

38 |
39 | ); 40 | } else if (i < step * 2) { 41 | return ( 42 | 50 |

{o.text}

51 |
52 | ); 53 | } else if (i < step * 3) { 54 | return ( 55 | 63 |

{o.text}

64 |
65 | ); 66 | } else if (i < step * 4) { 67 | return ( 68 | 76 |

{o.text}

77 |
78 | ); 79 | } else if (i < step * 5) { 80 | return ( 81 | 89 |

{o.text}

90 |
91 | ); 92 | } else if (i < step * 6) { 93 | return ( 94 | 102 |

{o.text}

103 |
104 | ); 105 | } else if (i < step * 7) { 106 | return ( 107 | 115 |

{o.text}

116 |
117 | ); 118 | } else if (i < step * 8) { 119 | return ( 120 | 128 |

{o.text}

129 |
130 | ); 131 | } else { 132 | return ( 133 | 141 |

{o.text}

142 |
143 | ); 144 | } 145 | })} 146 |
147 | ); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-router/DemoReactRouter.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'; 4 | import LoadableImage from './LoadableImage'; 5 | import Text from './Text'; 6 | import UserList from './UserList'; 7 | import UserProfile from './UserProfile'; 8 | 9 | const propTypes = { 10 | location: PropTypes.object.isRequired, 11 | match: PropTypes.object.isRequired 12 | }; 13 | 14 | class DemoReactRouter extends Component { 15 | constructor(props) { 16 | super(props); 17 | 18 | document.title = 'Demo React Router'; 19 | 20 | console.log(this.props.location); 21 | console.log(this.props.match); 22 | // example: 23 | // {pathname: "/4", search: "", hash: "", state: undefined, key: "6hvrlm"} 24 | // {path: "/:userID", url: "/4", isExact: true, params: {userID: 4}} 25 | } 26 | 27 | render() { 28 | return ( 29 |
30 | 31 |
32 |
    33 |
  • Loadable Image
  • 34 |
  • Unloadable Text
  • 35 |
  • User List
  • 36 |
  • Go to link not found
  • 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 |
404 Page Not Found
} /> 45 |
46 |
47 |
48 |
49 | ); 50 | } 51 | } 52 | 53 | DemoReactRouter.propTypes = propTypes; 54 | 55 | export default DemoReactRouter; 56 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-router/Images.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Fade, Zoom } from 'react-reveal'; 3 | 4 | export default class Images extends Component { 5 | 6 | constructor(props) { 7 | super(props); 8 | 9 | document.title = 'Images'; 10 | } 11 | 12 | render() { 13 | const array = []; 14 | for (let i = 0; i < 50; i++) array.push(i); 15 | const text = 'One of the best ways to learn how to do anything new (including software APIs!) is to get your hands dirty as quickly as possible. These examples will show you how to perform tasks ranging from something as simple as applying DataTables to an HTML table, right the way through to doing server-side processing with pipelining and custom plug-in functions.'; 16 | return ( 17 |
18 | {array.map(o => 19 | ( 20 |
21 | react 22 | react 23 | react 24 | react 25 | react 26 |
react
27 | react 28 |
29 | ))} 30 |
31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-router/LoadableImage.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Loadable from 'react-loadable'; 3 | import Loading from './../../common/loading/Loading'; 4 | 5 | const LoadableComponent = Loadable({ 6 | loader: () => import('./Images.jsx'), 7 | loading: Loading 8 | }); 9 | 10 | export default class LoadableImage extends Component { 11 | render() { 12 | return ; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-router/Text.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Fade, Zoom } from 'react-reveal'; 3 | 4 | export default class Images extends Component { 5 | 6 | constructor(props) { 7 | super(props); 8 | 9 | document.title = 'Text'; 10 | 11 | const text = 'One of the best ways to learn how to do anything new (including software APIs!) is to get your hands dirty as quickly as possible. These examples will show you how to perform tasks ranging from something as simple as applying DataTables to an HTML table, right the way through to doing server-side processing with pipelining and custom plug-in functions.'; 12 | 13 | this.repeat = []; 14 | for (let i = 0; i < 1000; i++) this.repeat.push({ id: i, text }); 15 | } 16 | 17 | render() { 18 | const text = 'One of the best ways to learn how to do anything new (including software APIs!) is to get your hands dirty as quickly as possible. These examples will show you how to perform tasks ranging from something as simple as applying DataTables to an HTML table, right the way through to doing server-side processing with pipelining and custom plug-in functions.'; 19 | return ( 20 |
21 | {this.repeat.map(o => 22 | (o.id % 2 ? 23 |

{o.text}

: 24 |

{o.text}

)) 25 | } 26 |
27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-router/UserList.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | import { connect } from 'react-redux'; 4 | import PropTypes from 'prop-types'; 5 | import * as Actions from './../../../actions'; 6 | 7 | class UserList extends Component { 8 | 9 | constructor(props) { 10 | super(props); 11 | 12 | document.title = 'User List'; 13 | } 14 | 15 | handleClickRemoveUser(user) { 16 | const res = window.confirm(`Do you want to remove ${user.name}`); 17 | if (res) { 18 | this.props.removeUser(user.id); 19 | } 20 | } 21 | 22 | render() { 23 | 24 | 25 | return ( 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | {this.props.userList.map((o, i) => ( 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 53 | 62 | 63 | ))} 64 | 65 |
#IDEmailNameAddressSalary ($)Action
{i}{o.id}{o.email}{o.name}{o.address}{o.salary} 49 | 50 | 51 | 52 | 54 | { this.handleClickRemoveUser(o); }} 56 | role="button" tabIndex={0} onKeyUp={() => { }} 57 | style={{ cursor: 'pointer' }} 58 | > 59 | 60 | 61 |
66 |
67 | ); 68 | } 69 | } 70 | 71 | UserList.propTypes = { 72 | userList: PropTypes.array, 73 | removeUser: PropTypes.func.isRequired 74 | }; 75 | 76 | UserList.defaultProps = { 77 | userList: [] 78 | }; 79 | 80 | const mapStateToProps = state => ({ 81 | userList: state.Users 82 | }); 83 | 84 | const mapDispatchToProps = dispatch => ({ 85 | removeUser: (userID) => { 86 | dispatch(Actions.removeUser(userID)); 87 | } 88 | }); 89 | 90 | export default connect(mapStateToProps, mapDispatchToProps)(UserList); 91 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-router/UserProfile.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | 5 | 6 | const propTypes = { 7 | match: PropTypes.object.isRequired, 8 | getUser: PropTypes.array.isRequired 9 | }; 10 | 11 | class UserProfile extends Component { 12 | constructor(props) { 13 | super(props); 14 | 15 | this.userID = this.props.match.params.userID; 16 | 17 | this.user = this.props.getUser; 18 | console.log(this.user); 19 | 20 | if (this.user && this.user.length > 0) this.user = this.user[0]; 21 | else this.user = {}; 22 | 23 | document.title = `User ${this.user.name}`; 24 | } 25 | 26 | render() { 27 | return ( 28 |
29 | Hello {this.user.name}, 30 |
31 | ); 32 | } 33 | } 34 | 35 | UserProfile.propTypes = propTypes; 36 | 37 | const mapStateToProps = (state, ownProps) => ({ 38 | getUser: state.Users.filter(o => o.id == ownProps.match.params.userID) 39 | }); 40 | 41 | export default connect(mapStateToProps)(UserProfile); 42 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-scrollchor/DemoReactScrollchor.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Scrollchor from 'react-scrollchor'; 3 | 4 | import('./DemoReactScrollchor.css'); 5 | 6 | const timeScroll = 300; 7 | 8 | function NavBarHeader() { 9 | return ( 10 | 62 | ); 63 | } 64 | 65 | function SectionIntro() { 66 | return ( 67 |
68 |

react-scrollchor

69 |
70 |

A React component for scroll to #hash links with smooth animations. Scrollchor is a mix of Scroll and Anchor, a joke name for a useful component.

71 |
See it in action:
72 | 79 |
hash is the id of a HTML tag on current page.
80 |
81 | Banner react 82 |
83 | ); 84 | } 85 | 86 | function SectionInstall() { 87 | return ( 88 |
89 |

Installation

90 |
91 |
npm
92 | npm install react-scrollchor --save 93 |
94 |
Dependencies
95 |

User should provide their own React package

96 |

fbjs is a collection of utility libraries created by React Team. It include useful modules like warning and invariant

97 |
98 | Node+React 99 |
100 | ); 101 | } 102 | 103 | function SectionUsage() { 104 | return ( 105 |
106 |

Usage

107 |
108 | import Scrollchor from 'react-scrollchor'; 109 |
110 | ); 111 | } 112 | 113 | function SectionImage() { 114 | return ( 115 |
116 |

Image React

117 |
118 | Banner react 119 |
120 | Redux Banner 121 |
122 | Node+React 123 |
124 | ); 125 | } 126 | 127 | function SectionFooter() { 128 | return ( 129 | 134 | ); 135 | } 136 | 137 | export default class DemoReactScrollChor extends Component { 138 | 139 | constructor(props) { 140 | super(props); 141 | 142 | document.title = 'Demo React Scrollchor'; 143 | } 144 | 145 | render() { 146 | return ( 147 |
148 | 149 | 150 | 151 | 152 | 153 | 154 |
155 | ); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-scrollchor/DemoReactScrollchor.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/variables.scss'; 2 | 3 | .DemoReactScrollchor { 4 | width: 100%; 5 | padding: 15px 10px; 6 | border: $blue 2px solid; 7 | position: relative; 8 | 9 | nav { 10 | font-size: $font-size-medium; 11 | position: absolute; 12 | top: 0px; 13 | left: 0px; 14 | width: 100%; 15 | img { 16 | border-radius: 6px; 17 | width: 35px; 18 | height: 35px; 19 | object-fit: cover; 20 | } 21 | } 22 | 23 | padding-top: 40px; 24 | 25 | .app-section { 26 | width: 100%; 27 | padding: 20px 10px; 28 | margin-top: 30px; 29 | &.footer { 30 | padding: 12px; 31 | background-color: $orange; 32 | a { 33 | color: white !important; 34 | font-size: $font-size-medium; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-table/DemoReactTable.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import * as Actions from './../../../actions'; 5 | 6 | import { FormattedDate, FormattedRelative, FormattedPlural } from 'react-intl'; 7 | 8 | import ReactTable from 'react-table'; 9 | import 'react-table/react-table.css'; 10 | 11 | import matchSorter from 'match-sorter'; 12 | 13 | import ModalEditTodo from './ModalEditTodo'; 14 | 15 | import './style.css'; 16 | 17 | const propTypes = { 18 | todos: PropTypes.array, 19 | removeTodo: PropTypes.func.isRequired 20 | }; 21 | 22 | const defaultProps = { 23 | todos: [] 24 | }; 25 | 26 | 27 | class DemoReactTable extends Component { 28 | 29 | constructor(props) { 30 | super(props); 31 | 32 | document.title = 'Demo react-table'; 33 | 34 | this.state = { 35 | modalIsOpen: false, 36 | modalData: {} 37 | }; 38 | 39 | this.toggleModalEdit = this.toggleModalEdit.bind(this); 40 | 41 | console.log(this.props.todos); 42 | } 43 | 44 | onClickRemoveTodo(rowInfo) { 45 | console.log(rowInfo); 46 | const data = rowInfo.row; 47 | const res = window.confirm(`Do you want to remove todo ${data.id}`); 48 | if (res) { 49 | this.props.removeTodo(data.id); 50 | } 51 | } 52 | 53 | onClickEditTodo(rowInfo) { 54 | // console.log(rowInfo); 55 | const data = rowInfo.row; 56 | this.toggleModalEdit(data); 57 | } 58 | 59 | toggleModalEdit(data) { 60 | this.setState({ 61 | modalIsOpen: !this.state.modalIsOpen, 62 | modalData: data 63 | }); 64 | } 65 | 66 | 67 | renderModal() { 68 | return ( 69 | 74 | ); 75 | } 76 | 77 | render() { 78 | 79 | const { todos } = this.props; 80 | 81 | const columns = [ 82 | { 83 | Header: props => ID, 84 | accessor: 'id', 85 | minWidth: 80, 86 | filterAll: true, 87 | id: 'id', 88 | filterMethod: (filter, rows) => matchSorter(rows, filter.value, { keys: ['id'] }) 89 | }, 90 | { 91 | Header: props => Content, 92 | accessor: 'content', 93 | minWidth: 100, 94 | filterAll: true, 95 | id: 'content', 96 | filterMethod: (filter, rows) => matchSorter(rows, filter.value, { keys: ['content'] }) 97 | }, 98 | { 99 | Header: props => Duration, 100 | accessor: 'duration', 101 | maxWidth: 85, 102 | resizable: false, 103 | Cell: props => ( 104 |
105 | {props.value} 106 |
107 | ), 108 | filterAll: true, 109 | id: 'duration', 110 | filterMethod: (filter, rows) => matchSorter(rows, filter.value, { keys: ['duration'] }) 111 | }, 112 | { 113 | Header: props => Date Start, 114 | accessor: 'dateStart', 115 | minWidth: 100, 116 | Cell: props => ( 117 |
118 | 119 |
120 | ) 121 | }, 122 | { 123 | Header: props => Date End, 124 | accessor: 'dateEnd', 125 | minWidth: 100, 126 | Cell: props => ( 127 |
128 | 129 |
130 | ) 131 | }, 132 | { 133 | Header: props => Status, 134 | accessor: 'process', 135 | width: 150, 136 | Cell: props => ( 137 |
145 |
66 ? '#85cc00' 150 | : props.value > 33 ? '#ffbf00' : '#ff2e00', 151 | borderRadius: '2px', 152 | transition: 'all .2s ease-out', 153 | textAlign: 'center', 154 | color: '#fff', 155 | fontWeight: 900, 156 | fontSize: 12, 157 | display: 'table' 158 | }} 159 | > 160 | {props.value}% 161 |
162 |
163 | ), 164 | Filter: ({ filter, onChange }) => ( 165 | 178 | ), 179 | filterMethod: (filter, row) => { 180 | const data = row[filter.id]; 181 | switch (filter.value) { 182 | case 'all': return true; 183 | case '100': return data == 100; 184 | case '67-99': return data > 66 && data < 100; 185 | case '34-66': return data > 33 && data < 67; 186 | case '1-33': return data > 0 && data < 34; 187 | case '0': return data == 0; 188 | default: return false; 189 | } 190 | } 191 | }, 192 | { 193 | Header: '', 194 | width: 30, 195 | filterable: false, 196 | sortable: false, 197 | resizable: false, 198 | id: 'btn-edit', 199 | Cell: props => ( 200 |
201 | 202 | 203 | 204 |
205 | ) 206 | }, 207 | { 208 | Header: '', 209 | width: 30, 210 | filterable: false, 211 | sortable: false, 212 | resizable: false, 213 | id: 'btn-remove', 214 | Cell: props => ( 215 |
216 | 217 | 218 | 219 |
220 | ) 221 | } 222 | ]; 223 | 224 | return ( 225 |
226 |

Todos List

227 | { 234 | const id = filter.pivotId || filter.id; 235 | if (row[id] === undefined) return true; 236 | const data = String(row[id]).toLowerCase().trim(); 237 | const text = String(filter.value).toLowerCase().trim(); 238 | return data.includes(text); 239 | }} 240 | noDataText="No anything found" 241 | className="-striped -highlight react-table" 242 | getTdProps={(state, rowInfo, column) => ({ 243 | onClick: (e) => { 244 | console.log(state); 245 | console.log(column); 246 | console.log(rowInfo); 247 | switch (column.id) { 248 | case 'btn-remove': return this.onClickRemoveTodo(rowInfo); 249 | case 'btn-edit': return this.onClickEditTodo(rowInfo); 250 | } 251 | } 252 | })} 253 | /> 254 | 255 | {this.renderModal()} 256 |
257 | ); 258 | } 259 | } 260 | 261 | DemoReactTable.propTypes = propTypes; 262 | DemoReactTable.defaultProps = defaultProps; 263 | 264 | const mapStateToProps = state => ({ 265 | todos: state.Todos 266 | }); 267 | 268 | const mapDispatchToProps = dispatch => ({ 269 | removeTodo: id => dispatch(Actions.removeTodo(id)) 270 | }); 271 | 272 | export default connect(mapStateToProps, mapDispatchToProps)(DemoReactTable); 273 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-table/ModalEditTodo.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import * as Actions from './../../../actions'; 5 | 6 | import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; 7 | 8 | import Select from 'react-select'; 9 | import 'react-select/dist/react-select.css'; 10 | 11 | import DatePicker from 'react-datepicker'; 12 | import 'react-datepicker/dist/react-datepicker.css'; 13 | // import 'react-datepicker/dist/react-datepicker-cssmodules.css'; 14 | 15 | import moment from 'moment'; 16 | 17 | 18 | class ModalEditTodo extends Component { 19 | 20 | constructor(props) { 21 | super(props); 22 | 23 | this.processOptions = []; 24 | for (let i = 0; i < 101; i++) this.processOptions.push({ 25 | value: `${i}`, label: `${i}%` 26 | }); 27 | 28 | this.durationOptions = []; 29 | for (let i = 1; i < 900; i++) this.durationOptions.push({ 30 | value: `${i}`, label: i + (i == 1 ? ' day' : ' days') 31 | }); 32 | 33 | this.state = { 34 | process: 0, 35 | content: '', 36 | duration: 0, 37 | dateStart: moment(), 38 | dateEnd: moment() 39 | }; 40 | 41 | this.handleChangeContent = this.handleChangeContent.bind(this); 42 | this.handleChangeProcess = this.handleChangeProcess.bind(this); 43 | this.handleChangeDuration = this.handleChangeDuration.bind(this); 44 | this.handleChangeDateStart = this.handleChangeDateStart.bind(this); 45 | this.handleChangeDateEnd = this.handleChangeDateEnd.bind(this); 46 | this.onSave = this.onSave.bind(this); 47 | this.onCancle = this.onCancle.bind(this); 48 | } 49 | 50 | componentWillReceiveProps(nextProps) { 51 | const { data } = nextProps; 52 | 53 | const process = data.process && this.processOptions.filter(o => o.value == data.process)[0]; 54 | const duration = data.duration && this.durationOptions.filter(o => o.value == data.duration)[0]; 55 | 56 | this.setState({ 57 | process, 58 | duration, 59 | content: data.content, 60 | dateStart: moment(data.dateStart || new Date()), 61 | dateEnd: moment(data.dateEnd || new Date()) 62 | }); 63 | } 64 | 65 | onSave() { 66 | const res = window.confirm('Do you want to save with your edition?'); 67 | if (res) { 68 | const newTodo = { 69 | content: this.state.content, 70 | process: parseInt(this.state.process.value, 10), 71 | duration: parseInt(this.state.duration.value, 10), 72 | dateStart: this.state.dateStart.toDate(), 73 | dateEnd: this.state.dateEnd.toDate() 74 | }; 75 | // console.log(newTodo); 76 | this.props.modifyTodo(this.props.data.id, newTodo); 77 | this.props.toggle(); 78 | } 79 | } 80 | 81 | onCancle() { 82 | const res = window.confirm('Do you want to close without saving your edtion?'); 83 | if (res) { 84 | this.props.toggle(); 85 | } 86 | } 87 | 88 | handleChangeContent(event) { 89 | this.setState({ content: event.target.value }); 90 | } 91 | 92 | handleChangeProcess(process) { 93 | this.setState({ process }); 94 | } 95 | 96 | syncDurationAfterSetDate() { 97 | console.log('syncDurationAfterSetDate'); 98 | const diff = this.state.dateEnd.diff(this.state.dateStart); 99 | // console.log(diff); 100 | const days = moment.duration(diff).asDays(); 101 | // console.log(days); 102 | const duration = this.durationOptions.filter(o => o.value == days)[0]; 103 | // console.log(duration); 104 | this.setState({ duration }); 105 | } 106 | 107 | handleChangeDuration(duration) { 108 | console.log('handleChangeDuration'); 109 | const days = duration.value; 110 | const dateEnd = this.state.dateStart.clone(); 111 | dateEnd.add(days, 'days'); 112 | console.log(dateEnd); 113 | this.setState({ dateEnd }, () => this.syncDurationAfterSetDate()); 114 | } 115 | 116 | handleChangeDateStart(dateStart) { 117 | console.log('handleChangeDateStart'); 118 | this.setState({ dateStart }, () => this.syncDurationAfterSetDate()); 119 | } 120 | 121 | handleChangeDateEnd(dateEnd) { 122 | console.log('handleChangeDa(teEnd'); 123 | this.setState({ dateEnd }, () => this.syncDurationAfterSetDate()); 124 | } 125 | 126 | renderFormEdit() { 127 | return ( 128 |
129 |
130 | 131 |
132 | 133 |
134 |
135 | 136 |
137 | 138 |
139 | 144 |
145 |
146 | 147 |
148 | 149 |
150 | 151 |
152 |
153 | 154 |
155 | 163 |
164 |
165 | 166 |
167 | 168 |
169 | 177 |
178 |
179 |
180 | 181 |
182 |
183 | 184 |
185 | 201 |
202 |
203 |
204 |
205 |
206 | ); 207 | } 208 | 209 | render() { 210 | return ( 211 | 212 | Edit Todo 213 | 214 | {this.renderFormEdit()} 215 | 216 | 217 | {' '} 218 | 219 | 220 | 221 | ); 222 | } 223 | } 224 | 225 | ModalEditTodo.propTypes = { 226 | data: PropTypes.object, 227 | isOpen: PropTypes.bool.isRequired, 228 | toggle: PropTypes.func, 229 | modifyTodo: PropTypes.func.isRequired 230 | }; 231 | 232 | ModalEditTodo.defaultProps = { 233 | data: {}, 234 | toggle: () => { } 235 | }; 236 | 237 | const mapStateToProps = state => ({ 238 | }); 239 | 240 | const mapDispatchToProps = dispatch => ({ 241 | modifyTodo: (id, newTodo) => dispatch(Actions.modifyTodo(id, newTodo)) 242 | }); 243 | 244 | export default connect(mapStateToProps, mapDispatchToProps)(ModalEditTodo); 245 | -------------------------------------------------------------------------------- /src/components/pages/demo-react-table/style.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/variables.scss'; 2 | 3 | .ReactTable { 4 | background-color: rgb(245, 245, 245); 5 | padding: 25px 5px; 6 | 7 | .react-table { 8 | font-size: $font-size-small; 9 | 10 | .tb-header { 11 | font-weight: 900; 12 | } 13 | 14 | .tb-cell { 15 | &.tb-buttons { 16 | width: 100%; 17 | height: 16px; 18 | font-size: 16px; 19 | span.tb-button { 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/pages/demo-reactstrap/DemoReactstrap.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Collapse, Button, CardBody, Card } from 'reactstrap'; 3 | 4 | export default class DemoReactstrap extends Component { 5 | constructor(props) { 6 | super(props); 7 | 8 | document.title = 'Demo Reactstrap'; 9 | 10 | this.toggle = this.toggle.bind(this); 11 | this.state = { collapse: false }; 12 | } 13 | 14 | toggle() { 15 | this.setState({ collapse: !this.state.collapse }); 16 | } 17 | 18 | render() { 19 | return ( 20 |
21 | 22 | 23 | 24 | 25 | Banner React 30 | 31 | 32 | 33 |
34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/pages/demo-redux/DemoRedux.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import ItemTable from './ItemTable'; 4 | import FormAddItem from './FormAddItem'; 5 | 6 | export default class DemoRedux extends Component { 7 | constructor(props) { 8 | super(props); 9 | 10 | document.title = 'Demo Redux'; 11 | } 12 | 13 | render() { 14 | return ( 15 |
16 | 17 | 18 |
19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/pages/demo-redux/FormAddItem.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import * as Actions from './../../../actions'; 5 | import { Col, Button, Form, FormGroup, Label, Input } from 'reactstrap'; 6 | 7 | const propTypes = { 8 | addItem: PropTypes.func.isRequired 9 | }; 10 | 11 | class FormAddItem extends Component { 12 | constructor(props) { 13 | super(props); 14 | 15 | this.item = { 16 | name: null, leave: null, price: null 17 | }; 18 | 19 | this.onClickAddItem = this.onClickAddItem.bind(this); 20 | } 21 | 22 | onClickAddItem() { 23 | // create new item, not pass one object is this.item (as redux) 24 | const newItem = { ...this.item }; 25 | this.props.addItem(newItem); 26 | } 27 | 28 | render() { 29 | return ( 30 |
31 |
32 | 33 | 34 | 35 | { this.item.name = e.target.value; }} 41 | /> 42 | 43 | 44 |
45 | 46 |
47 | 48 | 49 | 50 | { this.item.leave = e.target.value; }} 56 | /> 57 | 58 | 59 |
60 | 61 |
62 | 63 | 64 | 65 | { this.item.price = e.target.value; }} 71 | /> 72 | 73 | 74 |
75 | 76 |
77 | 78 | 79 | 80 | 81 | 82 |
83 |
84 | ); 85 | } 86 | } 87 | 88 | FormAddItem.propTypes = propTypes; 89 | 90 | const mapStateToProps = state => ({}); 91 | 92 | const mapDispatchToProps = dispatch => ({ 93 | addItem: (item) => { 94 | dispatch(Actions.addItem(item)); 95 | } 96 | }); 97 | 98 | export default connect(mapStateToProps, mapDispatchToProps)(FormAddItem); 99 | -------------------------------------------------------------------------------- /src/components/pages/demo-redux/ItemTable.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import { Table } from 'reactstrap'; 5 | import * as Actions from './../../../actions'; 6 | import { FormattedDate } from 'react-intl'; 7 | 8 | const propTypes = { 9 | removeItem: PropTypes.func.isRequired, 10 | moveItem: PropTypes.func.isRequired, 11 | items: PropTypes.array 12 | }; 13 | 14 | const defaultProps = { 15 | items: [] 16 | }; 17 | 18 | class ItemTable extends Component { 19 | constructor(props) { 20 | super(props); 21 | 22 | document.title = 'Demo Redux'; 23 | 24 | this.handleRemoveItem = this.handleRemoveItem.bind(this); 25 | this.handleMoveUpItem = this.handleMoveUpItem.bind(this); 26 | this.handleMoveDownItem = this.handleMoveDownItem.bind(this); 27 | } 28 | 29 | handleRemoveItem(id) { 30 | this.props.removeItem(id); 31 | } 32 | 33 | handleMoveUpItem(id) { 34 | this.props.moveItem(id, true); 35 | } 36 | 37 | handleMoveDownItem(id) { 38 | this.props.moveItem(id, false); 39 | } 40 | 41 | render() { 42 | 43 | const styleBtnFA = { 44 | cursor: 'pointer' 45 | }; 46 | 47 | return ( 48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {this.props.items.map((o, i) => 63 | ( 64 | 65 | 66 | 67 | 68 | 76 | 77 | 78 | 79 | 87 | 88 | 96 | 97 | 105 | 106 | ))} 107 | 108 |
#IDNameDateLeavePriceAction
{i}{o.id}{o.name} 69 | 75 | {o.leave}{o.price} 80 | this.handleMoveUpItem(o.id)} 83 | onKeyDown={() => { }} role="button" tabIndex={0} 84 | style={styleBtnFA} 85 | /> 86 | 89 | this.handleMoveDownItem(o.id)} 92 | onKeyDown={() => { }} role="button" tabIndex={0} 93 | style={styleBtnFA} 94 | /> 95 | 98 | this.handleRemoveItem(o.id)} 101 | onKeyDown={this.onKey} role="button" tabIndex={0} 102 | style={styleBtnFA} 103 | /> 104 |
109 |
110 | ); 111 | } 112 | 113 | } 114 | 115 | ItemTable.propTypes = propTypes; 116 | ItemTable.defaultProps = defaultProps; 117 | 118 | const mapStateToProps = state => ({ 119 | items: state.Items 120 | }); 121 | 122 | const mapDispatchToProps = dispatch => ({ 123 | removeItem: (id) => { 124 | dispatch(Actions.removeItem(id)); 125 | }, 126 | moveItem: (id, isUp) => { 127 | dispatch(Actions.moveItem(id, isUp)); 128 | } 129 | }); 130 | 131 | export default connect(mapStateToProps, mapDispatchToProps)(ItemTable); 132 | -------------------------------------------------------------------------------- /src/components/pages/lifecycle-component.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export default class LifeCycleComponent extends Component { 5 | 6 | constructor(props) { 7 | super(props); 8 | 9 | document.title = 'Life Cycle Component'; 10 | 11 | console.log('contructor'); 12 | } 13 | 14 | componentWillMount() { 15 | console.log('componentWillMount'); 16 | } 17 | 18 | componentDidMount() { 19 | console.log('componentDidMount'); 20 | } 21 | 22 | componentWillReceiveProps() { 23 | console.log('componentWillReceiveProps'); 24 | } 25 | 26 | shouldComponentUpdate() { 27 | console.log('shouldComponentUpdate'); 28 | } 29 | 30 | componentWillUpdate() { 31 | console.log('componentWillUpdate'); 32 | } 33 | 34 | componentDidUpdate() { 35 | console.log('componentDidUpdate'); 36 | } 37 | 38 | componentWillUnmount() { 39 | console.log('componentWillUnmount'); 40 | } 41 | 42 | render() { 43 | return ( 44 |
45 |

46 | This is demo Life Cycle of React Component 47 |

48 |
49 |

View Console from Browser to view life cycle component

50 |
51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/environments/env.development.js: -------------------------------------------------------------------------------- 1 | export default { 2 | baseUrl: 'http://localhost:4200' 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/env.production.js: -------------------------------------------------------------------------------- 1 | export default { 2 | baseUrl: '' 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/index.js: -------------------------------------------------------------------------------- 1 | import envDev from './env.development'; 2 | import envProd from './env.production'; 3 | 4 | let Env; 5 | 6 | if (process.env.REACT_APP_ENV == 'development') { 7 | Env = envDev; 8 | } else if (process.env.REACT_APP_ENV == 'production') { 9 | Env = envProd; 10 | } 11 | 12 | export default Env; 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import { createStore, applyMiddleware } from 'redux'; 5 | import thunk from 'redux-thunk'; 6 | import { IntlProvider } from 'react-intl'; 7 | 8 | // Libs 9 | import './lib'; 10 | 11 | // Styles 12 | import './styles/index.css'; 13 | 14 | // Components 15 | import App from './components/layout/App'; 16 | import registerServiceWorker from './registerServiceWorker'; 17 | 18 | // Config redux 19 | import allReducers from './reducers'; 20 | 21 | const store = createStore(allReducers, applyMiddleware(thunk)); 22 | 23 | ReactDOM.render( 24 | 25 | 26 | 27 | 28 | 29 | , 30 | 31 | document.getElementById('root') 32 | ); 33 | 34 | registerServiceWorker(); 35 | -------------------------------------------------------------------------------- /src/lib/animate.css.js: -------------------------------------------------------------------------------- 1 | import 'animate.css'; 2 | -------------------------------------------------------------------------------- /src/lib/bootstrap.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/css/bootstrap.min.css'; 2 | import 'bootstrap/dist/js/bootstrap.bundle.min.js'; 3 | -------------------------------------------------------------------------------- /src/lib/font-awesome.js: -------------------------------------------------------------------------------- 1 | import 'font-awesome/css/font-awesome.min.css'; 2 | -------------------------------------------------------------------------------- /src/lib/index.js: -------------------------------------------------------------------------------- 1 | import './jquery'; 2 | import './bootstrap'; 3 | import './font-awesome'; 4 | import './animate.css'; 5 | -------------------------------------------------------------------------------- /src/lib/jquery.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | 3 | // config jquery variables for other lib use jQuery (such as bootstrap) 4 | window.$ = $; 5 | window.jQuery = $; 6 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | 3 | import Items from './items'; 4 | import Users from './users'; 5 | import Todos from './todos'; 6 | 7 | const reducers = combineReducers({ 8 | Items, 9 | Users, 10 | Todos 11 | }); 12 | 13 | export default reducers; 14 | -------------------------------------------------------------------------------- /src/reducers/items.js: -------------------------------------------------------------------------------- 1 | import actionTypes from '../actions/action-types'; 2 | 3 | const initialState = []; 4 | 5 | function toHex(input) { 6 | var hash = '', 7 | alphabet = '0123456789abcdef', 8 | alphabetLength = alphabet.length; 9 | 10 | do { 11 | hash = alphabet[input % alphabetLength] + hash; 12 | input = parseInt(input / alphabetLength, 10); 13 | } while (input); 14 | 15 | return hash; 16 | } 17 | 18 | let currentID = 0; 19 | 20 | function nextID() { 21 | return toHex((++currentID) * 199999999).toUpperCase(); 22 | } 23 | 24 | for (let i = 0; i < 10; i++) initialState.push({ 25 | id: nextID(), 26 | name: `Item ${i}`, 27 | leave: i * 20, 28 | price: i * 8521 + (20 - i) * 1958, 29 | date: new Date(2018, i % 12, i * 197 % 28 + 1) 30 | }); 31 | 32 | const reducer = (state = initialState, action) => { 33 | 34 | switch (action.type) { 35 | 36 | case actionTypes.ADD_ITEM: 37 | const { item } = action; 38 | item.id = nextID(); 39 | item.date = new Date(); 40 | console.log(item); 41 | return [...state, item]; 42 | 43 | case actionTypes.REMOVE_ITEM: 44 | return state.filter((o, i) => o.id !== action.id); 45 | 46 | case actionTypes.EDIT_ITEM: 47 | return state.map((item, idx) => { 48 | if (item.id !== action.id) return item; 49 | return { ...item, ...action.newItem }; 50 | }); 51 | 52 | case actionTypes.MOVE_ITEM: 53 | const { id, isUp } = action; 54 | const srcItem = state.filter(o => o.id == id)[0]; 55 | let idx = state.indexOf(srcItem); 56 | if (isUp) { 57 | if (idx == 0) return state; 58 | const tarItem = state[--idx]; 59 | return [ 60 | ...state.slice(0, idx), 61 | { ...srcItem }, 62 | { ...tarItem }, 63 | ...state.slice(idx + 2) 64 | ]; 65 | } else { 66 | if (idx == state.length - 1) return state; 67 | const tarItem = state[idx + 1]; 68 | return [ 69 | ...state.slice(0, idx), 70 | { ...tarItem }, 71 | { ...srcItem }, 72 | ...state.slice(idx + 2) 73 | ]; 74 | } 75 | 76 | default: 77 | return state; 78 | } 79 | }; 80 | 81 | export default reducer; 82 | -------------------------------------------------------------------------------- /src/reducers/todos.js: -------------------------------------------------------------------------------- 1 | import actionTypes from '../actions/action-types'; 2 | import uniqid from 'uniqid'; 3 | 4 | const baseActions = [ 5 | 'Find out', 'Learn', 'Practice', 'Review', 'Build prject', 'Guide', 'Present' 6 | ]; 7 | const baseObjects = [ 8 | 'React', 'React Native', 'AngularJS', 'Angular 2', 'Angular 4', 'Angular 5', 'VueJS', 'EmberJS', 9 | 'SQL', 'MySql', 'Postgres SQL', 'SQL Server', 'MSSQL', 'Oracle SQL', 'MongoDB', 10 | 'NodeJS', 'PHP', 'Java', 'C++', 'Python', 'Go', 'Ruby', 'Objective-C', 'Android', 'iOS', 11 | 'C#', 'ASP.net' 12 | ]; 13 | 14 | const todoList = []; 15 | 16 | for (let i = 0; i < baseActions.length; i++) 17 | for (let j = 0; j < baseObjects.length; j++) { 18 | const num = i * baseActions.length + j; 19 | const action = baseActions[i]; 20 | const object = baseObjects[j]; 21 | const yyyy = 2015 + j % 4, 22 | mm = num % 12, 23 | dd = num * 1999999 % 29; 24 | const duration = i * 5 + (baseActions.length - i) * 3; 25 | const dateStart = new Date(yyyy, mm, dd); 26 | const dateEnd = new Date(dateStart.getTime() + duration * 86400000); 27 | const process = (num * 199997 + Math.round(Math.random() * 1999997)) % 101; 28 | todoList.push({ 29 | id: uniqid.time().toUpperCase(), 30 | content: `${action} ${object}`, 31 | duration, 32 | dateStart, 33 | dateEnd, 34 | process 35 | }); 36 | } 37 | 38 | const initialState = todoList; 39 | 40 | const reducer = (state = initialState, action) => { 41 | switch (action.type) { 42 | case actionTypes.ADD_TODO: 43 | return [...state, action.newTodo]; 44 | 45 | case actionTypes.REMOVE_TODO: 46 | return state.filter(o => o.id !== action.id); 47 | 48 | case actionTypes.DONE_TODO: 49 | return state.map((o) => { 50 | if (o.id != action.id) return o; 51 | return { ...o, done: action.isDone }; 52 | }); 53 | 54 | case actionTypes.MODIFY_TODO: 55 | console.log(action); 56 | return state.map((o) => { 57 | if (o.id != action.id) return o; 58 | return { ...o, ...action.newTodo }; 59 | }); 60 | 61 | default: 62 | return state; 63 | } 64 | }; 65 | 66 | export default reducer; 67 | -------------------------------------------------------------------------------- /src/reducers/users.js: -------------------------------------------------------------------------------- 1 | import actionTypes from '../actions/action-types'; 2 | 3 | const userList = []; 4 | for (let i = 0; i < 100; i++) { 5 | userList.push({ 6 | id: i, 7 | name: `User ${i}`, 8 | email: `user-${i}@gmail.com`, 9 | salary: i * 975 + (100 - i) * 285, 10 | address: `Street ${100 - i}` 11 | }); 12 | } 13 | 14 | const initialState = userList; 15 | 16 | const reducer = (state = initialState, action) => { 17 | switch (action.type) { 18 | case actionTypes.REMOVE_USER: 19 | return state.filter(o => o.id != action.id); 20 | default: 21 | return state; 22 | } 23 | }; 24 | 25 | export default reducer; 26 | -------------------------------------------------------------------------------- /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(window.location.hostname === 'localhost' || 12 | // [::1] is the IPv6 localhost address. 13 | window.location.hostname === '[::1]' || 14 | // 127.0.0.1/8 is considered localhost for IPv4. 15 | window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)); 16 | 17 | export default function register() { 18 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 19 | // The URL constructor is available in all browsers that support SW. 20 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 21 | if (publicUrl.origin !== window.location.origin) { 22 | // Our service worker won't work if PUBLIC_URL is on a different origin 23 | // from what our page is served on. This might happen if a CDN is used to 24 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 25 | return; 26 | } 27 | 28 | window.addEventListener('load', () => { 29 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 30 | 31 | if (isLocalhost) { 32 | // This is running on localhost. Lets check if a service worker still exists or not. 33 | checkValidServiceWorker(swUrl); 34 | 35 | // Add some additional logging to localhost, pointing developers to the 36 | // service worker/PWA documentation. 37 | navigator.serviceWorker.ready.then(() => { 38 | console.log('This web app is being served cache-first by a service ' + 39 | 'worker. To learn more, visit https://goo.gl/SC7cgQ'); 40 | }); 41 | } else { 42 | // Is not local host. Just register service worker 43 | registerValidSW(swUrl); 44 | } 45 | }); 46 | } 47 | } 48 | 49 | function registerValidSW(swUrl) { 50 | navigator.serviceWorker 51 | .register(swUrl) 52 | .then((registration) => { 53 | registration.onupdatefound = () => { 54 | const installingWorker = registration.installing; 55 | installingWorker.onstatechange = () => { 56 | if (installingWorker.state === 'installed') { 57 | if (navigator.serviceWorker.controller) { 58 | // At this point, the old content will have been purged and 59 | // the fresh content will have been added to the cache. 60 | // It's the perfect time to display a "New content is 61 | // available; please refresh." message in your web app. 62 | console.log('New content is available; please refresh.'); 63 | } else { 64 | // At this point, everything has been precached. 65 | // It's the perfect time to display a 66 | // "Content is cached for offline use." message. 67 | console.log('Content is cached for offline use.'); 68 | } 69 | } 70 | }; 71 | }; 72 | }) 73 | .catch((error) => { 74 | console.error('Error during service worker registration:', error); 75 | }); 76 | } 77 | 78 | function checkValidServiceWorker(swUrl) { 79 | // Check if the service worker can be found. If it can't reload the page. 80 | fetch(swUrl) 81 | .then((response) => { 82 | // Ensure service worker exists, and that we really are getting a JS file. 83 | if ( 84 | response.status === 404 || 85 | response.headers.get('content-type').indexOf('javascript') === -1 86 | ) { 87 | // No service worker found. Probably a different app. Reload the page. 88 | navigator.serviceWorker.ready.then((registration) => { 89 | registration.unregister().then(() => { 90 | window.location.reload(); 91 | }); 92 | }); 93 | } else { 94 | // Service worker found. Proceed as normal. 95 | registerValidSW(swUrl); 96 | } 97 | }) 98 | .catch(() => { 99 | console.log('No internet connection found. App is running in offline mode.'); 100 | }); 101 | } 102 | 103 | export function unregister() { 104 | if ('serviceWorker' in navigator) { 105 | navigator.serviceWorker.ready.then((registration) => { 106 | registration.unregister(); 107 | }); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/services/auth-service.js: -------------------------------------------------------------------------------- 1 | import Env from './../environments'; 2 | 3 | export class AuthService { 4 | 5 | static baseUrl() { return Env.baseUrl; } 6 | static parseUrl(url) { return AuthService.baseUrl() + url; } 7 | 8 | } 9 | 10 | export default AuthService; 11 | -------------------------------------------------------------------------------- /src/services/db-service.js: -------------------------------------------------------------------------------- 1 | import Env from './../environments'; 2 | 3 | export default class DbService { 4 | 5 | static baseUrl() { return Env.baseUrl; } 6 | static parseUrl(url) { return DbService.baseUrl() + url; } 7 | 8 | static getItems() { 9 | const url = DbService.parseUrl('/api/items'); 10 | console.log(url); 11 | return fetch(url).then(res => res.json()); 12 | } 13 | 14 | static addItem(item) { 15 | const url = DbService.parseUrl('/api/items'); 16 | return fetch(url, { 17 | method: 'POST', 18 | headers: { 19 | 'Accept': 'application/json', 20 | 'Content-Type': 'application/json' 21 | }, 22 | body: JSON.stringify(item) 23 | }).then(res => res.json()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/services/util-service.js: -------------------------------------------------------------------------------- 1 | export default class UtilService { 2 | // stuff something here, e.g. 3 | } 4 | -------------------------------------------------------------------------------- /src/styles/_animate.scss: -------------------------------------------------------------------------------- 1 | /* custom lib animate.css */ 2 | 3 | /* 4 | from 0.1s to 3s with step 0.1s 5 | generated classes: 6 | .animated.duration-100 7 | .animated.duration-200 8 | ... 9 | .animated.duration-1100 10 | .animated.duration-1200 11 | ... 12 | .animated.duration-3000 13 | */ 14 | 15 | @for $i from 1 through 30 { 16 | 17 | $suffix: $i * 100; 18 | 19 | $time: $i / 10; 20 | 21 | .animated.duration-#{$suffix} { 22 | animation-duration: #{$time}s; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/styles/_classes.scss: -------------------------------------------------------------------------------- 1 | /** 2 | |-------------------------------------------------- 3 | | You can add or/and custom your global classes here 4 | |-------------------------------------------------- 5 | */ 6 | 7 | .fontRoboto { 8 | font-family: $font-family-Roboto; 9 | } 10 | 11 | .fontOpenSans { 12 | font-family: $font-family-Open-Sans; 13 | } 14 | 15 | .fontNunito { 16 | font-family: $font-family-Nunito; 17 | } 18 | 19 | .fontExtraSmall { 20 | font-size: $font-size-extra-small; 21 | } 22 | 23 | .fontSmall { 24 | font-size: $font-size-small; 25 | } 26 | 27 | .fontNormal { 28 | font-size: $font-size-normal; 29 | } 30 | 31 | .fontMedium { 32 | font-size: $font-size-medium; 33 | } 34 | 35 | .fontLarge { 36 | font-size: $font-size-large; 37 | } 38 | 39 | .fontExtraLarge { 40 | font-size: $font-size-extra-large; 41 | } 42 | 43 | .cursorPointer { 44 | cursor: pointer; 45 | } 46 | 47 | .cursorNotAllowed { 48 | cursor: not-allowed 49 | } 50 | 51 | .cursorCrosshair { 52 | cursor: crosshair; 53 | } 54 | -------------------------------------------------------------------------------- /src/styles/_mixins.scss: -------------------------------------------------------------------------------- 1 | /** 2 | |-------------------------------------------------- 3 | | You can add or/and custom your mixins here 4 | |-------------------------------------------------- 5 | */ 6 | 7 | @mixin arrow-up($size, $color) { 8 | width: 0; 9 | height: 0; 10 | border-left: $size solid transparent; 11 | border-right: $size solid transparent; 12 | 13 | border-bottom: $size solid $color; 14 | } 15 | 16 | @mixin arrow-down($size, $color) { 17 | width: 0; 18 | height: 0; 19 | border-left: $size solid transparent; 20 | border-right: $size solid transparent; 21 | 22 | border-top: $size solid $color; 23 | } 24 | 25 | @mixin arrow-left($size, $color) { 26 | width: 0; 27 | height: 0; 28 | border-top: $size solid transparent; 29 | border-bottom: $size solid transparent; 30 | 31 | border-right: $size solid $color; 32 | } 33 | 34 | @mixin arrow-right($size, $color) { 35 | width: 0; 36 | height: 0; 37 | border-top: $size solid transparent; 38 | border-bottom: $size solid transparent; 39 | 40 | border-left: $size solid $color; 41 | } 42 | -------------------------------------------------------------------------------- /src/styles/_variables.scss: -------------------------------------------------------------------------------- 1 | /** 2 | |-------------------------------------------------- 3 | | You can add and/or custom your global variable here 4 | |-------------------------------------------------- 5 | */ 6 | 7 | // FONT SIZE GLOBAL 8 | $font-size: 16px; 9 | $font-size-extra-small: 0.7rem; 10 | $font-size-small: 0.8rem; 11 | $font-size-normal: 1rem; 12 | $font-size-medium: 1.2rem; 13 | $font-size-large: 1.5rem; 14 | $font-size-extra-large: 2rem; 15 | 16 | // FONT FAMILY GLOBAL 17 | $font-family-Roboto: 'Roboto', sans-serif; 18 | $font-family-Nunito: 'Nunito', sans-serif; 19 | $font-family-Open-Sans: 'Open Sans', sans-serif; 20 | 21 | // COLOR GLOBAL 22 | $red: #dd4b39; 23 | $orange: #FF851B; 24 | $purple: #605ca8; 25 | $blue: #0073b7; 26 | $green: #00a65a; 27 | $navy: #001F3F; 28 | 29 | $color-primary: $purple; 30 | $color-success: $green; 31 | $color-info: $blue; 32 | $color-warning: $orange; 33 | $color-dander: $red; 34 | 35 | // Z INDEX 36 | $z-index-base: 500; 37 | $z-index-min: $z-index-base - 500; 38 | $z-index-max: $z-index-base + 500; 39 | -------------------------------------------------------------------------------- /src/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import './variables.scss'; 2 | @import './mixins.scss'; 3 | @import './classes.scss'; 4 | @import './animate.scss'; 5 | 6 | /** 7 | |-------------------------------------------------- 8 | | You can style your app here 9 | |-------------------------------------------------- 10 | */ 11 | 12 | html, 13 | body { 14 | width: 100% !important; 15 | height: 100% !important; 16 | font-size: $font-size; 17 | line-height: initial; 18 | } 19 | 20 | body { 21 | margin: 0px; 22 | padding: 0px; 23 | font-family: $font-family-Nunito; 24 | background-color: #e9e9e9; 25 | } 26 | 27 | h1, h2, h3, h4, h5, h6 { 28 | font-weight: 900; 29 | font-family: $font-family-Roboto; 30 | } 31 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const a = 5; 2 | const b = 9; 3 | 4 | const c = () => { 5 | 6 | 7 | console.log('object'); 8 | 9 | 10 | }; 11 | --------------------------------------------------------------------------------