├── .babelrc
├── .bitmap
├── .circleci
└── config.yml
├── .eslintrc.js
├── .gitattributes
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .gitmodules
├── .vscode
└── settings.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── bit.json
├── docs
├── Account Ownership Diagram Template.png
├── Design Document.vsdx
├── Document_2018-07-16_21-57-33.png
├── components
│ ├── ReadMe.md
│ └── notifications
│ │ └── ReadMe.md
├── development
│ ├── Async.md
│ ├── Dev code block.md
│ ├── ReadMe.md
│ ├── Run and Package.md
│ └── TypeScript.md
├── environments
│ ├── Azure Service Fabric.md
│ ├── Docker.md
│ ├── GZIP and SSL.md
│ ├── IIS.md
│ ├── NodeJs.md
│ └── ReadMe.md
├── index.md
└── styles
│ ├── LESS.md
│ ├── ReadMe.md
│ └── SCSS.md
├── package.json
├── postcss.config.js
├── src
├── actions
│ ├── Dashboard
│ │ ├── DashboardActions.js
│ │ ├── DashboardReducer.js
│ │ └── index.js
│ ├── MessageBox
│ │ ├── MessageBoxActions.js
│ │ ├── MessageBoxReducer.js
│ │ └── index.js
│ ├── Notifications
│ │ ├── NotificationActions.js
│ │ ├── NotificationReducer.js
│ │ └── index.js
│ └── Users
│ │ ├── UserActions.js
│ │ ├── UserReducer.js
│ │ └── index.js
├── api
│ ├── chartApi.js
│ ├── generalApi.js
│ ├── index.js
│ └── userApi.js
├── assets
│ ├── img
│ │ ├── apple-icon.png
│ │ ├── cover.jpeg
│ │ ├── faces
│ │ │ └── marc.jpg
│ │ ├── favicon.png
│ │ ├── mask.png
│ │ ├── new_logo.png
│ │ ├── react_logo.svg
│ │ ├── sidebar-1.jpg
│ │ ├── sidebar-2.jpg
│ │ ├── sidebar-3.jpg
│ │ ├── sidebar-4.jpg
│ │ └── tim_80x80.png
│ ├── jss
│ │ ├── material-dashboard-react.jsx
│ │ └── material-dashboard-react
│ │ │ ├── cardImagesStyles.jsx
│ │ │ ├── checkboxAdnRadioStyle.jsx
│ │ │ ├── dropdownStyle.jsx
│ │ │ └── tooltipStyle.jsx
│ ├── less
│ │ └── material-dashboard-react.less
│ └── scss
│ │ └── material-dashboard-react.scss
├── commons
│ ├── checks.js.ignore
│ ├── commonControlRenderers.jsx
│ ├── commonFuncs.ts
│ ├── constants.js
│ ├── exceptionService.js
│ └── guard.js
├── components
│ ├── Card
│ │ ├── Card.jsx
│ │ ├── CardAvatar.jsx
│ │ ├── CardBody.jsx
│ │ ├── CardFooter.jsx
│ │ ├── CardHeader.jsx
│ │ ├── CardIcon.jsx
│ │ ├── cardAvatarStyle.jsx
│ │ ├── cardBodyStyle.jsx
│ │ ├── cardFooterStyle.jsx
│ │ ├── cardHeaderStyle.jsx
│ │ ├── cardIconStyle.jsx
│ │ └── cardStyle.jsx
│ ├── CustomButtons
│ │ ├── Button.jsx
│ │ └── buttonStyle.jsx
│ ├── CustomInput
│ │ ├── CustomInput.jsx
│ │ └── customInputStyle.jsx
│ ├── CustomTabs
│ │ ├── CustomTabs.jsx
│ │ └── customTabsStyle.jsx
│ ├── Footer
│ │ ├── Footer.jsx
│ │ └── footerStyle.jsx
│ ├── Grid
│ │ └── GridItem.jsx
│ ├── Header
│ │ ├── Header.jsx
│ │ ├── HeaderLinks.jsx
│ │ ├── headerLinksStyle.jsx
│ │ └── headerStyle.jsx
│ ├── MessageBox
│ │ ├── MessageBoxType.jsx
│ │ ├── helper.jsx
│ │ ├── index.jsx
│ │ └── jss.jsx
│ ├── Notification
│ │ ├── NotificationCenter.jsx
│ │ ├── NotificationGroup.jsx
│ │ ├── NotificationGroupStyle.js
│ │ ├── NotificationItem.jsx
│ │ ├── NotificationItemPropTypes.js
│ │ ├── NotificationItemStyle.js
│ │ ├── NotificationPanel.jsx
│ │ ├── NotificationPanelStyle.js
│ │ ├── NotificationPopup.jsx
│ │ ├── NotificationPopupItem.jsx
│ │ ├── NotificationPopupItemStyle.js
│ │ ├── NotificationStatus.js
│ │ ├── NotificationType.js
│ │ ├── helper.jsx
│ │ ├── index.js
│ │ └── jss.js
│ ├── Sidebar
│ │ ├── Sidebar.jsx
│ │ └── sidebarStyle.jsx
│ ├── Snackbar
│ │ ├── Snackbar.jsx
│ │ ├── SnackbarContent.jsx
│ │ └── snackbarContentStyle.jsx
│ ├── Table
│ │ ├── ActionCell.jsx
│ │ ├── Table.jsx
│ │ └── tableStyle.jsx
│ ├── Tasks
│ │ ├── Tasks.jsx
│ │ └── tasksStyle.jsx
│ ├── Typography
│ │ ├── Danger.jsx
│ │ ├── Info.jsx
│ │ ├── Muted.jsx
│ │ ├── Primary.jsx
│ │ ├── Quote.jsx
│ │ ├── Success.jsx
│ │ ├── Warning.jsx
│ │ └── typographyStyle.jsx
│ └── User
│ │ ├── UserForm.jsx
│ │ ├── UserTable.jsx
│ │ ├── UserView.jsx
│ │ └── userFormStyles.js
├── favicon.ico
├── index.html.ejs
├── index.jsx
├── layouts
│ ├── Dashboard.jsx
│ ├── ExceptionHandler.jsx
│ └── dashboardStyle.jsx
├── reducers
│ └── index.js
├── routes
│ ├── dashboard.jsx
│ └── index.jsx
├── settings
│ ├── dev.js
│ ├── index.js
│ └── prd.js
└── views
│ ├── Dashboard
│ ├── Dashboard.jsx
│ └── dashboardStyle.jsx
│ ├── Icons
│ ├── Icons.jsx
│ └── iconsStyle.jsx
│ ├── Maps
│ └── Maps.jsx
│ ├── MessageBox
│ └── index.jsx
│ ├── Notifications
│ └── Notifications.jsx
│ ├── TableList
│ └── TableList.jsx
│ ├── Typography
│ └── Typography.jsx
│ ├── UpgradeToPro
│ └── UpgradeToPro.jsx
│ ├── UserProfile
│ ├── UserEditTransition.jsx
│ ├── UserListing.jsx
│ └── UserProfile.jsx
│ └── loaders
│ ├── ComponentLoader.tsx
│ └── index.ts
├── tests
├── _dummy_data
│ ├── charts.jsx
│ ├── general.jsx
│ ├── simulator.js
│ └── users.js
├── commons
│ ├── commonFuncs.test.ts
│ └── guard.test.ts
└── components
│ ├── MessageBox
│ ├── __snapshots__
│ │ └── index.test.tsx.snap
│ └── index.test.tsx
│ ├── User
│ ├── UserForm.test.tsx.ignore
│ ├── UserTable.test.tsx.ignore
│ └── __snapshots__
│ │ └── UserTable.test.tsx.snap
│ └── notification
│ ├── NotificationPopup.test.tsx
│ ├── NotificationPopupItem.test.tsx
│ ├── __snapshots__
│ ├── NotificationPopup.test.tsx.snap
│ ├── NotificationPopupItem.test.tsx.snap
│ └── index.test.tsx.snap
│ └── index.test.tsx
├── tsconfig.json
└── tsconfig.test.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/env",
5 | {
6 | "modules": false,
7 | "useBuiltIns": "entry"
8 | }
9 | ],
10 | "@babel/react"
11 | ],
12 | "plugins": [
13 | ["@babel/transform-runtime", { "useESModules": true }],
14 | "@babel/plugin-syntax-dynamic-import",
15 | "@babel/plugin-syntax-import-meta",
16 | ["@babel/plugin-proposal-decorators", { "legacy": true }],
17 | ["@babel/plugin-proposal-class-properties", { "loose": true }],
18 | "@babel/plugin-proposal-json-strings",
19 | "@babel/plugin-transform-async-to-generator",
20 | "react-loadable/babel",
21 | [
22 | "import",
23 | {
24 | "libraryName": "@material-ui/core",
25 | "libraryDirectory": "",
26 | "camel2DashComponentName": false
27 | },
28 | "material-core"
29 | ],
30 | [
31 | "import",
32 | {
33 | "libraryName": "@material-ui/icons",
34 | "libraryDirectory": "",
35 | "camel2DashComponentName": false
36 | },
37 | "material-icon"
38 | ],
39 | [
40 | "transform-imports",
41 | {
42 | "material-ui": {
43 | "transform": "@material-ui/core/${member}",
44 | "preventFullImport": true
45 | }
46 | }
47 | ],
48 | "babel-plugin-lodash",
49 | "react-hot-loader/babel", //Enables React code to work with HMR.
50 | [
51 | "module-resolver",
52 | {
53 | "root": ["./src"]
54 | }
55 | ]
56 | ],
57 | "env": {
58 | "node": {
59 | "presets": [["@babel/preset-env"], "@babel/react"],
60 | "plugins": [
61 | ["@babel/transform-runtime"],
62 | ["@babel/plugin-transform-modules-commonjs", { "spec": true }]
63 | ]
64 | },
65 | "test": {
66 | "presets": [["@babel/preset-env"], "@babel/react"],
67 | "plugins": [
68 | ["@babel/transform-runtime"],
69 | ["@babel/plugin-transform-modules-commonjs", { "spec": true }]
70 | ]
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/.bitmap:
--------------------------------------------------------------------------------
1 | /* THIS IS A BIT-AUTO-GENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. */
2 |
3 | {
4 | "version": "13.0.4"
5 | }
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Javascript Node CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 | docker:
9 | # specify the version you desire here
10 | - image: circleci/node:latest
11 |
12 | # Specify service dependencies here if necessary
13 | # CircleCI maintains a library of pre-built images
14 | # documented at https://circleci.com/docs/2.0/circleci-images/
15 | # - image: circleci/mongo:3.4.4
16 |
17 | working_directory: ~/repo
18 |
19 | steps:
20 | #Check out code
21 | - checkout
22 |
23 | # Download and cache dependencies
24 | - restore_cache:
25 | keys:
26 | - v1-dependencies-{{ checksum "package.json" }}
27 | # fallback to using the latest cache if no exact match is found
28 | - v1-dependencies-
29 |
30 | - run: npm install
31 | - run: npm install codecov bundlesize
32 | - run: npm rebuild node-sass
33 |
34 | - save_cache:
35 | paths:
36 | - node_modules
37 | key: v1-dependencies-{{ checksum "package.json" }}
38 |
39 | # Build
40 | - run: npm run git-webpack && npm run build
41 | # run test bundle size
42 | #- run:
43 | # name: run test-bundle
44 | # command: npm run test-bundle
45 | #environment:
46 | # BUNDLESIZE_GITHUB_TOKEN: dca74b5808660e8e1b09dccbe38b3b79b21bef6c
47 | # run tests
48 | #- run: npm run git-jest && npm run test-ci
49 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | node: true,
5 | commonjs: true,
6 | es6: true,
7 | jest: true
8 | },
9 | extends: 'eslint:recommended',
10 | parser: 'babel-eslint',
11 | parserOptions: {
12 | ecmaVersion: 6,
13 | sourceType: 'module',
14 | legacyDecotators: true,
15 | ecmaFeatures: {
16 | jsx: true
17 | }
18 | },
19 | plugins: ['react'],
20 | rules: {
21 | indent: 'off',
22 | 'linebreak-style': ['warn', 'unix'],
23 | quotes: ['error', 'single'],
24 | semi: ['error', 'always'],
25 | 'no-unused-vars': 'off',
26 | experimentalDecorators: true
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Automatically normalize line endings for all text-based files
2 | # http://git-scm.com/docs/gitattributes#_end_of_line_conversion
3 | * text=auto
4 |
5 | # For the following file types, normalize line endings to LF on
6 | # checkin and prevent conversion to CRLF when they are checked out
7 | # (this is required in order to prevent newline related issues like,
8 | # for example, after the build script is run)
9 | .* text eol=lf
10 | *.html text eol=lf
11 | *.css text eol=lf
12 | *.less text eol=lf
13 | *.styl text eol=lf
14 | *.scss text eol=lf
15 | *.sass text eol=lf
16 | *.sss text eol=lf
17 | *.js text eol=lf
18 | *.jsx text eol=lf
19 | *.json text eol=lf
20 | *.md text eol=lf
21 | *.mjs text eol=lf
22 | *.sh text eol=lf
23 | *.svg text eol=lf
24 | *.txt text eol=lf
25 | *.xml text eol=lf
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | **Expected behavior**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Desktop (please complete the following information):**
24 | - OS: [e.g. iOS]
25 | - Browser [e.g. chrome, safari]
26 | - Version [e.g. 22]
27 |
28 | **Smartphone (please complete the following information):**
29 | - Device: [e.g. iPhone6]
30 | - OS: [e.g. iOS8.1]
31 | - Browser [e.g. stock browser, safari]
32 | - Version [e.g. 22]
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "sm-react-docker-nginx"]
2 | path = sm-react-docker-nginx
3 | url = https://github.com/baoduy/sm-react-docker-nginx
4 | [submodule "sm-react-service-fabric"]
5 | path = sm-react-service-fabric
6 | url = https://github.com/baoduy/sm-react-service-fabric
7 | [submodule "sm-react-iis"]
8 | path = sm-react-iis
9 | url = https://github.com/baoduy/sm-react-iis
10 | [submodule "sm-react-node-express"]
11 | path = sm-react-node-express
12 | url = https://github.com/baoduy/sm-react-node-express
13 | [submodule "configs/webpack"]
14 | path = configs/webpack
15 | url = https://github.com/baoduy/sm-webpack-config
16 | [submodule "configs/jest"]
17 | path = configs/jest
18 | url = https://github.com/baoduy/sm-spa-jest-config
19 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "git.ignoreLimitWarning": true
3 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributes
2 |
3 | Appreciate your all contribution.
4 |
5 | - If you want to contribute the ideas please create a new issue [here](https://github.com/baoduy/React-MaterialUI-Started-Kit/issues).
6 |
7 | - If you want contribute the new features or fixing the reported issues. Please follow the below steps.
8 |
9 | 1. Fork the code.
10 | 2. Add the new featuures or fixing the existing issues.
11 | 3. Create pull request with the comment details.
12 |
13 | We will review and merge your code accordingly.
14 |
15 | Thanks and Regards
16 | Duy
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Viktor Persson
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.md:
--------------------------------------------------------------------------------
1 | # React Material Starter Kit
2 |
3 | [](https://circleci.com/gh/baoduy/React-MaterialUI-Starter-Kit)
4 | [](https://codecov.io/gh/baoduy/React-MaterialUI-Started-Kit) [](https://greenkeeper.io/)
5 | [](https://www.codetriage.com/baoduy/react-materialui-started-kit)
6 | [](https://david-dm.org/baoduy/React-MaterialUI-Started-Kit?type=peer)
7 | [](https://david-dm.org/baoduy/React-MaterialUI-Started-Kit)
8 | [](https://david-dm.org/baoduy/React-MaterialUI-Started-Kit?type=develop)
9 | [](https://app.netlify.com/sites/pedantic-hypatia-cf3a12/deploys)
10 |
11 | ## Documentation
12 |
13 | Refer [here](/docs/index.md) for details
14 |
15 | ## Demo
16 |
17 | [react.drunkcoding.net](http://react.drunkcoding.net)
18 |
--------------------------------------------------------------------------------
/bit.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {},
3 | "dependencies": {},
4 | "componentsDefaultDirectory": "components/{namespace}/{name}",
5 | "packageManager": "npm"
6 | }
--------------------------------------------------------------------------------
/docs/Account Ownership Diagram Template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/docs/Account Ownership Diagram Template.png
--------------------------------------------------------------------------------
/docs/Design Document.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/docs/Design Document.vsdx
--------------------------------------------------------------------------------
/docs/Document_2018-07-16_21-57-33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/docs/Document_2018-07-16_21-57-33.png
--------------------------------------------------------------------------------
/docs/components/ReadMe.md:
--------------------------------------------------------------------------------
1 | # New Compoments
2 |
3 | 1. **Message Box and Notification**: Allow to show Info, Confirm, Success and Error message and notification. Refer to the MessageBox in Views folder so sample that using Redux store to manage the state.
4 |
--------------------------------------------------------------------------------
/docs/components/notifications/ReadMe.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/docs/components/notifications/ReadMe.md
--------------------------------------------------------------------------------
/docs/development/Async.md:
--------------------------------------------------------------------------------
1 | # async/await
2 |
3 | Thanks to `babel-regenerator-runtime` to make the developler life bester as providing the async transform tool to transform the async and await functions to Promise.
4 | It make the code clearer and easier to read.
5 |
6 | ```javascript
7 | //Transform from
8 | function getDataFromServer() {
9 | return Promise((resolve, reject) => {
10 | loadDataFromServer()
11 | .then(data => resolve(data))
12 | .catch(error => reject(error));
13 | });
14 | }
15 |
16 | //To
17 | async function getDataFromServer() {
18 | try {
19 | return await loadDataFromServer();
20 | } catch (error) {
21 | throw error;
22 | }
23 | }
24 | ```
25 |
--------------------------------------------------------------------------------
/docs/development/Dev code block.md:
--------------------------------------------------------------------------------
1 | # webpack-remove-block-loader
2 |
3 | The `webpack-remove-block-loader` is Webpack loader to strip blocks of code marked by special comment tags. Useful for removing code that you don't want in your production webpack bundle (e.g. verbose console warnings, etc).
4 |
5 | Example: the code in side `/* PrdDeletion:start */` and `/* PrdDeletion:end */` will be removed in PRD bundle.
6 |
7 | ```javascript
8 | /* devblock:start */
9 | console.log(`base URL is ${base}`);
10 | /* devblock:end */
11 | }
12 | ```
13 |
14 | ## Uninstall Webpack Strip Block
15 |
16 | 1. Run the _npm uninstall —save-dev_ for all below packages:
17 |
18 | - webpack-strip-block
19 |
20 | 2. Remove the below LESS config blog from Webpack config in **configs\webpack\common.js** file:
21 |
22 | ```json
23 | {
24 | "test": /\.(js|jsx|ts|tsx)$/,
25 | //exclude: /node_modules/,
26 | "use": [
27 | {
28 | "loader": 'webpack-remove-block-loader',
29 | "options": {
30 | "active": !devMode,
31 | }
32 | }
33 | ]
34 | },
35 | ```
36 |
37 | 3. Remove all code blocks which starting with `/* develblock:start */` and end with `/* develblock:end */`
38 |
--------------------------------------------------------------------------------
/docs/development/ReadMe.md:
--------------------------------------------------------------------------------
1 | # Features
2 |
3 | 1. [Run and Packaging](Run and Package)
4 | 2. [async and await](Async)
5 | 3. [Typescript](TypeScript)
6 | 4. [Dev code block](Dev code block): Allows to write some code which running in DEV only. This block code will be remove when bunlding for PRD.
7 |
--------------------------------------------------------------------------------
/docs/development/Run and Package.md:
--------------------------------------------------------------------------------
1 | # Run & Packaging
2 |
3 | ## Development
4 |
5 | `npm run start-dev`
6 |
7 | - Build app continously (HMR enabled)
8 | - App served @ `http://localhost:8080`
9 |
10 | ## Production
11 |
12 | `npm run start-prod`
13 |
14 | - Build app once (HMR disabled)
15 | - App served @ `http://localhost:3000`
16 |
17 | ## Webpack Bundle Analysis
18 |
19 | `npm run start-analysis`
20 |
21 | - Analysis served @ `http://localhost:8888`
22 |
--------------------------------------------------------------------------------
/docs/development/TypeScript.md:
--------------------------------------------------------------------------------
1 | # Typescript
2 |
3 | This project allows to develop some commonds javascript with Typescript which helping to minimize the common issue of coding.
4 | You can find the Typescript sample in \*\*src\commons\commonFuncs.ts, and you also able to import the js modules to the Typescript file as well.
5 |
6 | ## Uninstall Typescript
7 |
8 | 1. Run the _npm uninstall —save-dev_ for all below packages:
9 | - awesome-typescript-loader
10 | - typescript
11 | - and all packages have name started with `@types`.
12 | 2. Remove the below LESS config blog from Webpack config in **configs\webpack\common.js** file:
13 |
14 | ```json
15 | {
16 | test: /\.tsx?$/,
17 | loader: 'awesome-typescript-loader'
18 | },
19 | ```
20 |
21 | 3. Remove the **tsconfig.json** and **tsconfig.test.json** files.
22 | 4. Convert all .ts and .tsx files to .js and .jsx.
23 |
--------------------------------------------------------------------------------
/docs/environments/Azure Service Fabric.md:
--------------------------------------------------------------------------------
1 | # Azure Service Fabric Support
2 |
3 | All stuffs in `sm-react-service-fabric` folder are using for **[Azure Service Fabric](https://azure.microsoft.com/en-us/services/service-fabric/)** hosting purpose.
4 |
5 | The C# project inside this folder will copy all files from dist folder to wwwroot folder and host them as a static side in Azure Service Fabric.
6 |
7 | Currently, I'm using .Net Core 2.1 to make the project is flexible enough to host on any platforms.
8 |
9 | When build the Service Fabric application it will copy all files in `dist` folder to `wwwroot` folder. So ensure you run the `npm build` before deploy the Service Fabric app.
10 |
11 | However if you are not using Service Fabric just simply remove the submodule **sm-react-service-fabric** There is no impact to the application.
12 |
--------------------------------------------------------------------------------
/docs/environments/Docker.md:
--------------------------------------------------------------------------------
1 | # Docker Support
2 |
3 | 1. Build Image `docker build`.
4 | 2. Build and Tag the image `docker image build . -f sm-react-docker-nginx/Dockerfile -t [YOUR_ID]/react-materialui-started-kit:latest`.
5 | Example `docker image build . -f sm-react-docker-nginx/Dockerfile -t baoduy2412/react-materialui-started-kit:latest`.
6 | 3. Push inage to Docker hub `docker push [YOUR_ID]/react-materialui-started-kit:latest`
7 | Example `docker push baoduy2412/react-materialui-started-kit:latest`.
8 |
9 | The application will running port 80 and 443 in Docker.
10 | The image can be found in Docker hub [here](https://hub.docker.com/r/baoduy2412/react-materialui-started-kit/).
11 |
12 | However if you are not using Docker just simply remove the submodule **sm-react-docker-nginx** There is no impact to the application.
13 |
--------------------------------------------------------------------------------
/docs/environments/GZIP and SSL.md:
--------------------------------------------------------------------------------
1 | ### GZIP and SSL
2 |
3 | The **GZIP** and **SSL** had been applied for all hosting environments above.
4 |
--------------------------------------------------------------------------------
/docs/environments/IIS.md:
--------------------------------------------------------------------------------
1 | # IIS Support
2 |
3 | The `Web.config` file in **sm-react-iis** had been added for IIS hosting purpose. This file should be copy along with all files in dist folder when hosting in IIS.
4 |
5 | However if you are not hosting this app in IIS just simply remove the submodule **sm-react-iis** There is no impact to the application.
6 |
--------------------------------------------------------------------------------
/docs/environments/NodeJs.md:
--------------------------------------------------------------------------------
1 | # Node Js Hosting
2 |
3 | There is a sub module contains the Express.js configuration to host the application in the Node Js environment.
4 | The application will running port 3000 and 3001 in NodeJs and the port is configurable in the Js file.
5 |
6 | If you are not using Node Js hosting just simply remove the submodule **sm-react-node-express** There is no impact to the application.
7 | But, please note that the `npm run start-prod` is using this submodule to hosting the dist folder as a static side. Please be considered before removing this module.
8 |
--------------------------------------------------------------------------------
/docs/environments/ReadMe.md:
--------------------------------------------------------------------------------
1 | # Environment Deployments
2 |
3 | 1. [Azure Service Fabric](Azure Service Fabric)
4 | 2. [Docker](Docker)
5 | 3. [IIS](IIS)
6 | 4. [NodeJs](NodeJs)
7 | 5. [GZIP and SSL](GZIP and SSL)
8 |
--------------------------------------------------------------------------------
/docs/styles/LESS.md:
--------------------------------------------------------------------------------
1 | # LESS
2 |
3 | The project is supporting to develop the stylesheet with LESS. All the less files should be placed under **src\assets\less** folder and the LESS import should be in the **src\index.js** file.
4 |
5 | ## Syntax validation
6 |
7 | There is a command had been added to the package.json file which helps to verify the LESS best practices syntax.
8 |
9 | run `npm run lint` or `npm run lint-less`
10 |
11 | ## Stylesheet Bundling
12 |
13 | When packaging the application for Production all stylesheet files _(CSS, LESS and SCSS)_ will be bundled to a single file named **style.css** by the Webpack and storing in the **dist** folder.
14 |
15 | ## Convert Tools
16 |
17 | - Css to Jss [here](https://github.com/cssinjs/cli)
18 | - Css to LESS [here](http://kronus.me/cn/css2less/) in case you don't like Jss.
19 |
20 | ## Uninstall LESS
21 |
22 | LESS support is one of stylesheet development option which supporting by this Starter kid. If you want to use the other stylesheet development options like CSS or SCSS and want to uninstall all LESS related things then follow steps will show you How to remove LESS from this project.
23 |
24 | 1. Run the _npm uninstall —save-dev_ for all below packages:
25 | - less
26 | - less-loader
27 | - lesshint
28 | 2. Remove the below LESS config blog from Webpack config in **configs\webpack\common.js** file:
29 |
30 | ```json
31 | {
32 | "test": /\.less$/,
33 | "use": [
34 | devMode ? "style-loader" : ExtractCssChunks.loader,
35 | {
36 | "loader": "css-loader",
37 | "options": { "url": false, "sourceMap": false }
38 | },
39 | "postcss-loader",
40 | {
41 | "loader": "less-loader",
42 | "options": {
43 | "relativeUrls": false,
44 | "sourceMap": false
45 | }
46 | }
47 | ]
48 | }
49 | ```
50 |
51 | 3. Remove the **less** folder from **scr\asserts**
52 | 4. Remove the LESS scripts at in **package.json** file.
53 |
54 | ```json
55 | "scripts": {
56 | //This is for LESS compilation checking purpose. Remove it if not inuse.
57 | "build-less": "lessc ./src/assets/less/material-dashboard-react.less ./src/assets/less/material-dashboard-react.css",
58 | //Remove the **lint-less** fron this command
59 | "lint": "npm-run-all lint-js lint-less",
60 | //Remove this line
61 | "lint-less": "lesshint ./src/assets/less",
62 | }
63 | ```
64 |
65 | ## Samples
66 |
67 | There is a sample LESS file named **material-dashboard-react.less** had been added into the project under **scr\asserts** folder which importing to the application in the **index.jsx** file.
68 |
69 | ```javascript
70 | //Style-sheets
71 | import './assets/less/material-dashboard-react.less';
72 | ```
73 |
--------------------------------------------------------------------------------
/docs/styles/ReadMe.md:
--------------------------------------------------------------------------------
1 | # The stylesheet development tools.
2 |
3 | 1. [LESS](LESS)
4 | 1. [SCSS](scss)
5 |
--------------------------------------------------------------------------------
/docs/styles/SCSS.md:
--------------------------------------------------------------------------------
1 | # SCSS
2 |
3 | The project is support to develop the stylesheet with SCSS. All the scss files should be placed under **src\assets\scss** folder and the SCSS import should be in the **src\index.js** file.
4 |
5 | ## Syntax validation
6 |
7 | There is a command had been added to the package.json file which helping to verify the SCSS best practices syntax.
8 | before running below command ensure the sass-lint is installed globally ny command `sass-lint-install`.
9 |
10 | run `npm run lint` or `npm run lint-scss`
11 |
12 | ## Convert Tools
13 |
14 | - LESS to SCSS [here](http://less2scss.awk5.com/).
15 |
16 | ## Stylesheet Bundling
17 |
18 | When packaging the application for Production all stylesheet files _(css, LESS and SCSS)_ will be bundled to a single file named **style.css** by the Webpack and storing in the **dist** folder.
19 |
20 | ## Uninstall SCSS
21 |
22 | SCSS support is one of stylesheet development option which supporting by this Starter kid. If you want to using the other stylesheet development options like CSS or SCSS and want to uninstall all SCSS related things then follow steps will show you How to remove SCSS from this project.
23 |
24 | 1. Run the _npm uninstall —save-dev_ for all below packages:
25 | - node-sass
26 | - sass-loader
27 | 2. Remove the below SCSS config blog from Webpack config in **configs\webpack\common.js** file:
28 |
29 | ```json
30 | {
31 | "test": /\.scss$/,
32 | "use": [
33 | devMode ? "style-loader" : ExtractCssChunks.loader,
34 | "css-loader",
35 | "postcss-loader",
36 | "sass-loader"
37 | ]
38 | }
39 | ```
40 |
41 | 3. Remove the **scss** folder from **scr\asserts**
42 | 4. Remove the SCSS scripts at in **package.json** file.
43 |
44 | ```json
45 | "scripts": {
46 | //Remove **lint-scss** from this command
47 | "lint": "npm-run-all lint-js lint-scss",
48 | //Remove this line
49 | "lint-scss": "sass-lint 'src/**/*.scss' -v -q",
50 | //Remove this line
51 | "sass-lint-install": "npm install -g sass-lint",
52 | }
53 | ```
54 |
55 | ## Samples
56 |
57 | There is an sample SCSS file named **material-dashboard-react.scss** had been added into the project under **scr\asserts** folder which importing to the application in the **index.jsx** file.
58 |
59 | ```javascript
60 | //Style-sheets
61 | import './assets/scss/material-dashboard-react.scss';
62 | ```
63 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('cssnano')({
4 | preset: 'default'
5 | })
6 | ]
7 | };
8 |
--------------------------------------------------------------------------------
/src/actions/Dashboard/DashboardActions.js:
--------------------------------------------------------------------------------
1 | import { makeThunkAsyncActionCreator } from 'redux-toolbelt-thunk';
2 | import Api from '../../api';
3 |
4 | export const getGeneral = makeThunkAsyncActionCreator(
5 | 'FETCH_USER',
6 | Api.GeneralApi.getGeneral
7 | );
8 |
9 | export const getChartData = makeThunkAsyncActionCreator(
10 | 'FETCH_USER',
11 | Api.ChartApi.getChartData
12 | );
13 |
--------------------------------------------------------------------------------
/src/actions/Dashboard/DashboardReducer.js:
--------------------------------------------------------------------------------
1 | import { makeAsyncReducer } from 'redux-toolbelt';
2 | import * as actions from './DashboardActions';
3 |
4 | const chartsReducer = makeAsyncReducer(actions.getChartData);
5 | const generalReducer = makeAsyncReducer(actions.getGeneral);
6 |
7 | export default {
8 | chartsReducer,
9 | generalReducer
10 | };
11 |
--------------------------------------------------------------------------------
/src/actions/Dashboard/index.js:
--------------------------------------------------------------------------------
1 | import * as Actions from './DashboardActions';
2 | import Reducer from './DashboardReducer';
3 |
4 | export { Actions, Reducer };
5 | export default Actions;
6 |
--------------------------------------------------------------------------------
/src/actions/MessageBox/MessageBoxActions.js:
--------------------------------------------------------------------------------
1 | import { makeActionCreator } from 'redux-toolbelt';
2 | //import { makeThunkAsyncActionCreator } from 'redux-toolbelt-thunk';
3 | import dayjs from 'dayjs';
4 | import { NotificationStatus } from '../../components/Notification';
5 | import { newGuid } from '../../commons/commonFuncs';
6 |
7 | //Moved the type of all actions on top so it will be eaiser if need refectoring the names.
8 | export const TYPES = {
9 | Shown: '@MessageBox/Shown',
10 | Hided: '@MessageBox/Hided'
11 | };
12 |
13 | export function showMessage(type, message, handler) {
14 | return dispatch => {
15 | const callback = event => {
16 | try {
17 | if (handler) handler(event);
18 | } finally {
19 | dispatch({
20 | type: TYPES.Hided
21 | });
22 | }
23 | };
24 |
25 | dispatch({
26 | type: TYPES.Shown,
27 | payload: {
28 | id: newGuid(),
29 | type,
30 | message,
31 | actionHandler: callback
32 | }
33 | });
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/src/actions/MessageBox/MessageBoxReducer.js:
--------------------------------------------------------------------------------
1 | import { TYPES } from './MessageBoxActions';
2 |
3 | export default function MessageBoxReducer(state = {}, action) {
4 | switch (action.type) {
5 | case TYPES.Shown:
6 | return Object.assign(action.payload, {
7 | open: true
8 | });
9 | case TYPES.Hided:
10 | return Object.assign({}, state, {
11 | message: '',
12 | handler: undefined,
13 | open: false
14 | });
15 | default:
16 | return state;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/actions/MessageBox/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './MessageBoxActions';
2 |
3 | export { default as Reducer } from './MessageBoxReducer';
4 | export default actions;
5 |
--------------------------------------------------------------------------------
/src/actions/Notifications/NotificationActions.js:
--------------------------------------------------------------------------------
1 | import { makeActionCreator } from 'redux-toolbelt';
2 | //import { makeThunkAsyncActionCreator } from 'redux-toolbelt-thunk';
3 | import dayjs from 'dayjs';
4 | import { NotificationStatus } from '../../components/Notification';
5 | import { newGuid } from '../../commons/commonFuncs';
6 |
7 | //Moved the type of all actions on top so it will be eaiser if need refectoring the names.
8 | const TYPES = {
9 | AddedOrUpdated: '@Notification/AddedOrUpdated',
10 | Deleted: '@Notification/Deleted'
11 | };
12 |
13 | /**
14 | * Create new notification item
15 | *
16 | * @export changeStatus
17 | * @param {NotificationType} type [Default is INFO] the type of the notification
18 | * @param {string} message the notification message
19 | * @param {string?} title the notification message
20 | * @param {string?} group group notification by group name.
21 | * @param {func?} onClick the click action of notification.
22 | * @returns {NotificationItemPropTypes}
23 | */
24 | export function newNotification(type, message, title, group, onClick) {
25 | if (typeof title === 'function' && !onClick) {
26 | onClick = title;
27 | title = '';
28 | }
29 |
30 | if (typeof group === 'function' && !onClick) {
31 | onClick = group;
32 | group = '';
33 | }
34 |
35 | return {
36 | id: newGuid(),
37 | type,
38 | message,
39 | title,
40 | group,
41 | createdOn: dayjs(),
42 | onClick,
43 | status: NotificationStatus.NEW
44 | };
45 | }
46 |
47 | /**
48 | * Add or Update Notifications to Redux Store.
49 | *
50 | * @export addOrUpdateNotification
51 | * @param {Array of NotificationItemPropTypes} items
52 | * @returns
53 | */
54 | export const addOrUpdateNotifications = makeActionCreator(TYPES.AddedOrUpdated);
55 |
56 | /**
57 | * Delete the Notitications
58 | *
59 | * @export deleteNotifications
60 | * @param {Array of NotificationItemPropTypes} items
61 | * @returns
62 | */
63 | export const deleteNotifications = makeActionCreator(TYPES.Deleted);
64 |
65 | /**
66 | * Create notification Item by calling newNotification and then call addOrUpdateNotification to add to Redux Store.
67 | *
68 | * @export notify
69 | * @param {NotificationType} type
70 | * @param {string} message
71 | * @param {string?} title
72 | * @param {string?} group
73 | * @param {func?} onClick
74 | * @returns
75 | */
76 | export function notify(type, message, title, group, onClick) {
77 | return addOrUpdateNotifications(
78 | newNotification(type, message, title, group, onClick)
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/src/actions/Notifications/NotificationReducer.js:
--------------------------------------------------------------------------------
1 | import { makeReducer } from 'redux-toolbelt';
2 | import { isArray } from 'lodash';
3 | import {
4 | addOrUpdateNotifications,
5 | deleteNotifications
6 | } from './NotificationActions';
7 | import linq from 'linq';
8 | import { Merge } from '../../commons/commonFuncs';
9 |
10 | export default makeReducer(
11 | {
12 | [addOrUpdateNotifications]: (state, { payload }) => {
13 | return Merge(state, isArray(payload) ? payload : [payload]);
14 | },
15 | [deleteNotifications]: (state, { payload }) => {
16 | const deleteItems = isArray(payload) ? payload : [payload];
17 |
18 | return linq
19 | .from(state)
20 | .where(i => !deleteItems.find(n => n.id === i.id))
21 | .toArray();
22 | }
23 | },
24 | { defaultState: [] }
25 | );
26 |
--------------------------------------------------------------------------------
/src/actions/Notifications/index.js:
--------------------------------------------------------------------------------
1 | import * as Actions from './NotificationActions';
2 | import Reducer from './NotificationReducer';
3 |
4 | export { Actions, Reducer };
5 | export default Actions;
6 |
--------------------------------------------------------------------------------
/src/actions/Users/UserActions.js:
--------------------------------------------------------------------------------
1 | import * as api from '../../api/userApi';
2 | export const TYPES = {
3 | Request: '@User/Request',
4 | GetAllUsers: '@User/GetAllUsers',
5 | GetUserById: '@User/GetUserById',
6 | SaveUser: '@User/GetUserById',
7 | DeleteUser: '@User/DeleteUser'
8 | };
9 |
10 | function getUserSuccess(users) {
11 | return {
12 | type: TYPES.GetAllUsers,
13 | payload: users
14 | };
15 | }
16 | export const getAllUsers = () => {
17 | return dispatch => {
18 | dispatch({
19 | type: TYPES.Request
20 | });
21 | return api.getAllUsers().then(users => {
22 | dispatch(getUserSuccess(users));
23 | });
24 | };
25 | };
26 |
27 | function saveUserSuccess(user) {
28 | return {
29 | type: TYPES.SaveUser,
30 | payload: user
31 | };
32 | }
33 | export const saveUser = user => {
34 | return dispatch => {
35 | dispatch({
36 | type: TYPES.Request
37 | });
38 | return api.saveUser(user).then(response => {
39 | dispatch(saveUserSuccess(response));
40 | });
41 | };
42 | };
43 |
44 | function deleteUserSuccess(id) {
45 | return {
46 | type: TYPES.DeleteUser,
47 | payload: id
48 | };
49 | }
50 | export const deleteUser = id => {
51 | return dispatch => {
52 | dispatch({
53 | type: TYPES.Request
54 | });
55 | return api.deleteUser(id).then(response => {
56 | let payload = null;
57 | if (response) {
58 | payload = id;
59 | }
60 | dispatch(deleteUserSuccess(payload));
61 | });
62 | };
63 | };
--------------------------------------------------------------------------------
/src/actions/Users/UserReducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | TYPES
3 | } from './UserActions';
4 | import {
5 | Merge
6 | } from '../../commons/commonFuncs';
7 | import {
8 | isArray
9 | } from 'lodash';
10 | // const getUser = makeAsyncReducer(getUserById, {
11 | // defaultData: {}
12 | // });
13 | // const getUsers = makeAsyncReducer(getAllUsers, {
14 | // defaultData: []
15 | // });
16 | // export default composeReducers({
17 | // UserById: getUser,
18 | // AllUsers: getUsers
19 | // });
20 | //export default getUsers;
21 | export default (state = {
22 | data: []
23 | }, action) => {
24 | switch (action.type) {
25 | case TYPES.GetAllUsers:
26 | return { ...state,
27 | data: [...action.payload],
28 | isLoading: false
29 | };
30 | case TYPES.SaveUser:
31 | return { ...state,
32 | data: Merge(state.data, isArray(action.payload) ? action.payload : [action.payload]),
33 | isLoading: false
34 | };
35 | case TYPES.DeleteUser:
36 | const oldUsers = [...state.data];
37 | return {
38 | ...state,
39 | data: oldUsers.filter(i => i.id !== action.payload),
40 | isLoading: false
41 | };
42 | case TYPES.Request:
43 | return {
44 | ...state,
45 | isLoading: true
46 | };
47 | default:
48 | return state;
49 | }
50 | };
--------------------------------------------------------------------------------
/src/actions/Users/index.js:
--------------------------------------------------------------------------------
1 | import * as Actions from './UserActions';
2 | import Reducer from './UserReducer';
3 |
4 |
5 | export {
6 | Actions,
7 | Reducer
8 | };
9 | export default Actions;
--------------------------------------------------------------------------------
/src/api/chartApi.js:
--------------------------------------------------------------------------------
1 | import charts from '../../tests/_dummy_data/charts';
2 | import simulator from '../../tests/_dummy_data/simulator';
3 |
4 | //Calling Api and return data
5 | //This will use timeout to simulate server call.
6 | export function getChartData() {
7 | return simulator(charts);
8 | }
9 |
--------------------------------------------------------------------------------
/src/api/generalApi.js:
--------------------------------------------------------------------------------
1 | import general from '../../tests/_dummy_data/general';
2 | import simulator from '../../tests/_dummy_data/simulator';
3 |
4 | //This will use timeout to simulate server call.
5 | export function getGeneral() {
6 | return simulator(general);
7 | }
8 |
--------------------------------------------------------------------------------
/src/api/index.js:
--------------------------------------------------------------------------------
1 | import * as GeneralApi from './generalApi';
2 | import * as ChartApi from './chartApi';
3 |
4 | export default {
5 | GeneralApi,
6 | ChartApi
7 | };
8 |
--------------------------------------------------------------------------------
/src/api/userApi.js:
--------------------------------------------------------------------------------
1 | import urljoin from 'url-join';
2 | import * as evnConfig from '../settings';
3 | import axios from 'axios';
4 |
5 | const Root = urljoin(evnConfig.webService, 'api/users/');
6 |
7 | export const getAllUsers = () =>
8 | axios.get(Root).then(response => response.data);
9 |
10 | export const getUserById = id =>
11 | axios.get(urljoin(Root, `${id}`)).then(response => response.data);
12 |
13 | export const saveUser = user =>
14 | axios.post(Root, user).then(response => response.data);
15 |
16 | export const deleteUser = id =>
17 | axios.delete(urljoin(Root, `${id}`)).then(response => response.data);
18 |
19 | export const isUsernameOrEmailExist = (usernameOrEmail, id) =>
20 | axios
21 | .get(urljoin(Root, 'IsEmailOrUserNameExist', usernameOrEmail, `${id}`))
22 | .then(response => response.data);
23 |
--------------------------------------------------------------------------------
/src/assets/img/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/apple-icon.png
--------------------------------------------------------------------------------
/src/assets/img/cover.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/cover.jpeg
--------------------------------------------------------------------------------
/src/assets/img/faces/marc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/faces/marc.jpg
--------------------------------------------------------------------------------
/src/assets/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/favicon.png
--------------------------------------------------------------------------------
/src/assets/img/mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/mask.png
--------------------------------------------------------------------------------
/src/assets/img/new_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/new_logo.png
--------------------------------------------------------------------------------
/src/assets/img/react_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/assets/img/sidebar-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/sidebar-1.jpg
--------------------------------------------------------------------------------
/src/assets/img/sidebar-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/sidebar-2.jpg
--------------------------------------------------------------------------------
/src/assets/img/sidebar-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/sidebar-3.jpg
--------------------------------------------------------------------------------
/src/assets/img/sidebar-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/sidebar-4.jpg
--------------------------------------------------------------------------------
/src/assets/img/tim_80x80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/assets/img/tim_80x80.png
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/cardImagesStyles.jsx:
--------------------------------------------------------------------------------
1 | const cardImagesStyles = {
2 | cardImgTop: {
3 | width: "100%",
4 | borderTopLeftRadius: "calc(.25rem - 1px)",
5 | borderTopRightRadius: "calc(.25rem - 1px)"
6 | },
7 | cardImgBottom: {
8 | width: "100%",
9 | borderBottomRightRadius: "calc(.25rem - 1px)",
10 | borderBottomLeftRadius: "calc(.25rem - 1px)"
11 | },
12 | cardImgOverlay: {
13 | position: "absolute",
14 | top: "0",
15 | right: "0",
16 | bottom: "0",
17 | left: "0",
18 | padding: "1.25rem"
19 | },
20 | cardImg: {
21 | width: "100%",
22 | borderRadius: "calc(.25rem - 1px)"
23 | }
24 | };
25 |
26 | export default cardImagesStyles;
27 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/checkboxAdnRadioStyle.jsx:
--------------------------------------------------------------------------------
1 | import { primaryColor } from "../material-dashboard-react.jsx";
2 |
3 | const checkboxAdnRadioStyle = {
4 | checked: {
5 | color: primaryColor + "!important"
6 | },
7 | checkedIcon: {
8 | width: "20px",
9 | height: "20px",
10 | border: "1px solid rgba(0, 0, 0, .54)",
11 | borderRadius: "3px"
12 | },
13 | uncheckedIcon: {
14 | width: "0px",
15 | height: "0px",
16 | padding: "10px",
17 | border: "1px solid rgba(0, 0, 0, .54)",
18 | borderRadius: "3px"
19 | },
20 | radio: {
21 | color: primaryColor + "!important"
22 | },
23 | radioChecked: {
24 | width: "20px",
25 | height: "20px",
26 | border: "1px solid " + primaryColor,
27 | borderRadius: "50%"
28 | },
29 | radioUnchecked: {
30 | width: "0px",
31 | height: "0px",
32 | padding: "10px",
33 | border: "1px solid rgba(0, 0, 0, .54)",
34 | borderRadius: "50%"
35 | }
36 | };
37 |
38 | export default checkboxAdnRadioStyle;
39 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/dropdownStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | primaryColor,
3 | primaryBoxShadow,
4 | defaultFont
5 | } from "../material-dashboard-react.jsx";
6 |
7 | const dropdownStyle = theme => ({
8 | buttonLink: {
9 | [theme.breakpoints.down("md")]: {
10 | display: "flex",
11 | marginLeft: "30px",
12 | width: "auto"
13 | }
14 | },
15 | links: {
16 | width: "20px",
17 | height: "20px",
18 | zIndex: "4",
19 | [theme.breakpoints.down("md")]: {
20 | display: "block",
21 | width: "30px",
22 | height: "30px",
23 | color: "#a9afbb",
24 | marginRight: "15px"
25 | }
26 | },
27 | linkText: {
28 | zIndex: "4",
29 | ...defaultFont,
30 | fontSize: "14px"
31 | },
32 | popperClose: {
33 | pointerEvents: "none"
34 | },
35 | pooperResponsive: {
36 | [theme.breakpoints.down("md")]: {
37 | zIndex: "1640",
38 | position: "static",
39 | float: "none",
40 | width: "auto",
41 | marginTop: "0",
42 | backgroundColor: "transparent",
43 | border: "0",
44 | WebkitBoxShadow: "none",
45 | boxShadow: "none",
46 | color: "black"
47 | }
48 | },
49 | dropdown: {
50 | borderRadius: "3px",
51 | border: "0",
52 | boxShadow: "0 2px 5px 0 rgba(0, 0, 0, 0.26)",
53 | top: "100%",
54 | zIndex: "1000",
55 | minWidth: "160px",
56 | padding: "5px 0",
57 | margin: "2px 0 0",
58 | fontSize: "14px",
59 | textAlign: "left",
60 | listStyle: "none",
61 | backgroundColor: "#fff",
62 | WebkitBackgroundClip: "padding-box",
63 | backgroundClip: "padding-box"
64 | },
65 | dropdownItem: {
66 | ...defaultFont,
67 | fontSize: "13px",
68 | padding: "10px 20px",
69 | margin: "0 5px",
70 | borderRadius: "2px",
71 | WebkitTransition: "all 150ms linear",
72 | MozTransition: "all 150ms linear",
73 | OTransition: "all 150ms linear",
74 | MsTransition: "all 150ms linear",
75 | transition: "all 150ms linear",
76 | display: "block",
77 | clear: "both",
78 | fontWeight: "400",
79 | lineHeight: "1.42857143",
80 | color: "#333",
81 | whiteSpace: "nowrap",
82 | height: "unset",
83 | "&:hover": {
84 | backgroundColor: primaryColor,
85 | color: "#FFFFFF",
86 | ...primaryBoxShadow
87 | }
88 | }
89 | });
90 |
91 | export default dropdownStyle;
92 |
--------------------------------------------------------------------------------
/src/assets/jss/material-dashboard-react/tooltipStyle.jsx:
--------------------------------------------------------------------------------
1 | const tooltipStyle = {
2 | tooltip: {
3 | padding: "10px 15px",
4 | minWidth: "130px",
5 | color: "#555555",
6 | lineHeight: "1.7em",
7 | background: "#FFFFFF",
8 | border: "none",
9 | borderRadius: "3px",
10 | boxShadow:
11 | "0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2)",
12 | maxWidth: "200px",
13 | textAlign: "center",
14 | fontFamily: "'Helvetica Neue',Helvetica,Arial,sans-serif",
15 | fontSize: "12px",
16 | fontStyle: "normal",
17 | fontWeight: "400",
18 | textShadow: "none",
19 | textTransform: "none",
20 | letterSpacing: "normal",
21 | wordBreak: "normal",
22 | wordSpacing: "normal",
23 | wordWrap: "normal",
24 | whiteSpace: "normal",
25 | lineBreak: "auto"
26 | }
27 | };
28 | export default tooltipStyle;
29 |
--------------------------------------------------------------------------------
/src/commons/checks.js.ignore:
--------------------------------------------------------------------------------
1 | export const isNull = item => item === null;
2 | export const isUndefined = item => item === undefined;
3 | export const isEmpty = item => item === '' || item === {} || item === [];
4 | export const isFunction = item => typeof item === 'function';
5 | export const isString = item => typeof item === 'string';
6 | export const isArray = item => Array.isArray(item);
7 |
--------------------------------------------------------------------------------
/src/commons/commonControlRenderers.jsx:
--------------------------------------------------------------------------------
1 | import TextField from '@material-ui/core/TextField';
2 | import FormControl from '@material-ui/core/FormControl';
3 |
4 | export const renderTextField = ({
5 | input,
6 | label,
7 | meta: { touched, error, invalid },
8 | formControlProps = {},
9 | ...custom
10 | }) => {
11 | return (
12 |
13 |
21 |
22 | );
23 | };
24 |
25 | export const renderInputFile = ({
26 | input,
27 | label,
28 | meta: { touched, error, invalid },
29 | fileRef,
30 | onChangeFile,
31 | ...custom
32 | }) => {
33 | return (
34 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/src/commons/commonFuncs.ts:
--------------------------------------------------------------------------------
1 | /*eslint no-console: ["off", { allow: ["warn", "error"] }] */
2 |
3 | import linq from 'linq';
4 | import uuidv4 from 'uuid/v4';
5 | import Default from './constants.js';
6 | //correct URL for Reserved proxy
7 | //Get the millisecond of current time.
8 |
9 | export const GetBaseUrl = () => {
10 | const key = 'BASE_URL';
11 |
12 | const base: string =
13 | window.sessionStorage.getItem(key) ||
14 | document.getElementsByTagName('base')[0].getAttribute('href') ||
15 | '/';
16 |
17 | window.sessionStorage.setItem(key, base);
18 |
19 | /* devblock:start */
20 | console.log(`base URL is ${base}`);
21 | /* devblock:end */
22 |
23 | return base;
24 | };
25 |
26 | export const newGuid = () => uuidv4();
27 |
28 | /**
29 | *getImgSrc for both normal hosting and Reverse proxy
30 | *
31 | * @export
32 | * @param {string} url the relative image url
33 | * @returns real url
34 | */
35 | export function getImgSrc(url: string) {
36 | //if (typeof url !== 'string') return url;
37 | const base = GetBaseUrl();
38 |
39 | return !base || base === '/' || url.indexOf(base) >= 0
40 | ? url
41 | : `${base}/${url}`;
42 | }
43 |
44 | /**
45 | *Merge second array to first array if existed then update.
46 | *
47 | * @export
48 | * @param {Array} [fistArray=[]]
49 | * @param {Array} [secondArray=[]]
50 | * @param {Function} [selector=i => i.id]
51 | */
52 | export function Merge(
53 | fistArray = [],
54 | secondArray = [],
55 | selector = (i: any) => i.id
56 | ) {
57 | const firstQuery = linq.from(fistArray);
58 | const secondQuery = linq.from(secondArray);
59 |
60 | const news = secondQuery.where(i =>
61 | firstQuery.all(f => selector(f) !== selector(i))
62 | );
63 |
64 | const exists = secondQuery.where(i =>
65 | firstQuery.any(f => selector(f) === selector(i))
66 | );
67 |
68 | return firstQuery
69 | .select(i => {
70 | const found = exists.firstOrDefault(e => selector(e) === selector(i));
71 | return found ? Object.assign({}, i, found) : i;
72 | })
73 | .union(news)
74 | .toArray();
75 | }
76 | export function getAvatar(avatar: string): string {
77 | const tmp = avatar
78 | ? avatar.includes('data:image')
79 | ? avatar
80 | : `data:image/png;base64,${avatar}`
81 | : Default.DefaultAvatar;
82 | return tmp;
83 | }
84 |
85 | export function isValidEmail(email: string): boolean {
86 | if (email && !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(email)) {
87 | return false;
88 | }
89 | return true;
90 | }
91 |
92 | export function convertToFormData(object: any): FormData | undefined {
93 | if (!object) return undefined;
94 |
95 | const formData = new FormData();
96 | for (var key in object) formData.append(key, object[key]);
97 |
98 | return formData;
99 | }
100 |
--------------------------------------------------------------------------------
/src/commons/constants.js:
--------------------------------------------------------------------------------
1 | const DefaultDateFormat = '';
2 | const DefaultAvatar =
3 | 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAG2YAABzjgAA+swAAIT6AAB5gQAA/RMAADBtAAASKQ0eJk4AAAMAUExURevr7Jydn5manJucnuPj5JiZm9vb3PT09MvLzMLCw5GSlPr6+qeoqdXV1tHR0rW1trW2uKusrbi4urO0tLq6vKiqq7e4uLW2tqGipLm6ury8vr6+vr+/wLu8vM7OztDQ0cjJytjY2dTU1aipqqqrrMXGxqanqKmqq6Wmp9LT062usKSlprS0ta2trra2t6ytrqWmqK2ur66vsK6ur7CwsbOztK+vsK+wsbKys7GxsqOkpqOkpZ6foampq6qqrJ2eoKenqaysraKjpZqbnbi4uaKjpKSlp5eYmqioqqurrKChory8vKGio6amqKCho7Gys7CxsrGysrKzs5+gop+gobS1tbq6u7e3uLCxsbKztLi4uJWWmJaXmba3t7i5ub29vZWXmZSWmLq6upOVl5SVl7m5up6foLq7u7u7vJqcnZOUlpeZm5aYmpKUlry8vZKTlpGTlZCRlJCRk6ytr9bX197e3q+vsb2+v8DAweDh4bOztebm5ujp6e/v756eoP///4CAgIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouLi4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOTk5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2dnZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+vr7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5ubq6uru7u7y8vL29vb6+vr+/v8DAwMHBwcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zMzM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f3+Dg4OHh4eLi4uPj4+Tk5OXl5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///zfARREAAAeqSURBVHja7N3xVxJZFMBxQAQVilzPSTslBxcDdwdtBQRBDQUFBYNMDTcoNLAMM7QD23JozvvX94cJZBhQZ+bdO2/26F/Q59wv8K48JwP5n/wY7iH3kHvIPYT6D89bLBazfiF8Y+T09PT09MOHzc3Nd+8yeoTwb99+/PjkSbfj8eN83qYPSCOTOTs7O3veEP69UkcegEIdMpPJCI6zz5/f9p9HPp9//97KMsTwLZO5o2Nh4RmrkHrpmxzHwsICzyLEWSq1IXd1TE6aWYNYSqVSqSRzHpOTDsdDliC2ksBQ4HA4zOxA6iURRJ7DccizAbE9fVpyNXhlXTkcjsNDHxMQKyGEWBV35Tg89Pl8rKTVUtHVoc/n89mYgPBK3686Dt8EIcQwMzOjKUTF+1XHMbG0tLT095s3y8vL77WCqHq/Ehy+Lsdybm9aC4irRKGrLkcut7cXiUTQIS1588jfPo/cXiQSibxGhtTpdyU4kCElyq/zXMdx9AwT0qI+j1zbEQwiQmyUX+fXXR0Fg0EXGsQK1dXRUTAYDIbRIJBdBYNhNIgFsqtgOBx2IkFguwqHQyEcSAu2q3AICwLcVSjEh1oYEPCuQgbix4A4obsK+QmPAwHtKhTy+3+gvEacsF2F/H5/wIAIAevK7/cHAhgQgPNuzzwCgcAiFgSoK3/bgQWhuUdJuwosYkGgu1pcnDdgQCju5wPmMY8CAeyqPY/5+To8BKErPAjY50fb8QIHAnIu6Z7HCxwI0Lmk24ECge8KB4LQ1YuNDYS3X4SuNjbGESAIXW2M40DAuxofH0c4ayF0hQNB6AoJAt8VDgShq/GdHQwIYFfteezMIkCgzrsiBwZkhPp+LulqFgXyB/X9XDoPFEgTviscCE99P+/+/PjlwIAQ6vu5dB4vX2JAALvaaTu8OBCoc0m7q5deHAjYuaQzD68fAwJ3Luk4vC4MyAh4V17vAwxIE7orr9fLY0AIdFde7xpBg8B09cuBCAHtyrvmxoLAdrXm/h0DUgfvas3tdvPQEBdCV2632+3eHgWFwL9ftR12+yYg5CfIfi7pyu3ettvtdkAI2B4lnYfdbndBQiD28wGO9XUwiAFmP5e8zu0CxGOFgrgQu1pf93hcUJA84HlX/DoXIDkoCNB+3r8rj8fjgYIA7ef9u4KGoHXl8XheAUKAzyXdXXlezcFBwM8lXV29moODoHY1BwfB7QoSgtoVIARuj+rXFTAEtCvxPJKPoCBm1K6SyZ9gx3jorrodc0kObh/B7CrJzQJCELviZA1EJsQAtp9LuwKFENA9SjwPbhoSYgbbzwVGl0PeQGT/gg5sP+/tipuFhRCkruQORD5kFPa8qzAsJb/Ehj3v/uqKM8NDSANmPxd11cD5fgS8K5Q/3yOE2L7l9vYWALpKPuI4jsP7M3DhB+JcovyBbmoeJ0K/K45oASG0u0py09pAND7v0oM0qe7nSU4zCKG7R2kJofw5yGsFcVLcz1UOROXztah2pSWE6vkqatUO0qS2n3McFyXaQYiP2h6l0qH6qYCU9nMuGmUBon6P4qLRh9pCrJS6UjsQ9Q+cXKKwR3HRaPQfrSGESlfRFaI5pK7284OKg8aDiyl0tcIEpKV4j6LooPIoaYParlZ4NiBE2X5+7fiXMAIh6rpaIcxAeDVdUXHQem78A/n7ecfRYAlCphXsURTnQfG/JJC/RwkO9iCy9yjBEWcNoqyrlTiTEPldxZmEKOgqHt9iDyL782MlHo9vsQeRtZ9fO5iDyNyjOg72IIq62tqaYg0ib4+6drAJkd3VFJMQBV1NTe2yC5HTFZOQO+9R3fPYZQ4iu6spwcEq5PY9StTV7m6WLYjtVFlXu9nsCDMQi9+ruKtsNptOp9N/WTWHmJ/I2s8l88im0+n0/v7+Qc6mHcSiZI8a4Dg4OFhdVXGnRjHks9I9StpVx7G6uvrpU8yJCHmudD+/cR6CIxaLxR5gQJT/3ufOjljMaDQ6ASHN18q+P5fRVcdhNBqNQ9tWAEhL+ffnCuZhNBqNQ0NDQ0N+qpCmyu85lTu+fEkkEnYLDcio6u/PFXbVcSQSiYTJ5FQFeU7le0518xAcJpPJNKMMUqL0/Tk1h2l4eHh4RB6kPkHlHvKA827HsS/bMXx+nvqtdUcItfvt9OcxfH6eSqVSqa8/boU06d2/AnR8LRaLN0Pq9O6339aVckfqa7FYLB7fBKF0DxlhHsXj42PjQEgIqqspCEehUBgA8dG5347S1fFxoVAo2PpCWrrqqlAoFE5OWn0gBr11VTg5Oan0gdC63w45j1Svo2KVQujdQ8bq6qRSqVQkkAlq95DxuqpUKmUJhNb9dsyuKpVyeVQC0WNX5XK52gOx6LKrcrlabYghE5Tut+N2VS5Xq3YxhNo9ZNyuqtXqhQhipXS/HburavVCDKkzvUcN7qp60QPZ1GtXFxc1EYTV/fwaMmgetV4Iu/v5jV3VarW6CML2fj64q1qt9mc3hPX9fPA8ape9ED3sUX3mcXl5KYboY4/q5xgTQdjfz/t31QvRb1djYz0QvXYlhbC/n/ftqgeinz1KMo8eiG72KKlDBNHPHtXbVT+ILrsaG7vqgei0q6ur770QfXZ19V2A/DcAHpmC7NcZ4/wAAAAASUVORK5CYII=';
4 | export default {
5 | DefaultDateFormat,
6 | DefaultAvatar
7 | };
8 |
--------------------------------------------------------------------------------
/src/commons/exceptionService.js:
--------------------------------------------------------------------------------
1 | export function getErrorMessage(error, info) {
2 | if (typeof error === 'string') return error;
3 | return 'There is an error had been uncured. Please contact your App Support for details.';
4 | }
5 |
--------------------------------------------------------------------------------
/src/commons/guard.js:
--------------------------------------------------------------------------------
1 | //Some basic validation and exception
2 | import {
3 | isNull,
4 | isUndefined,
5 | isEmpty,
6 | isFunction,
7 | isString,
8 | isArray
9 | } from 'lodash';
10 |
11 | export function argumentNotNull(object, name) {
12 | if (isNull(object) || isUndefined(object))
13 | throw `${name || 'Argument'} must not be null or undefined.`;
14 | }
15 |
16 | export function argumentNotEmpty(object, name) {
17 | argumentNotNull(object, name);
18 | if (isEmpty(object)) throw `${name || 'Argument'} must not be empty.`;
19 | }
20 |
21 | export function argumentIsFunc(func, name) {
22 | if (!isFunction(func)) throw `${name || 'Argument'} is must be a Function.`;
23 | }
24 |
25 | export function argumentIsString(object, name) {
26 | if (!isString(object)) throw `${name || 'Argument'} is must be a String.`;
27 | }
28 |
29 | export function argumentIsStringAndNotEmpty(object, name) {
30 | argumentNotEmpty(object, name);
31 | argumentIsString(object.name);
32 | }
33 |
34 | export function argumentIsArray(object, name) {
35 | if (!isArray(object)) throw `${name || 'Argument'} is must be an Array.`;
36 | }
37 |
38 | export function argumentIsArrayAndNotEmpty(object, name) {
39 | argumentIsArray(object, name);
40 | if (isEmpty(object)) throw `${name || 'Argument'} is must not be empty.`;
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/Card/Card.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import withStyles from '@material-ui/core/styles/withStyles';
8 | // @material-ui/icons
9 |
10 | // core components
11 | import cardStyle from './cardStyle.jsx';
12 |
13 | function Card({ ...props }) {
14 | const {
15 | classes,
16 | className,
17 | children,
18 | plain,
19 | profile,
20 | chart,
21 | ...rest
22 | } = props;
23 | const cardClasses = classNames({
24 | [classes.card]: true,
25 | [classes.cardPlain]: plain,
26 | [classes.cardProfile]: profile,
27 | [classes.cardChart]: chart,
28 | [className]: className !== undefined
29 | });
30 | return (
31 |
32 | {children}
33 |
34 | );
35 | }
36 |
37 | Card.propTypes = {
38 | classes: PropTypes.object.isRequired,
39 | className: PropTypes.string,
40 | plain: PropTypes.bool,
41 | profile: PropTypes.bool,
42 | chart: PropTypes.bool
43 | };
44 |
45 | export default withStyles(cardStyle)(Card);
46 |
--------------------------------------------------------------------------------
/src/components/Card/CardAvatar.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import withStyles from '@material-ui/core/styles/withStyles';
8 | // @material-ui/icons
9 | // core components
10 |
11 | import cardAvatarStyle from './cardAvatarStyle.jsx';
12 |
13 | function CardAvatar({ ...props }) {
14 | const { classes, children, className, plain, profile, ...rest } = props;
15 | const cardAvatarClasses = classNames({
16 | [classes.cardAvatar]: true,
17 | [classes.cardAvatarProfile]: profile,
18 | [classes.cardAvatarPlain]: plain,
19 | [className]: className !== undefined
20 | });
21 | return (
22 |
23 | {children}
24 |
25 | );
26 | }
27 |
28 | CardAvatar.propTypes = {
29 | children: PropTypes.node.isRequired,
30 | className: PropTypes.string,
31 | profile: PropTypes.bool,
32 | plain: PropTypes.bool
33 | };
34 |
35 | export default withStyles(cardAvatarStyle)(CardAvatar);
36 |
--------------------------------------------------------------------------------
/src/components/Card/CardBody.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import withStyles from '@material-ui/core/styles/withStyles';
8 | // @material-ui/icons
9 |
10 | // core components
11 | import cardBodyStyle from './cardBodyStyle.jsx';
12 |
13 | function CardBody({ ...props }) {
14 | const { classes, className, children, plain, profile, ...rest } = props;
15 | const cardBodyClasses = classNames({
16 | [classes.cardBody]: true,
17 | [classes.cardBodyPlain]: plain,
18 | [classes.cardBodyProfile]: profile,
19 | [className]: className !== undefined
20 | });
21 | return (
22 |
23 | {children}
24 |
25 | );
26 | }
27 |
28 | CardBody.propTypes = {
29 | classes: PropTypes.object.isRequired,
30 | className: PropTypes.string,
31 | plain: PropTypes.bool,
32 | profile: PropTypes.bool
33 | };
34 |
35 | export default withStyles(cardBodyStyle)(CardBody);
36 |
--------------------------------------------------------------------------------
/src/components/Card/CardFooter.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | // nodejs library that concatenates classes
3 | import classNames from "classnames";
4 | // nodejs library to set properties for components
5 | import PropTypes from "prop-types";
6 | // @material-ui/core components
7 | import withStyles from "@material-ui/core/styles/withStyles";
8 | // @material-ui/icons
9 |
10 | // core components
11 | import cardFooterStyle from "./cardFooterStyle.jsx";
12 |
13 | function CardFooter({ ...props }) {
14 | const {
15 | classes,
16 | className,
17 | children,
18 | plain,
19 | profile,
20 | stats,
21 | chart,
22 | ...rest
23 | } = props;
24 | const cardFooterClasses = classNames({
25 | [classes.cardFooter]: true,
26 | [classes.cardFooterPlain]: plain,
27 | [classes.cardFooterProfile]: profile,
28 | [classes.cardFooterStats]: stats,
29 | [classes.cardFooterChart]: chart,
30 | [className]: className !== undefined
31 | });
32 | return (
33 |
34 | {children}
35 |
36 | );
37 | }
38 |
39 | CardFooter.propTypes = {
40 | classes: PropTypes.object.isRequired,
41 | className: PropTypes.string,
42 | plain: PropTypes.bool,
43 | profile: PropTypes.bool,
44 | stats: PropTypes.bool,
45 | chart: PropTypes.bool
46 | };
47 |
48 | export default withStyles(cardFooterStyle)(CardFooter);
49 |
--------------------------------------------------------------------------------
/src/components/Card/CardHeader.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | // nodejs library that concatenates classes
3 | import classNames from "classnames";
4 | // nodejs library to set properties for components
5 | import PropTypes from "prop-types";
6 | // @material-ui/core components
7 | import withStyles from "@material-ui/core/styles/withStyles";
8 | // @material-ui/icons
9 |
10 | // core components
11 | import cardHeaderStyle from "./cardHeaderStyle.jsx";
12 |
13 | function CardHeader({ ...props }) {
14 | const {
15 | classes,
16 | className,
17 | children,
18 | color,
19 | plain,
20 | stats,
21 | icon,
22 | ...rest
23 | } = props;
24 | const cardHeaderClasses = classNames({
25 | [classes.cardHeader]: true,
26 | [classes[color + "CardHeader"]]: color,
27 | [classes.cardHeaderPlain]: plain,
28 | [classes.cardHeaderStats]: stats,
29 | [classes.cardHeaderIcon]: icon,
30 | [className]: className !== undefined
31 | });
32 | return (
33 |
34 | {children}
35 |
36 | );
37 | }
38 |
39 | CardHeader.propTypes = {
40 | classes: PropTypes.object.isRequired,
41 | className: PropTypes.string,
42 | color: PropTypes.oneOf([
43 | "warning",
44 | "success",
45 | "danger",
46 | "info",
47 | "primary",
48 | "rose"
49 | ]),
50 | plain: PropTypes.bool,
51 | stats: PropTypes.bool,
52 | icon: PropTypes.bool
53 | };
54 |
55 | export default withStyles(cardHeaderStyle)(CardHeader);
56 |
--------------------------------------------------------------------------------
/src/components/Card/CardIcon.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // nodejs library that concatenates classes
3 | import classNames from 'classnames';
4 | // nodejs library to set properties for components
5 | import PropTypes from 'prop-types';
6 | // @material-ui/core components
7 | import withStyles from '@material-ui/core/styles/withStyles';
8 | // @material-ui/icons
9 |
10 | // core components
11 | import cardIconStyle from './cardIconStyle.jsx';
12 |
13 | function CardIcon({ ...props }) {
14 | const { classes, className, children, color, ...rest } = props;
15 | const cardIconClasses = classNames({
16 | [classes.cardIcon]: true,
17 | [classes[color + 'CardHeader']]: color,
18 | [className]: className !== undefined
19 | });
20 | return (
21 |
22 | {children}
23 |
24 | );
25 | }
26 |
27 | CardIcon.propTypes = {
28 | classes: PropTypes.object.isRequired,
29 | className: PropTypes.string,
30 | color: PropTypes.oneOf([
31 | 'warning',
32 | 'success',
33 | 'danger',
34 | 'info',
35 | 'primary',
36 | 'rose'
37 | ])
38 | };
39 |
40 | export default withStyles(cardIconStyle)(CardIcon);
41 |
--------------------------------------------------------------------------------
/src/components/Card/cardAvatarStyle.jsx:
--------------------------------------------------------------------------------
1 | const cardAvatarStyle = {
2 | cardAvatar: {
3 | '&$cardAvatarProfile img': {
4 | width: '100%',
5 | height: 'auto'
6 | }
7 | },
8 | cardAvatarProfile: {
9 | maxWidth: '130px',
10 | maxHeight: '130px',
11 | margin: '-50px auto 0',
12 | borderRadius: '50%',
13 | overflow: 'hidden',
14 | padding: '0',
15 | boxShadow:
16 | '0 16px 38px -12px rgba(0, 0, 0, 0.56), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2)',
17 | '&$cardAvatarPlain': {
18 | marginTop: '0'
19 | }
20 | },
21 | cardAvatarPlain: {}
22 | };
23 |
24 | export default cardAvatarStyle;
25 |
--------------------------------------------------------------------------------
/src/components/Card/cardBodyStyle.jsx:
--------------------------------------------------------------------------------
1 | const cardBodyStyle = {
2 | cardBody: {
3 | padding: "0.9375rem 20px",
4 | flex: "1 1 auto",
5 | WebkitBoxFlex: "1",
6 | position: "relative"
7 | },
8 | cardBodyPlain: {
9 | paddingLeft: "5px",
10 | paddingRight: "5px"
11 | },
12 | cardBodyProfile: {
13 | marginTop: "15px"
14 | }
15 | };
16 |
17 | export default cardBodyStyle;
18 |
--------------------------------------------------------------------------------
/src/components/Card/cardFooterStyle.jsx:
--------------------------------------------------------------------------------
1 | const cardFooterStyle = {
2 | cardFooter: {
3 | padding: "0",
4 | paddingTop: "10px",
5 | margin: "0 15px 10px",
6 | borderRadius: "0",
7 | justifyContent: "space-between",
8 | alignItems: "center",
9 | display: "flex",
10 | backgroundColor: "transparent",
11 | border: "0"
12 | },
13 | cardFooterProfile: {
14 | marginTop: "-15px"
15 | },
16 | cardFooterPlain: {
17 | paddingLeft: "5px",
18 | paddingRight: "5px",
19 | backgroundColor: "transparent"
20 | },
21 | cardFooterStats: {
22 | borderTop: "1px solid #eee",
23 | marginTop: "20px",
24 | "& svg": {
25 | position: "relative",
26 | top: "4px",
27 | marginRight: "3px",
28 | marginLeft: "3px",
29 | width: "16px",
30 | height: "16px"
31 | }
32 | },
33 | cardFooterChart: {
34 | borderTop: "1px solid #eee"
35 | }
36 | };
37 |
38 | export default cardFooterStyle;
39 |
--------------------------------------------------------------------------------
/src/components/Card/cardHeaderStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | warningCardHeader,
3 | successCardHeader,
4 | dangerCardHeader,
5 | infoCardHeader,
6 | primaryCardHeader,
7 | roseCardHeader
8 | } from "../../assets/jss/material-dashboard-react.jsx";
9 | const cardHeaderStyle = {
10 | cardHeader: {
11 | padding: "0.75rem 1.25rem",
12 | marginBottom: "0",
13 | borderBottom: "none",
14 | background: "transparent",
15 | zIndex: "3 !important",
16 | "&$cardHeaderPlain,&$cardHeaderIcon,&$cardHeaderStats,&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader": {
17 | margin: "0 15px",
18 | padding: "0",
19 | position: "relative",
20 | color: "#FFFFFF"
21 | },
22 | "&:first-child": {
23 | borderRadius: "calc(.25rem - 1px) calc(.25rem - 1px) 0 0"
24 | },
25 | "&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader": {
26 | "&:not($cardHeaderIcon)": {
27 | borderRadius: "3px",
28 | marginTop: "-20px",
29 | padding: "15px"
30 | }
31 | },
32 | "&$cardHeaderStats svg": {
33 | fontSize: "36px",
34 | lineHeight: "56px",
35 | textAlign: "center",
36 | width: "36px",
37 | height: "36px",
38 | margin: "10px 10px 4px"
39 | },
40 | "&$cardHeaderStats i": {
41 | fontSize: "36px",
42 | lineHeight: "56px",
43 | width: "56px",
44 | height: "56px",
45 | textAlign: "center"
46 | },
47 | "&$cardHeaderStats$cardHeaderIcon": {
48 | textAlign: "right"
49 | }
50 | },
51 | cardHeaderPlain: {
52 | marginLeft: "0px !important",
53 | marginRight: "0px !important"
54 | },
55 | cardHeaderStats: {
56 | "& $cardHeaderIcon": {
57 | textAlign: "right"
58 | },
59 | "& h1,& h2,& h3,& h4,& h5,& h6": {
60 | margin: "0 !important"
61 | }
62 | },
63 | cardHeaderIcon: {
64 | "&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader": {
65 | background: "transparent",
66 | boxShadow: "none"
67 | },
68 | "& i": {
69 | width: "33px",
70 | height: "33px",
71 | textAlign: "center",
72 | lineHeight: "33px"
73 | },
74 | "& svg": {
75 | width: "24px",
76 | height: "24px",
77 | textAlign: "center",
78 | lineHeight: "33px",
79 | margin: "5px 4px 0px"
80 | }
81 | },
82 | warningCardHeader: {
83 | color: "#FFFFFF",
84 | "&:not($cardHeaderIcon)": {
85 | ...warningCardHeader
86 | }
87 | },
88 | successCardHeader: {
89 | color: "#FFFFFF",
90 | "&:not($cardHeaderIcon)": {
91 | ...successCardHeader
92 | }
93 | },
94 | dangerCardHeader: {
95 | color: "#FFFFFF",
96 | "&:not($cardHeaderIcon)": {
97 | ...dangerCardHeader
98 | }
99 | },
100 | infoCardHeader: {
101 | color: "#FFFFFF",
102 | "&:not($cardHeaderIcon)": {
103 | ...infoCardHeader
104 | }
105 | },
106 | primaryCardHeader: {
107 | color: "#FFFFFF",
108 | "&:not($cardHeaderIcon)": {
109 | ...primaryCardHeader
110 | }
111 | },
112 | roseCardHeader: {
113 | color: "#FFFFFF",
114 | "&:not($cardHeaderIcon)": {
115 | ...roseCardHeader
116 | }
117 | }
118 | };
119 |
120 | export default cardHeaderStyle;
121 |
--------------------------------------------------------------------------------
/src/components/Card/cardIconStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | warningCardHeader,
3 | successCardHeader,
4 | dangerCardHeader,
5 | infoCardHeader,
6 | primaryCardHeader,
7 | roseCardHeader
8 | } from "../../assets/jss/material-dashboard-react.jsx";
9 | const cardIconStyle = {
10 | cardIcon: {
11 | "&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader": {
12 | borderRadius: "3px",
13 | backgroundColor: "#999",
14 | padding: "15px",
15 | marginTop: "-20px",
16 | marginRight: "15px",
17 | float: "left"
18 | }
19 | },
20 | warningCardHeader,
21 | successCardHeader,
22 | dangerCardHeader,
23 | infoCardHeader,
24 | primaryCardHeader,
25 | roseCardHeader
26 | };
27 |
28 | export default cardIconStyle;
29 |
--------------------------------------------------------------------------------
/src/components/Card/cardStyle.jsx:
--------------------------------------------------------------------------------
1 | const cardStyle = {
2 | card: {
3 | border: "0",
4 | marginBottom: "30px",
5 | marginTop: "30px",
6 | borderRadius: "6px",
7 | color: "rgba(0, 0, 0, 0.87)",
8 | background: "#fff",
9 | width: "100%",
10 | boxShadow: "0 1px 4px 0 rgba(0, 0, 0, 0.14)",
11 | position: "relative",
12 | display: "flex",
13 | flexDirection: "column",
14 | minWidth: "0",
15 | wordWrap: "break-word",
16 | fontSize: ".875rem"
17 | },
18 | cardPlain: {
19 | background: "transparent",
20 | boxShadow: "none"
21 | },
22 | cardProfile: {
23 | marginTop: "30px",
24 | textAlign: "center"
25 | },
26 | cardChart: {
27 | "& p": {
28 | marginTop: "0px",
29 | paddingTop: "0px"
30 | }
31 | }
32 | };
33 |
34 | export default cardStyle;
35 |
--------------------------------------------------------------------------------
/src/components/CustomButtons/Button.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | // nodejs library that concatenates classes
3 | import classNames from "classnames";
4 | // nodejs library to set properties for components
5 | import PropTypes from "prop-types";
6 |
7 | // material-ui components
8 | import withStyles from "@material-ui/core/styles/withStyles";
9 | import Button from "@material-ui/core/Button";
10 |
11 | import buttonStyle from "./buttonStyle.jsx";
12 | function RegularButton({ ...props }) {
13 | const {
14 | classes,
15 | color,
16 | round,
17 | children,
18 | disabled,
19 | simple,
20 | size,
21 | block,
22 | link,
23 | justIcon,
24 | className,
25 | muiClasses,
26 | ...rest
27 | } = props;
28 | const btnClasses = classNames({
29 | [classes.button]: true,
30 | [classes[size]]: size,
31 | [classes[color]]: color,
32 | [classes.round]: round,
33 | [classes.disabled]: disabled,
34 | [classes.simple]: simple,
35 | [classes.block]: block,
36 | [classes.link]: link,
37 | [classes.justIcon]: justIcon,
38 | [className]: className
39 | });
40 | return (
41 |
42 | {children}
43 |
44 | );
45 | }
46 |
47 | RegularButton.propTypes = {
48 | classes: PropTypes.object.isRequired,
49 | color: PropTypes.oneOf([
50 | "primary",
51 | "info",
52 | "success",
53 | "warning",
54 | "danger",
55 | "rose",
56 | "white",
57 | "transparent"
58 | ]),
59 | size: PropTypes.oneOf(["sm", "lg"]),
60 | simple: PropTypes.bool,
61 | round: PropTypes.bool,
62 | disabled: PropTypes.bool,
63 | block: PropTypes.bool,
64 | link: PropTypes.bool,
65 | justIcon: PropTypes.bool,
66 | className: PropTypes.string,
67 | // use this to pass the classes props from Material-UI
68 | muiClasses: PropTypes.object
69 | };
70 |
71 | export default withStyles(buttonStyle)(RegularButton);
72 |
--------------------------------------------------------------------------------
/src/components/CustomInput/CustomInput.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import classNames from "classnames";
3 | import PropTypes from "prop-types";
4 | // @material-ui/core components
5 | import withStyles from "@material-ui/core/styles/withStyles";
6 | import FormControl from "@material-ui/core/FormControl";
7 | import InputLabel from "@material-ui/core/InputLabel";
8 | import Input from "@material-ui/core/Input";
9 | // @material-ui/icons
10 | import Clear from "@material-ui/icons/Clear";
11 | import Check from "@material-ui/icons/Check";
12 | // core components
13 | import customInputStyle from "./customInputStyle";
14 | import FormHelperText from "@material-ui/core/FormHelperText";
15 |
16 | function CustomInput({ ...props }) {
17 | const {
18 | classes,
19 | formControlProps,
20 | labelText,
21 | id,
22 | labelProps,
23 | inputProps,
24 | error,
25 | errorText,
26 | success
27 | } = props;
28 |
29 | const labelClasses = classNames({
30 | [" " + classes.labelRootError]: error,
31 | [" " + classes.labelRootSuccess]: success && !error
32 | });
33 | const underlineClasses = classNames({
34 | [classes.underlineError]: error,
35 | [classes.underlineSuccess]: success && !error,
36 | [classes.underline]: true
37 | });
38 | const marginTop = classNames({
39 | [classes.marginTop]: labelText === undefined
40 | });
41 | return (
42 |
46 | {labelText !== undefined ? (
47 |
52 | {labelText}
53 |
54 | ) : null}
55 |
64 | {error ? (
65 |
66 |
67 | {errorText}
68 |
69 | ) : success ? (
70 |
71 | ) : null}
72 |
73 | );
74 | }
75 |
76 | CustomInput.propTypes = {
77 | classes: PropTypes.object.isRequired,
78 | labelText: PropTypes.node,
79 | labelProps: PropTypes.object,
80 | id: PropTypes.string,
81 | inputProps: PropTypes.object,
82 | formControlProps: PropTypes.object,
83 | error: PropTypes.bool,
84 | success: PropTypes.bool
85 | };
86 |
87 | export default withStyles(customInputStyle)(CustomInput);
88 |
--------------------------------------------------------------------------------
/src/components/CustomInput/customInputStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | primaryColor,
3 | dangerColor,
4 | successColor,
5 | defaultFont
6 | } from "../../assets/jss/material-dashboard-react.jsx";
7 |
8 | const customInputStyle = {
9 | disabled: {
10 | "&:before": {
11 | backgroundColor: "transparent !important"
12 | }
13 | },
14 | underline: {
15 | "&:hover:not($disabled):before,&:before": {
16 | borderColor: "#D2D2D2 !important",
17 | borderWidth: "1px !important"
18 | },
19 | "&:after": {
20 | borderColor: primaryColor
21 | }
22 | },
23 | underlineError: {
24 | "&:after": {
25 | borderColor: dangerColor
26 | }
27 | },
28 | underlineSuccess: {
29 | "&:after": {
30 | borderColor: successColor
31 | }
32 | },
33 | labelRoot: {
34 | ...defaultFont,
35 | color: "#AAAAAA !important",
36 | fontWeight: "400",
37 | fontSize: "14px",
38 | lineHeight: "1.42857"
39 | },
40 | labelRootError: {
41 | color: dangerColor
42 | },
43 | labelRootSuccess: {
44 | color: successColor
45 | },
46 | feedback: {
47 | position: "absolute",
48 | top: "18px",
49 | right: "0",
50 | zIndex: "2",
51 | display: "block",
52 | width: "24px",
53 | height: "24px",
54 | textAlign: "center",
55 | pointerEvents: "none"
56 | },
57 | marginTop: {
58 | marginTop: "16px"
59 | },
60 | formControl: {
61 | paddingBottom: "10px",
62 | margin: "27px 0 0 0",
63 | position: "relative"
64 | }
65 | };
66 |
67 | export default customInputStyle;
68 |
--------------------------------------------------------------------------------
/src/components/CustomTabs/CustomTabs.jsx:
--------------------------------------------------------------------------------
1 | // core components
2 | import Card from '../Card/Card.jsx';
3 | import CardBody from '../Card/CardBody.jsx';
4 | import CardHeader from '../Card/CardHeader.jsx';
5 | import LinearProgress from '@material-ui/core/LinearProgress';
6 | // nodejs library to set properties for components
7 | import PropTypes from 'prop-types';
8 | import React from 'react';
9 | import Tab from '@material-ui/core/Tab';
10 | import Tabs from '@material-ui/core/Tabs';
11 | // nodejs library that concatenates classes
12 | import classNames from 'classnames';
13 | import customTabsStyle from './customTabsStyle.jsx';
14 | // material-ui components
15 | import withStyles from '@material-ui/core/styles/withStyles';
16 |
17 | class CustomTabs extends React.Component {
18 | state = {
19 | value: 0
20 | };
21 |
22 | handleChange = (event, value) => {
23 | this.setState({ value });
24 | };
25 |
26 | render() {
27 | const {
28 | classes,
29 | headerColor,
30 | plainTabs,
31 | tabs,
32 | title,
33 | rtlActive,
34 | loading
35 | } = this.props;
36 | const cardTitle = classNames({
37 | [classes.cardTitle]: true,
38 | [classes.cardTitleRTL]: rtlActive
39 | });
40 | return (
41 |
42 |
43 | {title !== undefined ? (
44 | {title}
45 | ) : null}
46 |
56 | {tabs.map((prop, key) => {
57 | let icon = {};
58 | if (prop.tabIcon) {
59 | icon = {
60 | icon:
61 | };
62 | }
63 | return (
64 |
76 | );
77 | })}
78 |
79 | {loading && }
80 |
81 |
82 | {tabs.map((prop, key) => {
83 | if (key === this.state.value) {
84 | return {prop.tabContent}
;
85 | }
86 | return null;
87 | })}
88 |
89 |
90 | );
91 | }
92 | }
93 |
94 | CustomTabs.propTypes = {
95 | classes: PropTypes.object.isRequired,
96 | headerColor: PropTypes.oneOf([
97 | 'warning',
98 | 'success',
99 | 'danger',
100 | 'info',
101 | 'primary'
102 | ]),
103 | title: PropTypes.string,
104 | tabs: PropTypes.arrayOf(
105 | PropTypes.shape({
106 | tabName: PropTypes.string.isRequired,
107 | tabIcon: PropTypes.func,
108 | tabContent: PropTypes.node.isRequired
109 | })
110 | ),
111 | rtlActive: PropTypes.bool,
112 | plainTabs: PropTypes.bool
113 | };
114 |
115 | export default withStyles(customTabsStyle)(CustomTabs);
116 |
--------------------------------------------------------------------------------
/src/components/CustomTabs/customTabsStyle.jsx:
--------------------------------------------------------------------------------
1 | const customTabsStyle = {
2 | cardTitle: {
3 | float: "left",
4 | padding: "10px 10px 10px 0px",
5 | lineHeight: "24px"
6 | },
7 | cardTitleRTL: {
8 | float: "right",
9 | padding: "10px 0px 10px 10px !important"
10 | },
11 | displayNone: {
12 | display: "none !important"
13 | },
14 | tabsRoot: {
15 | minHeight: "unset !important"
16 | },
17 | tabRootButton: {
18 | minHeight: "unset !important",
19 | minWidth: "unset !important",
20 | width: "unset !important",
21 | height: "unset !important",
22 | maxWidth: "unset !important",
23 | maxHeight: "unset !important",
24 | padding: "10px 15px",
25 | borderRadius: "3px",
26 | lineHeight: "24px",
27 | border: "0 !important",
28 | color: "#fff !important",
29 | marginLeft: "4px",
30 | "&:last-child": {
31 | marginLeft: "0px"
32 | }
33 | },
34 | tabLabelContainer: {
35 | padding: "0px"
36 | },
37 | tabLabel: {
38 | fontWeight: "500",
39 | fontSize: "12px"
40 | },
41 | tabSelected: {
42 | backgroundColor: "rgba(255, 255, 255, 0.2)",
43 | transition: "0.2s background-color 0.1s"
44 | },
45 | tabWrapper: {
46 | display: "inline-block",
47 | minHeight: "unset !important",
48 | minWidth: "unset !important",
49 | width: "unset !important",
50 | height: "unset !important",
51 | maxWidth: "unset !important",
52 | maxHeight: "unset !important",
53 | "& > svg": {
54 | verticalAlign: "middle",
55 | margin: "-1px 5px 0 0"
56 | }
57 | }
58 | };
59 |
60 | export default customTabsStyle;
61 |
--------------------------------------------------------------------------------
/src/components/Footer/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | import ListItem from "@material-ui/core/ListItem";
6 | import List from "@material-ui/core/List";
7 | // core components
8 | import footerStyle from "./footerStyle";
9 |
10 | function Footer({ ...props }) {
11 | const { classes } = props;
12 | return (
13 |
49 | );
50 | }
51 |
52 | Footer.propTypes = {
53 | classes: PropTypes.object.isRequired
54 | };
55 |
56 | export default withStyles(footerStyle)(Footer);
57 |
--------------------------------------------------------------------------------
/src/components/Footer/footerStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | container,
4 | primaryColor
5 | } from "../../assets/jss/material-dashboard-react.jsx";
6 |
7 | const footerStyle = {
8 | block: {
9 | color: "inherit",
10 | padding: "15px",
11 | textTransform: "uppercase",
12 | borderRadius: "3px",
13 | textDecoration: "none",
14 | position: "relative",
15 | display: "block",
16 | ...defaultFont,
17 | fontWeight: "500",
18 | fontSize: "12px"
19 | },
20 | left: {
21 | float: "left!important",
22 | display: "block"
23 | },
24 | right: {
25 | padding: "15px 0",
26 | margin: "0",
27 | fontSize: "14px",
28 | float: "right!important"
29 | },
30 | footer: {
31 | bottom: "0",
32 | borderTop: "1px solid #e7e7e7",
33 | padding: "15px 0",
34 | ...defaultFont
35 | },
36 | container,
37 | a: {
38 | color: primaryColor,
39 | textDecoration: "none",
40 | backgroundColor: "transparent"
41 | },
42 | list: {
43 | marginBottom: "0",
44 | padding: "0",
45 | marginTop: "0"
46 | },
47 | inlineBlock: {
48 | display: "inline-block",
49 | paddingTop: "0px",
50 | width: "auto"
51 | }
52 | };
53 | export default footerStyle;
54 |
--------------------------------------------------------------------------------
/src/components/Grid/GridItem.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | // @material-ui/core components
3 | import withStyles from "@material-ui/core/styles/withStyles";
4 | import Grid from "@material-ui/core/Grid";
5 |
6 | const style = {
7 | grid: {
8 | padding: "0 15px !important"
9 | }
10 | };
11 |
12 | function GridItem({ ...props }) {
13 | const { classes, children, ...rest } = props;
14 | return (
15 |
16 | {children}
17 |
18 | );
19 | }
20 |
21 | export default withStyles(style)(GridItem);
22 |
--------------------------------------------------------------------------------
/src/components/Header/Header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classNames from 'classnames';
3 | import PropTypes from 'prop-types';
4 | // @material-ui/core components
5 | import withStyles from '@material-ui/core/styles/withStyles';
6 | import AppBar from '@material-ui/core/AppBar';
7 | import Toolbar from '@material-ui/core/Toolbar';
8 | import IconButton from '@material-ui/core/IconButton';
9 | import Hidden from '@material-ui/core/Hidden';
10 | // @material-ui/icons
11 | import Menu from '@material-ui/icons/Menu';
12 | // core components
13 | import HeaderLinks from './HeaderLinks';
14 |
15 | import headerStyle from './headerStyle.jsx';
16 |
17 | function Header({
18 | classes,
19 | color,
20 | routes,
21 | location,
22 | path,
23 | handleDrawerToggle,
24 | ...others
25 | }) {
26 | function makeBrand() {
27 | let name;
28 | routes.map(prop => {
29 | if (path === location.pathname) {
30 | name = prop.navbarName;
31 | }
32 | return null;
33 | });
34 | return name;
35 | }
36 |
37 | const appBarClasses = classNames({
38 | [' ' + classes[color]]: color
39 | });
40 | return (
41 |
42 |
43 |
44 | {/* Here we create navbar brand, based on route name */}
45 | {makeBrand()}
46 |
47 |
48 |
49 |
50 |
51 |
57 |
58 |
59 |
60 |
61 |
62 | );
63 | }
64 |
65 | Header.propTypes = {
66 | classes: PropTypes.object.isRequired,
67 | color: PropTypes.oneOf(['primary', 'info', 'success', 'warning', 'danger']),
68 | notificationBackgroundImage: PropTypes.string,
69 | notifications: PropTypes.array,
70 | onNotificationChange: PropTypes.func.isRequired,
71 | onNotificationDelete: PropTypes.func.isRequired
72 | };
73 |
74 | export default withStyles(headerStyle)(Header);
75 |
--------------------------------------------------------------------------------
/src/components/Header/HeaderLinks.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | //import { Manager, Target, Popper } from "react-popper";
3 | // @material-ui/core components
4 | import withStyles from '@material-ui/core/styles/withStyles';
5 | import Hidden from '@material-ui/core/Hidden';
6 | // @material-ui/icons
7 | import Person from '@material-ui/icons/Person';
8 | import Dashboard from '@material-ui/icons/Dashboard';
9 | import Search from '@material-ui/icons/Search';
10 | // core components
11 | import CustomInput from '../CustomInput/CustomInput.jsx';
12 | import Button from '../CustomButtons/Button.jsx';
13 |
14 | import NotificationCenter from '../../components/Notification';
15 | import headerLinksStyle from './headerLinksStyle';
16 |
17 | function HeaderLinks({
18 | classes,
19 | notifications,
20 | onNotificationChange,
21 | onNotificationDelete,
22 | notificationBackgroundImage,
23 | ...others
24 | }) {
25 | return (
26 |
27 |
28 |
39 |
40 |
41 |
42 |
43 |
959 ? 'transparent' : 'white'}
45 | justIcon={window.innerWidth > 959}
46 | simple={!(window.innerWidth > 959)}
47 | aria-label="Dashboard"
48 | className={classes.buttonLink}
49 | >
50 |
51 |
52 | Dashboard
53 |
54 |
55 |
959 ? 'transparent' : 'white',
59 | justIcon: window.innerWidth > 959,
60 | simple: !(window.innerWidth > 959),
61 | classes: {
62 | button: classes.buttonLink,
63 | icon: classes.icons
64 | }
65 | }}
66 | items={notifications}
67 | onChange={onNotificationChange}
68 | onDelete={onNotificationDelete}
69 | image={notificationBackgroundImage}
70 | />
71 | 959 ? 'transparent' : 'white'}
73 | justIcon={window.innerWidth > 959}
74 | simple={!(window.innerWidth > 959)}
75 | aria-label="Person"
76 | className={classes.buttonLink}
77 | >
78 |
79 |
80 | Profile
81 |
82 |
83 |
84 | );
85 | }
86 |
87 | export default withStyles(headerLinksStyle)(HeaderLinks);
88 |
--------------------------------------------------------------------------------
/src/components/Header/headerLinksStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | dangerColor
4 | } from "../../assets/jss/material-dashboard-react";
5 |
6 | import dropdownStyle from "../../assets/jss/material-dashboard-react/dropdownStyle";
7 |
8 | const headerLinksStyle = theme => ({
9 | ...dropdownStyle(theme),
10 | search: {
11 | "& > div": {
12 | marginTop: "0"
13 | },
14 | [theme.breakpoints.down("sm")]: {
15 | margin: "10px 15px !important",
16 | float: "none !important",
17 | paddingTop: "1px",
18 | paddingBottom: "1px",
19 | padding: "0!important",
20 | width: "60%",
21 | marginTop: "40px",
22 | "& input": {
23 | color: "#FFFFFF"
24 | }
25 | }
26 | },
27 | linkText: {
28 | zIndex: "4",
29 | ...defaultFont,
30 | fontSize: "14px",
31 | margin: "0px"
32 | },
33 | buttonLink: {
34 | [theme.breakpoints.down("sm")]: {
35 | display: "flex",
36 | margin: "10px 15px 0",
37 | width: "-webkit-fill-available",
38 | "& svg": {
39 | width: "24px",
40 | height: "30px",
41 | marginRight: "15px",
42 | marginLeft: "-15px"
43 | },
44 | "& > span": {
45 | justifyContent: "flex-start"
46 | }
47 | }
48 | },
49 | searchButton: {
50 | [theme.breakpoints.down("sm")]: {
51 | top: "-50px !important",
52 | marginRight: "22px",
53 | float: "right"
54 | }
55 | },
56 | margin: {
57 | zIndex: "4",
58 | margin: "0"
59 | },
60 | searchIcon: {
61 | width: "17px",
62 | zIndex: "4"
63 | },
64 | notifications: {
65 | zIndex: "4",
66 | [theme.breakpoints.up("md")]: {
67 | position: "absolute",
68 | top: "2px",
69 | border: "1px solid #FFF",
70 | right: "4px",
71 | fontSize: "9px",
72 | background: dangerColor,
73 | color: "#FFFFFF",
74 | minWidth: "16px",
75 | height: "16px",
76 | borderRadius: "10px",
77 | textAlign: "center",
78 | lineHeight: "16px",
79 | verticalAlign: "middle",
80 | display: "block"
81 | },
82 | [theme.breakpoints.down("sm")]: {
83 | ...defaultFont,
84 | fontSize: "14px",
85 | marginRight: "8px"
86 | }
87 | },
88 | manager: {
89 | [theme.breakpoints.down("sm")]: {
90 | width: "100%"
91 | },
92 | display: "inline-block"
93 | },
94 | searchWrapper: {
95 | [theme.breakpoints.down("sm")]: {
96 | width: "-webkit-fill-available",
97 | margin: "10px 15px 0"
98 | },
99 | display: "inline-block"
100 | }
101 | });
102 |
103 | export default headerLinksStyle;
104 |
--------------------------------------------------------------------------------
/src/components/Header/headerStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | container,
3 | defaultFont,
4 | primaryColor,
5 | defaultBoxShadow,
6 | infoColor,
7 | successColor,
8 | warningColor,
9 | dangerColor
10 | } from "../../assets/jss/material-dashboard-react.jsx";
11 |
12 | const headerStyle = theme => ({
13 | appBar: {
14 | backgroundColor: "transparent",
15 | boxShadow: "none",
16 | borderBottom: "0",
17 | marginBottom: "0",
18 | position: "absolute",
19 | width: "100%",
20 | paddingTop: "10px",
21 | zIndex: "1029",
22 | color: "#555555",
23 | border: "0",
24 | borderRadius: "3px",
25 | padding: "10px 0",
26 | transition: "all 150ms ease 0s",
27 | minHeight: "50px",
28 | display: "block"
29 | },
30 | container: {
31 | ...container,
32 | minHeight: "50px"
33 | },
34 | flex: {
35 | flex: 1
36 | },
37 | title: {
38 | ...defaultFont,
39 | lineHeight: "30px",
40 | fontSize: "18px",
41 | borderRadius: "3px",
42 | textTransform: "none",
43 | color: "inherit",
44 | "&:hover,&:focus": {
45 | background: "transparent"
46 | }
47 | },
48 | appResponsive: {
49 | top: "8px"
50 | },
51 | primary: {
52 | backgroundColor: primaryColor,
53 | color: "#FFFFFF",
54 | ...defaultBoxShadow
55 | },
56 | info: {
57 | backgroundColor: infoColor,
58 | color: "#FFFFFF",
59 | ...defaultBoxShadow
60 | },
61 | success: {
62 | backgroundColor: successColor,
63 | color: "#FFFFFF",
64 | ...defaultBoxShadow
65 | },
66 | warning: {
67 | backgroundColor: warningColor,
68 | color: "#FFFFFF",
69 | ...defaultBoxShadow
70 | },
71 | danger: {
72 | backgroundColor: dangerColor,
73 | color: "#FFFFFF",
74 | ...defaultBoxShadow
75 | }
76 | });
77 |
78 | export default headerStyle;
79 |
--------------------------------------------------------------------------------
/src/components/MessageBox/MessageBoxType.jsx:
--------------------------------------------------------------------------------
1 | const MessageBoxType = {
2 | SUCCESS: 'success',
3 | DANGER: 'danger',
4 | WARNING: 'warning',
5 | INFO: 'info',
6 | CONFIRM: 'confirm'
7 | };
8 |
9 | export default MessageBoxType;
10 |
--------------------------------------------------------------------------------
/src/components/MessageBox/helper.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Button from "@material-ui/core/Button";
3 | import MessageBoxType from "./MessageBoxType";
4 | import SvgIcon from "@material-ui/core/SvgIcon";
5 |
6 | export function getTitleClasses(type, classes) {
7 | switch (type) {
8 | case MessageBoxType.CONFIRM:
9 | return classes.confirm;
10 | case MessageBoxType.DANGER:
11 | return classes.danger;
12 | case MessageBoxType.WARNING:
13 | return classes.warning;
14 | case MessageBoxType.SUCCESS:
15 | return classes.success;
16 | case MessageBoxType.INFO:
17 | default:
18 | return classes.info;
19 | }
20 | }
21 |
22 | export function getTitle(type) {
23 | switch (type) {
24 | case MessageBoxType.CONFIRM:
25 | return "Confirmation";
26 | case MessageBoxType.DANGER:
27 | return "Error";
28 | case MessageBoxType.WARNING:
29 | return "Warning";
30 | case MessageBoxType.SUCCESS:
31 | return "Successfully";
32 | case MessageBoxType.INFO:
33 | default:
34 | return "Information";
35 | }
36 | }
37 |
38 | export function getIcon(type, classes) {
39 | const style = {
40 | fontSize: 100,
41 | float: "left",
42 | paddingTop: "5px"
43 | };
44 | switch (type) {
45 | case MessageBoxType.CONFIRM:
46 | return (
47 |
48 |
49 |
50 | );
51 | case MessageBoxType.DANGER:
52 | return (
53 |
54 |
55 |
56 | );
57 | case MessageBoxType.WARNING:
58 | return (
59 |
60 |
61 |
62 | );
63 | case MessageBoxType.SUCCESS:
64 | return (
65 |
66 |
67 |
68 | );
69 | case MessageBoxType.INFO:
70 | default:
71 | return (
72 |
73 |
74 |
75 | );
76 | }
77 | }
78 |
79 | export function getActions(type, handler, classes, okText, cancelText) {
80 | const okButton = (
81 |
90 | {okText}
91 |
92 | );
93 |
94 | const cancelButton = (
95 |
102 | {cancelText}
103 |
104 | );
105 |
106 | switch (type) {
107 | case MessageBoxType.CONFIRM:
108 | return [cancelButton, okButton];
109 | case MessageBoxType.DANGER:
110 | return [okButton];
111 | case MessageBoxType.WARNING:
112 | return [okButton];
113 | case MessageBoxType.SUCCESS:
114 | return [okButton];
115 | case MessageBoxType.INFO:
116 | default:
117 | return [okButton];
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/components/MessageBox/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import Grid from '@material-ui/core/Grid';
4 | import GridItem from '../Grid/GridItem.jsx';
5 | import Dialog from '@material-ui/core/Dialog';
6 | import DialogActions from '@material-ui/core/DialogActions';
7 | import DialogContent from '@material-ui/core/DialogContent';
8 | import Typography from '@material-ui/core/Typography';
9 | import { withStyles } from '@material-ui/core/styles';
10 | import MessageBoxStyle from './jss';
11 | import MessageBoxType from './MessageBoxType';
12 | import * as helper from './helper';
13 |
14 | function MessageBox({
15 | type,
16 | open,
17 | title,
18 | message,
19 | actionHandler,
20 | icon,
21 | okText,
22 | cancelText,
23 | classes,
24 | ...other
25 | }) {
26 | let finalIcon = icon;
27 | if (icon === true) finalIcon = helper.getIcon(type, classes);
28 |
29 | return (
30 |
38 |
43 | {title || helper.getTitle(type)}
44 |
45 |
46 |
53 | {finalIcon && (
54 |
55 | {finalIcon}
56 |
57 | )}
58 |
59 |
60 | {message}
61 |
62 |
63 |
64 |
65 | {helper.getActions(type, actionHandler, classes, okText, cancelText)}
66 |
67 |
68 | );
69 | }
70 |
71 | MessageBox.defaultProps = {
72 | type: MessageBoxType.INFO,
73 | okText: 'Ok',
74 | cancelText: 'Cancel',
75 | open: true,
76 | icon: true
77 | };
78 |
79 | MessageBox.propTypes = {
80 | //The type of Message box
81 | type: PropTypes.oneOf([
82 | MessageBoxType.CONFIRM,
83 | MessageBoxType.DANGER,
84 | MessageBoxType.INFO,
85 | MessageBoxType.SUCCESS,
86 | MessageBoxType.WARNING
87 | ]),
88 | //The title of message box
89 | title: PropTypes.string,
90 | //show/hide message box
91 | open: PropTypes.bool.isRequired,
92 | //the message
93 | message: PropTypes.string,
94 | //the text of Ok button
95 | okText: PropTypes.string,
96 | //the text of cancel button
97 | cancelText: PropTypes.string,
98 | //buttons action handler.
99 | actionHandler: PropTypes.func,
100 | //The icon of notification. set to false to hide the default icon.
101 | icon: PropTypes.oneOfType([PropTypes.element, PropTypes.bool])
102 | };
103 |
104 | export default withStyles(MessageBoxStyle)(MessageBox);
105 |
--------------------------------------------------------------------------------
/src/components/MessageBox/jss.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | primaryColor,
3 | infoColor,
4 | successColor,
5 | warningColor,
6 | dangerColor
7 | } from "../../assets/jss/material-dashboard-react.jsx";
8 |
9 | const titleType = {
10 | paddingTop: "12px",
11 | paddingBottom: "12px",
12 | paddingLeft: "25px",
13 | paddingRight: "25px",
14 | color: "white",
15 | fontWeight: "600"
16 | };
17 |
18 | const MessageBoxStyle = {
19 | dialog: {
20 | minWidth: "40%",
21 | maxWidth: "65%"
22 | },
23 | dialogContent: { padding: "1px !important", margin: "1px !important" },
24 | content: {
25 | fontSize: "20px",
26 | display: "table"
27 | },
28 | button: {
29 | minWidth: "80px"
30 | },
31 | confirm: {
32 | backgroundColor: primaryColor,
33 | ...titleType
34 | },
35 | confirmIcon: {
36 | color: primaryColor
37 | },
38 | info: {
39 | backgroundColor: infoColor,
40 | ...titleType
41 | },
42 | infoIcon: {
43 | color: infoColor
44 | },
45 | success: {
46 | backgroundColor: successColor,
47 | ...titleType
48 | },
49 | successIcon: {
50 | color: successColor
51 | },
52 | warning: {
53 | backgroundColor: warningColor,
54 | ...titleType
55 | },
56 | warningIcon: {
57 | color: warningColor
58 | },
59 | danger: {
60 | backgroundColor: dangerColor,
61 | ...titleType
62 | },
63 | dangerIcon: {
64 | color: dangerColor
65 | }
66 | };
67 |
68 | export default MessageBoxStyle;
69 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationGroup.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | List,
5 | Collapse,
6 | ListItem,
7 | ListItemAvatar,
8 | Avatar,
9 | ListItemText,
10 | Divider,
11 | IconButton,
12 | Tooltip
13 | } from '@material-ui/core';
14 | import withStyles from '@material-ui/core/styles/withStyles';
15 | import CloseIcon from '@material-ui/icons/Close';
16 | import classnames from 'classnames';
17 |
18 | import NotificationGroupStyle from './NotificationGroupStyle';
19 | import NotificationItem from './NotificationItem';
20 | import NotificationItemPropTypes from './NotificationItemPropTypes';
21 | //helper
22 | import { getUnreadItems } from './helper';
23 |
24 | @withStyles(NotificationGroupStyle)
25 | export default class NotificationGroup extends React.PureComponent {
26 | constructor(props, context) {
27 | super(props, context);
28 |
29 | this.state = { open: props.open };
30 | }
31 |
32 | onClick = () => this.setState(p => ({ open: !p.open }));
33 |
34 | onItemClose = item => {
35 | const { onClose } = this.props;
36 | if (onClose) onClose([item]);
37 | };
38 |
39 | onClose = () => {
40 | const { onClose, items } = this.props;
41 | if (onClose) onClose(items);
42 | };
43 |
44 | render() {
45 | const { title, items, classes } = this.props;
46 | const unReadItems = getUnreadItems(items);
47 |
48 | return (
49 |
50 |
58 |
59 | 0
63 | ? classes.avatarNew
64 | : this.state.open
65 | ? classes.avatarHighlight
66 | : ''
67 | )}
68 | >
69 | {unReadItems.length > 0 ? unReadItems.length : items.length}
70 |
71 |
72 |
76 | {this.state.open && (
77 |
82 |
83 |
84 |
85 |
86 | )}
87 |
88 |
89 |
90 |
91 | {items.map((n, i) => (
92 |
93 | {
96 | this.onItemClose(n);
97 | //stop event bubbling on click
98 | e.preventDefault();
99 | e.stopPropagation();
100 | return false;
101 | }}
102 | />
103 |
104 |
105 | ))}
106 |
107 |
108 |
109 |
110 | );
111 | }
112 | }
113 |
114 | NotificationGroup.defaultProps = {
115 | badgeColor: 'primary',
116 | open: false
117 | };
118 |
119 | NotificationGroup.propTypes = {
120 | //the title of notification
121 | title: PropTypes.string,
122 | items: PropTypes.arrayOf(PropTypes.shape(NotificationItemPropTypes))
123 | .isRequired,
124 | //Close handler.
125 | onClose: PropTypes.func,
126 | open: PropTypes.bool,
127 | badgeColor: PropTypes.oneOf([
128 | 'inherit',
129 | 'primary',
130 | 'secondary',
131 | 'default',
132 | 'error'
133 | ])
134 | };
135 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationGroupStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | primaryColor,
3 | infoColor,
4 | warningColor
5 | } from "../../assets/jss/material-dashboard-react";
6 |
7 | import { closeButton, tooltip } from "./jss";
8 |
9 | const NotificationGroupStyle = theme => ({
10 | root: {
11 | width: "auto",
12 | transition: "all 300ms linear",
13 | margin: "5px 5px 0",
14 | borderRadius: "3px",
15 | position: "relative",
16 | padding: "10px 10px",
17 | borderBottom: "1px solid rgba(180, 180, 180, 0.3)"
18 | },
19 | title: {
20 | fontSize: theme.typography.pxToRem(13),
21 | fontWeight: 600,
22 | color: "white",
23 | textTransform: "uppercase"
24 | },
25 | ...closeButton,
26 | ...tooltip(theme),
27 | avatar: {
28 | width: "24px",
29 | height: "24px",
30 | fontSize: theme.typography.pxToRem(13),
31 | backgroundColor: "transparent",
32 | border: "1px solid rgba(180, 180, 180, 0.3)"
33 | },
34 | avatarHighlight: {
35 | backgroundColor: primaryColor
36 | },
37 | avatarNew: {
38 | backgroundColor: warningColor
39 | },
40 | summary: {
41 | paddingRight: 0
42 | },
43 | details: {
44 | margin: 0,
45 | padding: 0,
46 | width: "100%"
47 | },
48 | blue: {
49 | border: 0,
50 | backgroundColor: infoColor,
51 | boxShadow:
52 | "0 12px 20px -10px rgba(0,188,212,.28), 0 4px 20px 0 rgba(0,0,0,.12), 0 7px 8px -5px rgba(0,188,212,.2)",
53 | "&:hover": {
54 | backgroundColor: infoColor,
55 | boxShadow:
56 | "0 12px 20px -10px rgba(0,188,212,.28), 0 4px 20px 0 rgba(0,0,0,.12), 0 7px 8px -5px rgba(0,188,212,.2)"
57 | }
58 | }
59 | });
60 |
61 | export default NotificationGroupStyle;
62 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import NotificationType from './NotificationType';
4 | import NotificationItemStyle from './NotificationItemStyle';
5 | import dayjs from 'dayjs';
6 | import { ListItem, IconButton, Tooltip, Grid } from '@material-ui/core';
7 | import withStyles from '@material-ui/core/styles/withStyles';
8 | import CloseIcon from '@material-ui/icons/Close';
9 | import * as helper from './helper';
10 | import NotificationItemPropTypes from './NotificationItemPropTypes';
11 | import NotificationStatus from './NotificationStatus';
12 | import classnames from 'classnames';
13 |
14 | function defaultFormatDate(date) {
15 | //convert Date to dayjs
16 | if (date instanceof Date) date = dayjs(date);
17 | //Check if it is nothing then just return out
18 | if (!date || !dayjs.isDayjs(date)) return date;
19 | const now = dayjs();
20 |
21 | //Less than 1 minutes => now
22 | if (now.diff(date, 'minutes') <= 1) return 'now';
23 |
24 | //Less than 5hours => hours ago
25 | if (now.diff(date, 'hours') <= 5) return date.format('h') + ' ago';
26 |
27 | //If today then => Today hh:mm
28 | if (now.diff(date, 'days') <= 1) return 'today ' + date.format('HH:mm');
29 |
30 | //If Yesterday then => yesterday
31 | const diff = now.diff(date, 'days');
32 | if (diff > 1 && diff <= 2) return 'yesterday';
33 |
34 | return `${diff} days`;
35 | }
36 |
37 | function NotificationItem({
38 | title,
39 | message,
40 | type,
41 | classes,
42 | status,
43 | onClose,
44 | onClick,
45 | formatDate,
46 | createdOn
47 | }) {
48 | const Icon = helper.getIcon(type);
49 | const isNew =
50 | status === NotificationStatus.NEW || status === NotificationStatus.NOTIFIED;
51 |
52 | return (
53 |
58 |
59 |
60 |
61 |
62 |
63 | {title}
64 |
65 |
66 | {formatDate(createdOn)}
67 |
68 |
69 | {message}
70 |
71 |
72 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | );
85 | }
86 |
87 | NotificationItem.defaultProps = {
88 | type: NotificationType.INFO,
89 | icon: true,
90 | formatDate: defaultFormatDate
91 | };
92 |
93 | NotificationItem.propTypes = {
94 | ...NotificationItemPropTypes,
95 | //The function to format dayjs object to string
96 | formatDate: PropTypes.func
97 | };
98 |
99 | export default withStyles(NotificationItemStyle)(NotificationItem);
100 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationItemPropTypes.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import NotificationType from './NotificationType';
3 | import NotificationStatus from './NotificationStatus';
4 |
5 | const NotificationItemPropTypes = {
6 | id: PropTypes.any.isRequired,
7 | //The Tye of notification
8 | type: PropTypes.oneOf([
9 | NotificationType.CONFIRM,
10 | NotificationType.DANGER,
11 | NotificationType.INFO,
12 | NotificationType.SUCCESS,
13 | NotificationType.WARNING
14 | ]),
15 | //The message of notification
16 | message: PropTypes.string.isRequired,
17 | //the title of notification
18 | title: PropTypes.string,
19 | //Close handler.
20 | onClose: PropTypes.func,
21 | //click event handler.
22 | onClick: PropTypes.func,
23 | //The icon of notification. set to false to hide the default icon.
24 | icon: PropTypes.oneOfType([PropTypes.element, PropTypes.bool]),
25 | //Created date of Notification
26 | createdOn: PropTypes.object,
27 | //status of notification
28 | status: PropTypes.oneOf([
29 | NotificationStatus.NEW,
30 | NotificationStatus.DELETED,
31 | NotificationStatus.NOTIFIED,
32 | NotificationStatus.READ
33 | ]).isRequired
34 | };
35 |
36 | export default NotificationItemPropTypes;
37 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationItemStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | primaryColor,
3 | infoColor,
4 | successColor,
5 | warningColor,
6 | dangerColor
7 | } from '../../assets/jss/material-dashboard-react';
8 | import { closeButton, tooltip } from './jss';
9 |
10 | const marginRight = 0;
11 |
12 | const NotificationItemStyle = theme => ({
13 | root: {
14 | width: 'auto',
15 | transition: 'all 300ms linear',
16 | margin: '5px 5px 0',
17 | borderRadius: '3px',
18 | position: 'relative',
19 | padding: '10px 10px',
20 | border: '1px solid rgba(180, 180, 180, 0.3)'
21 | },
22 | highlight: {
23 | border: `1px solid ${warningColor}`
24 | },
25 | date: {
26 | textAlign: 'right',
27 | fontSize: theme.typography.pxToRem(10),
28 | fontWeight: 400,
29 | color: 'white'
30 | },
31 | title: {
32 | fontSize: theme.typography.pxToRem(13),
33 | fontWeight: 550,
34 | color: 'white',
35 | paddingLeft: '10px'
36 | },
37 | message: {
38 | fontSize: theme.typography.pxToRem(12),
39 | textAlign: 'justify',
40 | color: 'white'
41 | },
42 | ...closeButton,
43 | ...tooltip(theme),
44 |
45 | success: {
46 | color: successColor,
47 | marginRight
48 | },
49 | danger: {
50 | color: dangerColor,
51 | marginRight
52 | },
53 | warning: {
54 | color: warningColor,
55 | marginRight
56 | },
57 | info: {
58 | color: infoColor,
59 | marginRight
60 | },
61 | confirm: {
62 | color: primaryColor,
63 | marginRight
64 | }
65 | });
66 |
67 | export default NotificationItemStyle;
68 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationPanel.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Drawer, List } from '@material-ui/core';
4 | import withStyles from '@material-ui/core/styles/withStyles';
5 | import NotificationPanelStyle from './NotificationPanelStyle';
6 | import MessageIcon from '@material-ui/icons/Message';
7 | import NotificationGroup from './NotificationGroup';
8 | import NotificationItemPropTypes from './NotificationItemPropTypes';
9 | //helper
10 | import { getGroupItems } from './helper';
11 |
12 | function defaultGroupComponent({ classes, onClose, items }) {
13 | return (
14 |
15 | {items.map((g, i) => (
16 |
22 | ))}
23 |
24 | );
25 | }
26 |
27 | function defaultBackgroundComponent({ image, classes }) {
28 | if (!image) return null;
29 | return (
30 |
34 | );
35 | }
36 |
37 | function defaultTitleComponent({ classes, title }) {
38 | if (!title) return null;
39 |
40 | return (
41 |
42 |
43 | {title}
44 |
45 | );
46 | }
47 |
48 | function NotificationPanel({
49 | GroupComponent,
50 | BackgroundComponent,
51 | TitleComponent,
52 | position,
53 | open,
54 | onPanelClose,
55 | onItemClose,
56 | classes,
57 | items,
58 | ...others
59 | }) {
60 | const groups = getGroupItems(items);
61 |
62 | return (
63 | onPanelClose(items)}
68 | classes={{
69 | paper: classes.drawerPaper
70 | }}
71 | ModalProps={{
72 | //keepMounted: true // Better open performance on mobile.
73 | BackdropProps: {
74 | invisible: true
75 | }
76 | }}
77 | >
78 |
79 |
80 |
81 |
87 |
88 |
89 | );
90 | }
91 |
92 | NotificationPanel.defaultProps = {
93 | GroupComponent: defaultGroupComponent,
94 | BackgroundComponent: defaultBackgroundComponent,
95 | TitleComponent: defaultTitleComponent,
96 | position: 'right',
97 | open: false
98 | };
99 |
100 | NotificationPanel.propTypes = {
101 | GroupComponent: PropTypes.func,
102 | BackgroundComponent: PropTypes.func,
103 | TitleComponent: PropTypes.func,
104 | items: PropTypes.arrayOf(PropTypes.shape(NotificationItemPropTypes))
105 | .isRequired,
106 | position: PropTypes.oneOf(['left', 'top', 'right', 'bottom']),
107 | open: PropTypes.bool,
108 | onPanelClose: PropTypes.func.isRequired,
109 | onItemClose: PropTypes.func.isRequired,
110 | //The background image of Notification Panel
111 | image: PropTypes.string,
112 | title: PropTypes.string
113 | };
114 |
115 | export default withStyles(NotificationPanelStyle)(NotificationPanel);
116 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationPanelStyle.js:
--------------------------------------------------------------------------------
1 | import {
2 | drawerWidth,
3 | transition,
4 | boxShadow,
5 | defaultFont
6 | } from "../../assets/jss/material-dashboard-react";
7 |
8 | const width = drawerWidth + 30;
9 |
10 | const NotificationPanelStyle = () => ({
11 | drawerPaper: {
12 | position: "fixed",
13 | zIndex: "1",
14 | top: "0",
15 | ...boxShadow,
16 | transform: `translate3d(${width}px, 0, 0)`,
17 | ...transition,
18 | width: width
19 | },
20 | background: {
21 | position: "absolute",
22 | zIndex: "0",
23 | height: "100%",
24 | width: "100%",
25 | display: "block",
26 | top: "0",
27 | left: "0",
28 | backgroundSize: "cover",
29 | backgroundPosition: "center center",
30 | "&:after": {
31 | position: "absolute",
32 | zIndex: "3",
33 | width: "100%",
34 | height: "100%",
35 | content: "''",
36 | display: "block",
37 | background: "#000",
38 | opacity: ".8"
39 | }
40 | },
41 | containWrapper: {
42 | position: "relative",
43 | height: "calc(100vh - 75px)",
44 | overflow: "auto",
45 | zIndex: "10000",
46 | overflowScrolling: "touch",
47 | display: "block",
48 | top: "0",
49 | left: "0"
50 | },
51 | logo: {
52 | position: "relative",
53 | padding: "15px 15px",
54 | zIndex: "4",
55 | "&:after": {
56 | content: "''",
57 | position: "absolute",
58 | bottom: "0",
59 | height: "1px",
60 | right: "15px",
61 | width: "calc(100% - 30px)",
62 | backgroundColor: "rgba(180, 180, 180, 0.3)"
63 | }
64 | },
65 | logoText: {
66 | ...defaultFont,
67 | textTransform: "uppercase",
68 | padding: "5px 0 0 40px",
69 | display: "block",
70 | fontSize: "18px",
71 | textAlign: "left",
72 | fontWeight: "400",
73 | lineHeight: "30px",
74 | textDecoration: "none",
75 | backgroundColor: "transparent",
76 | "&,&:hover": {
77 | color: "#FFFFFF"
78 | }
79 | },
80 | icon: {
81 | width: "35px",
82 | top: "22px",
83 | position: "absolute",
84 | verticalAlign: "middle",
85 | border: "0",
86 | color: "#00acc1"
87 | }
88 | });
89 |
90 | export default NotificationPanelStyle;
91 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationPopup.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import NotificationPopupItem from './NotificationPopupItem';
4 |
5 | function defaultPopupItemComponent(props) {
6 | return ;
7 | }
8 |
9 | //Render the Popup of the list NotificationPopupItem
10 | export default function NotificationPopup({
11 | PopupItemComponent,
12 | items,
13 | displayIn,
14 | subsequentDelay,
15 | onClose,
16 | ...others
17 | }) {
18 | let count = items.length - 1;
19 |
20 | return (
21 |
22 | {items.map((p, i) => {
23 | return (
24 | {
29 | if (p.onClose) p.onClose(e);
30 | if (onClose) onClose(e);
31 | }}
32 | displayIn={displayIn + count-- * subsequentDelay}
33 | autoClose={i === 0}
34 | />
35 | );
36 | })}
37 |
38 | );
39 | }
40 |
41 | NotificationPopup.defaultProps = {
42 | //Using default defaultPopupItemComponent render
43 | PopupItemComponent: defaultPopupItemComponent,
44 | displayIn: 3000,
45 | subsequentDelay: 1000,
46 | items: []
47 | };
48 |
49 | NotificationPopup.propTypes = {
50 | //This property allow to customize the NotificationPopupItem.
51 | PopupItemComponent: PropTypes.func,
52 | items: PropTypes.arrayOf(PropTypes.shape(NotificationPopupItem.propTypes)),
53 | displayIn: PropTypes.number,
54 | subsequentDelay: PropTypes.number,
55 | onClose: PropTypes.func
56 | };
57 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationPopupItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import Snackbar from '../Snackbar/Snackbar';
4 | import NotificationType from './NotificationType';
5 | import NotificationPopupItemStyle from './NotificationPopupItemStyle';
6 | import withStyles from '@material-ui/core/styles/withStyles';
7 | import * as helper from './helper';
8 | import NotificationItemPropTypes from './NotificationItemPropTypes';
9 |
10 | @withStyles(NotificationPopupItemStyle)
11 | export default class NotificationPopupItem extends React.PureComponent {
12 | constructor(props, context) {
13 | super(props, context);
14 | this._timeout = undefined;
15 | }
16 |
17 | setCallbackTimeout = props => {
18 | const { onClose, open, autoClose, displayIn } = props;
19 |
20 | if (!onClose || open !== true || autoClose !== true || displayIn <= 0)
21 | return;
22 |
23 | if (this._timeout) return;
24 | this._timeout = setTimeout(this.onClosing, displayIn);
25 | };
26 |
27 | componentDidMount() {
28 | this.setCallbackTimeout(this.props);
29 | }
30 |
31 | componentWillReceiveProps(nextProps) {
32 | this.setCallbackTimeout(nextProps);
33 | }
34 |
35 | //Handling the internal closing event and call onClose with id
36 | onClosing = () => {
37 | const { onClose, id } = this.props;
38 | onClose({ id });
39 | this._timeout = undefined;
40 | };
41 |
42 | render() {
43 | const { id, type, icon, title, message, classes, place, open } = this.props;
44 |
45 | return (
46 |
56 | {title && {title}
}
57 | {message}
58 |
59 | }
60 | />
61 | );
62 | }
63 | }
64 |
65 | NotificationPopupItem.defaultProps = {
66 | place: 'tr', //Top right
67 | autoClose: true,
68 | type: NotificationType.INFO,
69 | open: true,
70 | icon: true
71 | };
72 |
73 | NotificationPopupItem.propTypes = {
74 | ...NotificationItemPropTypes,
75 | //The number of second will be displayed.
76 | displayIn: PropTypes.number,
77 | //Enable timeout to call onClose after displayIn second automatically.
78 | autoClose: PropTypes.bool
79 | };
80 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationPopupItemStyle.js:
--------------------------------------------------------------------------------
1 | const NotificationItemStyle = theme => ({
2 | title: { fontWeight: 'bold' }
3 | // icon: {
4 | // fontSize: 20
5 | // },
6 | // message: {
7 | // color: "white",
8 | // display: "flex",
9 | // alignItems: "center",
10 | // whiteSpace: "pre",
11 | // textTransform: "none"
12 | // }
13 | });
14 |
15 | export default NotificationItemStyle;
16 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationStatus.js:
--------------------------------------------------------------------------------
1 | const NotificationStatus = {
2 | NEW: "NEW",
3 | NOTIFIED: "NOTIFIED",
4 | READ: "READ"
5 | };
6 |
7 | export default NotificationStatus;
8 |
--------------------------------------------------------------------------------
/src/components/Notification/NotificationType.js:
--------------------------------------------------------------------------------
1 | const NotificationType = {
2 | SUCCESS: "success",
3 | DANGER: "danger",
4 | WARNING: "warning",
5 | INFO: "info",
6 | CONFIRM: "confirm"
7 | };
8 |
9 | export default NotificationType;
10 |
--------------------------------------------------------------------------------
/src/components/Notification/helper.jsx:
--------------------------------------------------------------------------------
1 | import NotificationType from './NotificationType';
2 | import confirmIcon from '@material-ui/icons/Help';
3 | import errorIcon from '@material-ui/icons/Error';
4 | import infoIcon from '@material-ui/icons/Info';
5 | import warningIcon from '@material-ui/icons/Warning';
6 | import successIcon from '@material-ui/icons/CheckCircle';
7 | import linq from 'linq';
8 | import NotificationStatus from './NotificationStatus';
9 | import * as guard from '../../commons/guard';
10 |
11 | export function getColor(type) {
12 | switch (type) {
13 | case NotificationType.CONFIRM:
14 | return 'primary';
15 | case NotificationType.DANGER:
16 | return 'danger';
17 | case NotificationType.WARNING:
18 | return 'warning';
19 | case NotificationType.SUCCESS:
20 | return 'success';
21 | case NotificationType.INFO:
22 | default:
23 | return 'info';
24 | }
25 | }
26 |
27 | export function getIcon(type) {
28 | switch (type) {
29 | case NotificationType.CONFIRM:
30 | return confirmIcon;
31 | case NotificationType.DANGER:
32 | return errorIcon;
33 | case NotificationType.WARNING:
34 | return warningIcon;
35 | case NotificationType.SUCCESS:
36 | return successIcon;
37 | case NotificationType.INFO:
38 | default:
39 | return infoIcon;
40 | }
41 | }
42 |
43 | /**
44 | * Get Unread Notification Items
45 | *
46 | * @export getUnreadItems
47 | * @param {NotificationItemPropTypes} items
48 | * @returns items which status is in [NEW,NOTIFIED]
49 | */
50 | export function getUnreadItems(items) {
51 | if (!items) return items;
52 | guard.argumentIsArray(items, 'Notification Items');
53 | if (items.length <= 0) return items;
54 |
55 | return linq
56 | .from(items)
57 | .where(
58 | i =>
59 | i.status === NotificationStatus.NEW ||
60 | i.status === NotificationStatus.NOTIFIED
61 | )
62 | .toArray();
63 | }
64 | /**
65 | * Get Notification Items for Popup component
66 | *
67 | * @export getItemsForPopup
68 | * @param {NotificationItemPropTypes} items
69 | * @returns items which status is in [NEW,NOTIFIED], orderByDescending by i.createdOn and mark open based on NEW status
70 | */
71 | export function getItemsForPopup(items) {
72 | const unreadItems = getUnreadItems(items);
73 | if (unreadItems.length <= 0) return unreadItems;
74 |
75 | return (
76 | linq
77 | .from(unreadItems)
78 | .orderByDescending(i => i.createdOn)
79 | //Tell the popup that only show the NEW status once.
80 | .select(i => ({ ...i, open: i.status === NotificationStatus.NEW }))
81 | .toArray()
82 | );
83 | }
84 | /**
85 | * Group notification by group
86 | *
87 | * @export getGroupItems
88 | * @param {NotificationItemPropTypes} items
89 | * @returns groups orderByDescending by i.createdOn and grouped by i.group
90 | */
91 | export function getGroupItems(items) {
92 | if (!items) return items;
93 | guard.argumentIsArray(items, 'Notification Items');
94 | if (items.length <= 0) return items;
95 |
96 | return linq
97 | .from(items)
98 | .groupBy(i => i.group || '')
99 | .select(g => ({
100 | title: g.key(),
101 | items: g.orderByDescending(i => i.createdOn.valueOf()).toArray()
102 | }))
103 | .orderBy(i => i.title)
104 | .toArray();
105 | }
106 |
--------------------------------------------------------------------------------
/src/components/Notification/index.js:
--------------------------------------------------------------------------------
1 | import NotificationCenter from './NotificationCenter';
2 | import * as NotificationCenterStyle from './jss';
3 | import NotificationStatus from './NotificationStatus';
4 | import NotificationType from './NotificationType';
5 |
6 | export {
7 | NotificationCenter,
8 | NotificationCenterStyle,
9 | NotificationStatus,
10 | NotificationType
11 | };
12 | export default NotificationCenter;
13 |
--------------------------------------------------------------------------------
/src/components/Notification/jss.js:
--------------------------------------------------------------------------------
1 | import {
2 | primaryColor,
3 | grayColor
4 | } from '../../assets/jss/material-dashboard-react';
5 |
6 | const closeButton = {
7 | iconButton: {
8 | width: '24px',
9 | height: '24px'
10 | },
11 | close: {
12 | width: '11px',
13 | height: '11px',
14 | color: 'white'
15 | }
16 | };
17 |
18 | const tooltip = theme => ({
19 | tooltip: {
20 | background: theme.palette.common.white,
21 | color: theme.palette.text.primary,
22 | boxShadow: theme.shadows[1],
23 | fontSize: 11
24 | },
25 | arrowPopper: {
26 | '&[x-placement*="bottom"] $arrowArrow': {
27 | top: 0,
28 | left: 0,
29 | marginTop: '-0.9em',
30 | width: '3em',
31 | height: '1em',
32 | '&::before': {
33 | borderWidth: '0 1em 1em 1em',
34 | borderColor: `transparent transparent ${
35 | theme.palette.common.white
36 | } transparent`
37 | }
38 | },
39 | '&[x-placement*="top"] $arrowArrow': {
40 | bottom: 0,
41 | left: 0,
42 | marginBottom: '-0.9em',
43 | width: '3em',
44 | height: '1em',
45 | '&::before': {
46 | borderWidth: '1em 1em 0 1em',
47 | borderColor: `${
48 | theme.palette.grey[700]
49 | } transparent transparent transparent`
50 | }
51 | },
52 | '&[x-placement*="right"] $arrowArrow': {
53 | left: 0,
54 | marginLeft: '-0.9em',
55 | height: '3em',
56 | width: '1em',
57 | '&::before': {
58 | borderWidth: '1em 1em 1em 0',
59 | borderColor: `transparent ${
60 | theme.palette.grey[700]
61 | } transparent transparent`
62 | }
63 | },
64 | '&[x-placement*="left"] $arrowArrow': {
65 | right: 0,
66 | marginRight: '-0.9em',
67 | height: '3em',
68 | width: '1em',
69 | '&::before': {
70 | borderWidth: '1em 0 1em 1em',
71 | borderColor: `transparent transparent transparent ${
72 | theme.palette.grey[700]
73 | }`
74 | }
75 | }
76 | },
77 | arrowArrow: {
78 | position: 'absolute',
79 | fontSize: 7,
80 | width: '3em',
81 | height: '3em',
82 | '&::before': {
83 | content: '""',
84 | margin: 'auto',
85 | display: 'block',
86 | width: 0,
87 | height: 0,
88 | borderStyle: 'solid'
89 | }
90 | }
91 | });
92 |
93 | const NotificationCenterStyle = theme => ({
94 | iconActive: {
95 | color: primaryColor
96 | },
97 | badge: {
98 | width: '20px',
99 | height: '20px',
100 | fontSize: theme.typography.pxToRem(10)
101 | },
102 | colorSecondary: {
103 | backgroundColor: grayColor
104 | },
105 | ...tooltip(theme)
106 | });
107 |
108 | export { closeButton, tooltip, NotificationCenterStyle };
109 | export default NotificationCenterStyle;
110 |
--------------------------------------------------------------------------------
/src/components/Snackbar/Snackbar.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import classNames from "classnames";
3 | import PropTypes from "prop-types";
4 | // @material-ui/core components
5 | import withStyles from "@material-ui/core/styles/withStyles";
6 | import Snack from "@material-ui/core/Snackbar";
7 | import IconButton from "@material-ui/core/IconButton";
8 | // @material-ui/icons
9 | import Close from "@material-ui/icons/Close";
10 | // core components
11 | import snackbarContentStyle from "./snackbarContentStyle";
12 |
13 | function getMessage() {}
14 | function Snackbar({
15 | classes,
16 | message,
17 | color,
18 | close,
19 | place,
20 | open,
21 | onClose,
22 | onClick,
23 | ...others
24 | }) {
25 | let action = [];
26 | const messageClasses = classNames({
27 | [classes.iconMessage]: others.icon !== undefined
28 | });
29 |
30 | if (close !== undefined) {
31 | action = [
32 |
39 |
40 |
41 | ];
42 | }
43 |
44 | return (
45 |
58 | {others.icon !== undefined ? (
59 | typeof others.icon === "function" ? (
60 |
61 | ) : (
62 | {others.icon}
63 | )
64 | ) : null}
65 | {message}
66 |
67 | }
68 | action={action}
69 | ContentProps={{
70 | classes: {
71 | root: classes.root + " " + classes[color],
72 | message: classes.message
73 | }
74 | }}
75 | />
76 | );
77 | }
78 |
79 | Snackbar.propTypes = {
80 | classes: PropTypes.object.isRequired,
81 | message: PropTypes.node.isRequired,
82 | //The color of the Snackbar
83 | color: PropTypes.oneOf(["info", "success", "warning", "danger", "primary"]),
84 | //Show/Hide close button
85 | close: PropTypes.bool,
86 | icon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
87 | //The position the Snackbar:top-left, top-right, top-center, buttom-right, buttom-left,buttom-center.
88 | place: PropTypes.oneOf(["tl", "tr", "tc", "br", "bl", "bc"]),
89 | open: PropTypes.bool,
90 | onClose: PropTypes.func,
91 | onClick: PropTypes.func
92 | };
93 |
94 | export default withStyles(snackbarContentStyle)(Snackbar);
95 |
--------------------------------------------------------------------------------
/src/components/Snackbar/SnackbarContent.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import classNames from "classnames";
4 | // @material-ui/core components
5 | import withStyles from "@material-ui/core/styles/withStyles";
6 | import Snack from "@material-ui/core/SnackbarContent";
7 | import IconButton from "@material-ui/core/IconButton";
8 | // @material-ui/icons
9 | import Close from "@material-ui/icons/Close";
10 | // core components
11 | import snackbarContentStyle from "./snackbarContentStyle.jsx";
12 |
13 | function SnackbarContent({ ...props }) {
14 | const { classes, message, color, close, icon } = props;
15 | let action = [];
16 | const messageClasses = classNames({
17 | [classes.iconMessage]: icon !== undefined
18 | });
19 | if (close !== undefined) {
20 | action = [
21 |
27 |
28 |
29 | ];
30 | }
31 | return (
32 |
35 | {icon !== undefined ? : null}
36 | {message}
37 |
38 | }
39 | classes={{
40 | root: classes.root + " " + classes[color],
41 | message: classes.message
42 | }}
43 | action={action}
44 | />
45 | );
46 | }
47 |
48 | SnackbarContent.propTypes = {
49 | classes: PropTypes.object.isRequired,
50 | message: PropTypes.node.isRequired,
51 | color: PropTypes.oneOf(["info", "success", "warning", "danger", "primary"]),
52 | close: PropTypes.bool,
53 | icon: PropTypes.func
54 | };
55 |
56 | export default withStyles(snackbarContentStyle)(SnackbarContent);
57 |
--------------------------------------------------------------------------------
/src/components/Snackbar/snackbarContentStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | primaryBoxShadow,
4 | infoBoxShadow,
5 | successBoxShadow,
6 | warningBoxShadow,
7 | dangerBoxShadow,
8 | roseBoxShadow,
9 | pointer
10 | } from "../../assets/jss/material-dashboard-react";
11 |
12 | const snackbarContentStyle = {
13 | pointer: {
14 | ...pointer
15 | },
16 | root: {
17 | ...defaultFont,
18 | flexWrap: "unset",
19 | position: "relative",
20 | padding: "20px 15px",
21 | lineHeight: "20px",
22 | marginBottom: "20px",
23 | fontSize: "14px",
24 | backgroundColor: "white",
25 | color: "#555555",
26 | borderRadius: "3px",
27 | boxShadow:
28 | "0 12px 20px -10px rgba(255, 255, 255, 0.28), 0 4px 20px 0px rgba(0, 0, 0, 0.12), 0 7px 8px -5px rgba(255, 255, 255, 0.2)"
29 | },
30 | top20: {
31 | top: "20px"
32 | },
33 | top40: {
34 | top: "40px"
35 | },
36 | info: {
37 | backgroundColor: "#00d3ee",
38 | color: "#ffffff",
39 | ...infoBoxShadow
40 | },
41 | success: {
42 | backgroundColor: "#5cb860",
43 | color: "#ffffff",
44 | ...successBoxShadow
45 | },
46 | warning: {
47 | backgroundColor: "#ffa21a",
48 | color: "#ffffff",
49 | ...warningBoxShadow
50 | },
51 | danger: {
52 | backgroundColor: "#f55a4e",
53 | color: "#ffffff",
54 | ...dangerBoxShadow
55 | },
56 | primary: {
57 | backgroundColor: "#af2cc5",
58 | color: "#ffffff",
59 | ...primaryBoxShadow
60 | },
61 | rose: {
62 | backgroundColor: "#eb3573",
63 | color: "#ffffff",
64 | ...roseBoxShadow
65 | },
66 | message: {
67 | padding: "0",
68 | display: "block",
69 | maxWidth: "89%"
70 | },
71 | close: {
72 | width: "11px",
73 | height: "11px"
74 | },
75 | iconButton: {
76 | width: "24px",
77 | height: "24px"
78 | },
79 | icon: {
80 | display: "block",
81 | left: "15px",
82 | position: "absolute",
83 | top: "50%",
84 | marginTop: "-15px",
85 | width: "30px",
86 | height: "30px"
87 | },
88 | infoIcon: {
89 | color: "#00d3ee"
90 | },
91 | successIcon: {
92 | color: "#5cb860"
93 | },
94 | warningIcon: {
95 | color: "#ffa21a"
96 | },
97 | dangerIcon: {
98 | color: "#f55a4e"
99 | },
100 | primaryIcon: {
101 | color: "#af2cc5"
102 | },
103 | roseIcon: {
104 | color: "#eb3573"
105 | },
106 | iconMessage: {
107 | paddingLeft: "50px",
108 | display: "block"
109 | }
110 | };
111 |
112 | export default snackbarContentStyle;
113 |
--------------------------------------------------------------------------------
/src/components/Table/ActionCell.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TableCell from '@material-ui/core/TableCell';
3 | import Tooltip from '@material-ui/core/Tooltip';
4 | import IconButton from '@material-ui/core/IconButton';
5 | import PropTypes from 'prop-types';
6 | import withStyles from '@material-ui/core/styles/withStyles';
7 | import classNames from 'classnames';
8 | import tableStyle from './tableStyle';
9 |
10 | const ActionCell = ({ actionColumns, classes, rowData }) => {
11 | let cell = null;
12 | if (actionColumns.length > 0) {
13 | cell = (
14 |
15 | {actionColumns.map((obj, key) => (
16 |
17 | obj.Callback(rowData)}>
18 |
24 |
25 |
26 | ))}
27 |
28 | );
29 | }
30 | return cell;
31 | };
32 | ActionCell.defaultProps = {
33 | actionColumns: []
34 | };
35 | ActionCell.propTypes = {
36 | actionColumns: PropTypes.arrayOf(
37 | PropTypes.shape({
38 | Callback: PropTypes.func,
39 | Icon: PropTypes.any.isRequired,
40 | Tooltip: PropTypes.string,
41 | Color: PropTypes.oneOf([
42 | 'warning',
43 | 'primary',
44 | 'danger',
45 | 'success',
46 | 'info',
47 | 'rose',
48 | 'gray'
49 | ])
50 | })
51 | )
52 | };
53 | export default withStyles(tableStyle)(ActionCell);
54 |
--------------------------------------------------------------------------------
/src/components/Table/Table.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | // @material-ui/core components
4 | import withStyles from '@material-ui/core/styles/withStyles';
5 | import Table from '@material-ui/core/Table';
6 | import TableHead from '@material-ui/core/TableHead';
7 | import TableRow from '@material-ui/core/TableRow';
8 | import TableBody from '@material-ui/core/TableBody';
9 | import TableCell from '@material-ui/core/TableCell';
10 | // core components
11 | import tableStyle from './tableStyle';
12 | import ActionCell from './ActionCell';
13 |
14 | function CustomTable({ ...props }) {
15 | const {
16 | classes,
17 | tableHead,
18 | tableData,
19 | tableHeaderColor,
20 | actionColumns
21 | } = props;
22 | return (
23 |
24 |
25 | {tableHead !== undefined ? (
26 |
27 |
28 | {tableHead.map((prop, key) => {
29 | return (
30 |
34 | {prop}
35 |
36 | );
37 | })}
38 | {actionColumns.length > 0 && (
39 |
48 | Action
49 |
50 | )}
51 |
52 |
53 | ) : null}
54 |
55 | {tableData.map((prop, key) => {
56 | return (
57 |
58 | {prop.map((item, key) => {
59 | return (
60 |
61 | {item}
62 |
63 | );
64 | })}
65 |
66 |
67 | );
68 | })}
69 |
70 |
71 |
72 | );
73 | }
74 |
75 | CustomTable.defaultProps = {
76 | tableHeaderColor: 'gray',
77 | actionColumns: []
78 | };
79 |
80 | CustomTable.propTypes = {
81 | classes: PropTypes.object.isRequired,
82 | tableHeaderColor: PropTypes.oneOf([
83 | 'warning',
84 | 'primary',
85 | 'danger',
86 | 'success',
87 | 'info',
88 | 'rose',
89 | 'gray'
90 | ]),
91 | tableHead: PropTypes.arrayOf(PropTypes.string),
92 | tableData: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string))
93 | };
94 |
95 | export default withStyles(tableStyle)(CustomTable);
96 |
--------------------------------------------------------------------------------
/src/components/Table/tableStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | warningColor,
3 | primaryColor,
4 | dangerColor,
5 | successColor,
6 | infoColor,
7 | roseColor,
8 | grayColor,
9 | defaultFont
10 | } from '../../assets/jss/material-dashboard-react.jsx';
11 |
12 | const tableStyle = theme => ({
13 | warningTableHeader: {
14 | color: warningColor
15 | },
16 | primaryTableHeader: {
17 | color: primaryColor
18 | },
19 | dangerTableHeader: {
20 | color: dangerColor
21 | },
22 | successTableHeader: {
23 | color: successColor
24 | },
25 | infoTableHeader: {
26 | color: infoColor
27 | },
28 | roseTableHeader: {
29 | color: roseColor
30 | },
31 | grayTableHeader: {
32 | color: grayColor
33 | },
34 | table: {
35 | marginBottom: '0',
36 | width: '100%',
37 | maxWidth: '100%',
38 | backgroundColor: 'transparent',
39 | borderSpacing: '0',
40 | borderCollapse: 'collapse'
41 | },
42 | tableHeadCell: {
43 | color: 'inherit',
44 | ...defaultFont,
45 | fontSize: '1em'
46 | },
47 | tableCell: {
48 | ...defaultFont,
49 | lineHeight: '1.42857143',
50 | padding: '12px 8px',
51 | verticalAlign: 'middle'
52 | },
53 | tableResponsive: {
54 | width: '100%',
55 | marginTop: theme.spacing.unit * 3,
56 | overflowX: 'auto'
57 | },
58 | tableActionButtonIcon: {
59 | width: '17px',
60 | height: '17px'
61 | },
62 | alignCenter: {
63 | textAlign: 'center'
64 | },
65 | cellHidden: {
66 | display: 'none'
67 | }
68 | });
69 |
70 | export default tableStyle;
71 |
--------------------------------------------------------------------------------
/src/components/Tasks/Tasks.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | // @material-ui/core components
4 | import withStyles from '@material-ui/core/styles/withStyles';
5 | import Checkbox from '@material-ui/core/Checkbox';
6 | import Tooltip from '@material-ui/core/Tooltip';
7 | import IconButton from '@material-ui/core/IconButton';
8 | import Table from '@material-ui/core/Table';
9 | import TableRow from '@material-ui/core/TableRow';
10 | import TableBody from '@material-ui/core/TableBody';
11 | import TableCell from '@material-ui/core/TableCell';
12 | // @material-ui/icons
13 | import Edit from '@material-ui/icons/Edit';
14 | import Close from '@material-ui/icons/Close';
15 | import Check from '@material-ui/icons/Check';
16 | // core components
17 | import tasksStyle from './tasksStyle.jsx';
18 |
19 | class Tasks extends React.Component {
20 | state = {
21 | checked: this.props.checkedIndexes
22 | };
23 | handleToggle = value => () => {
24 | const { checked } = this.state;
25 | const currentIndex = checked.indexOf(value);
26 | const newChecked = [...checked];
27 |
28 | if (currentIndex === -1) {
29 | newChecked.push(value);
30 | } else {
31 | newChecked.splice(currentIndex, 1);
32 | }
33 |
34 | this.setState({
35 | checked: newChecked
36 | });
37 | };
38 | render() {
39 | const { classes, tasksIndexes, tasks } = this.props;
40 | return (
41 |
42 |
43 | {tasksIndexes.map(value => (
44 |
45 |
46 | }
51 | icon={ }
52 | classes={{
53 | checked: classes.checked
54 | }}
55 | />
56 |
57 |
58 | {tasks[value]}
59 |
60 |
61 |
67 |
71 |
76 |
77 |
78 |
84 |
88 |
93 |
94 |
95 |
96 |
97 | ))}
98 |
99 |
100 | );
101 | }
102 | }
103 |
104 | Tasks.propTypes = {
105 | classes: PropTypes.object.isRequired,
106 | tasksIndexes: PropTypes.arrayOf(PropTypes.number),
107 | tasks: PropTypes.arrayOf(PropTypes.node)
108 | };
109 |
110 | export default withStyles(tasksStyle)(Tasks);
111 |
--------------------------------------------------------------------------------
/src/components/Tasks/tasksStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | primaryColor,
4 | dangerColor
5 | } from "../../assets/jss/material-dashboard-react";
6 | import tooltipStyle from "../../assets/jss/material-dashboard-react/tooltipStyle";
7 | import checkboxAdnRadioStyle from "../../assets/jss/material-dashboard-react/checkboxAdnRadioStyle";
8 |
9 | const tasksStyle = {
10 | ...tooltipStyle,
11 | ...checkboxAdnRadioStyle,
12 | table: {
13 | marginBottom: "0",
14 | overflow: "visible"
15 | },
16 | tableRow: {
17 | position: "relative",
18 | borderBottom: "1px solid #dddddd"
19 | },
20 | tableActions: {
21 | display: "flex",
22 | border: "none",
23 | padding: "12px 8px !important",
24 | verticalAlign: "middle"
25 | },
26 | tableCell: {
27 | ...defaultFont,
28 | padding: "8px",
29 | verticalAlign: "middle",
30 | border: "none",
31 | lineHeight: "1.42857143",
32 | fontSize: "14px"
33 | },
34 | tableActionButton: {
35 | width: "27px",
36 | height: "27px"
37 | },
38 | tableActionButtonIcon: {
39 | width: "17px",
40 | height: "17px"
41 | },
42 | edit: {
43 | backgroundColor: "transparent",
44 | color: primaryColor,
45 | boxShadow: "none"
46 | },
47 | close: {
48 | backgroundColor: "transparent",
49 | color: dangerColor,
50 | boxShadow: "none"
51 | }
52 | };
53 | export default tasksStyle;
54 |
--------------------------------------------------------------------------------
/src/components/Typography/Danger.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | // core components
6 | import typographyStyle from "./typographyStyle.jsx";
7 |
8 | function Danger({ ...props }) {
9 | const { classes, children } = props;
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
17 | Danger.propTypes = {
18 | classes: PropTypes.object.isRequired
19 | };
20 |
21 | export default withStyles(typographyStyle)(Danger);
22 |
--------------------------------------------------------------------------------
/src/components/Typography/Info.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | // core components
6 | import typographyStyle from "./typographyStyle.jsx";
7 |
8 | function Info({ ...props }) {
9 | const { classes, children } = props;
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
17 | Info.propTypes = {
18 | classes: PropTypes.object.isRequired
19 | };
20 |
21 | export default withStyles(typographyStyle)(Info);
22 |
--------------------------------------------------------------------------------
/src/components/Typography/Muted.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | // core components
6 | import typographyStyle from "./typographyStyle.jsx";
7 |
8 | function Muted({ ...props }) {
9 | const { classes, children } = props;
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
17 | Muted.propTypes = {
18 | classes: PropTypes.object.isRequired
19 | };
20 |
21 | export default withStyles(typographyStyle)(Muted);
22 |
--------------------------------------------------------------------------------
/src/components/Typography/Primary.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | // core components
6 | import typographyStyle from "./typographyStyle.jsx";
7 |
8 | function Primary({ ...props }) {
9 | const { classes, children } = props;
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
17 | Primary.propTypes = {
18 | classes: PropTypes.object.isRequired
19 | };
20 |
21 | export default withStyles(typographyStyle)(Primary);
22 |
--------------------------------------------------------------------------------
/src/components/Typography/Quote.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | // core components
6 | import typographyStyle from "./typographyStyle.jsx";
7 |
8 | function Quote({ ...props }) {
9 | const { classes, text, author } = props;
10 | return (
11 |
12 | {text}
13 | {author}
14 |
15 | );
16 | }
17 |
18 | Quote.propTypes = {
19 | classes: PropTypes.object.isRequired,
20 | text: PropTypes.node,
21 | author: PropTypes.node
22 | };
23 |
24 | export default withStyles(typographyStyle)(Quote);
25 |
--------------------------------------------------------------------------------
/src/components/Typography/Success.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | // core components
6 | import typographyStyle from "./typographyStyle.jsx";
7 |
8 | function Success({ ...props }) {
9 | const { classes, children } = props;
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
17 | Success.propTypes = {
18 | classes: PropTypes.object.isRequired
19 | };
20 |
21 | export default withStyles(typographyStyle)(Success);
22 |
--------------------------------------------------------------------------------
/src/components/Typography/Warning.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | // core components
6 | import typographyStyle from "./typographyStyle.jsx";
7 |
8 | function Warning({ ...props }) {
9 | const { classes, children } = props;
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
17 | Warning.propTypes = {
18 | classes: PropTypes.object.isRequired
19 | };
20 |
21 | export default withStyles(typographyStyle)(Warning);
22 |
--------------------------------------------------------------------------------
/src/components/Typography/typographyStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | defaultFont,
3 | primaryColor,
4 | infoColor,
5 | successColor,
6 | warningColor,
7 | dangerColor
8 | } from "../../assets/jss/material-dashboard-react.jsx";
9 |
10 | const typographyStyle = {
11 | defaultFontStyle: {
12 | ...defaultFont,
13 | fontSize: "14px"
14 | },
15 | defaultHeaderMargins: {
16 | marginTop: "20px",
17 | marginBottom: "10px"
18 | },
19 | quote: {
20 | padding: "10px 20px",
21 | margin: "0 0 20px",
22 | fontSize: "17.5px",
23 | borderLeft: "5px solid #eee"
24 | },
25 | quoteText: {
26 | margin: "0 0 10px",
27 | fontStyle: "italic"
28 | },
29 | quoteAuthor: {
30 | display: "block",
31 | fontSize: "80%",
32 | lineHeight: "1.42857143",
33 | color: "#777"
34 | },
35 | mutedText: {
36 | color: "#777"
37 | },
38 | primaryText: {
39 | color: primaryColor
40 | },
41 | infoText: {
42 | color: infoColor
43 | },
44 | successText: {
45 | color: successColor
46 | },
47 | warningText: {
48 | color: warningColor
49 | },
50 | dangerText: {
51 | color: dangerColor
52 | }
53 | };
54 |
55 | export default typographyStyle;
56 |
--------------------------------------------------------------------------------
/src/components/User/userFormStyles.js:
--------------------------------------------------------------------------------
1 | export default {
2 | cardCategoryWhite: {
3 | color: 'rgba(255,255,255,.62)',
4 | margin: '0',
5 | fontSize: '14px',
6 | marginTop: '0',
7 | marginBottom: '0'
8 | },
9 | cardTitleWhite: {
10 | color: '#FFFFFF',
11 | marginTop: '0px',
12 | minHeight: 'auto',
13 | fontWeight: '300',
14 | marginBottom: '3px',
15 | textDecoration: 'none'
16 | },
17 | appBar: {
18 | position: 'relative'
19 | },
20 | flex: {
21 | flex: 1
22 | },
23 | avatar: {
24 | width: '200px',
25 | height: '200px'
26 | },
27 | hiddenTag: {
28 | display: 'none'
29 | },
30 | pointer: {
31 | cursor: 'pointer'
32 | },
33 | formControl: {
34 | paddingBottom: '10px',
35 | margin: '27px 0 0 0',
36 | position: 'relative'
37 | }
38 | };
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baoduy/React-MaterialUI-Starter-Kit/450262c7cac7fda180c46fe06c8ca24e63407278/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.html.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | drunkcoding.net - Hello React!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/index.jsx:
--------------------------------------------------------------------------------
1 | //Sample to import LESS or SCSS
2 | //Style-sheets
3 | import './assets/scss/material-dashboard-react.scss';
4 |
5 | import { BrowserRouter, Route, Router, Switch } from 'react-router-dom';
6 |
7 | import ExceptionHandler from './layouts/ExceptionHandler';
8 | import { GetBaseUrl } from './commons/commonFuncs';
9 | import Provider from 'react-redux-thunk-store';
10 | import React from 'react';
11 | import ReactDOM from 'react-dom';
12 | import { createBrowserHistory } from 'history';
13 | import indexRoutes from 'routes/index.jsx';
14 | import reducers from './reducers';
15 |
16 | //import './assets/less/material-dashboard-react.less';
17 | //Sample to import LESS or SCSS
18 |
19 | //indicate whether application is running on PRD or not
20 | const isPrd = process.env.NODE_ENV === 'production';
21 |
22 | //Update for Reserved proxy
23 | const base = GetBaseUrl();
24 | const hist = createBrowserHistory({ basename: base });
25 |
26 | const createRouter = () => {
27 | return (
28 |
29 |
30 |
31 | {indexRoutes.map((prop, key) => {
32 | return (
33 |
34 | );
35 | })}
36 |
37 |
38 |
39 | );
40 | };
41 |
42 | //The Global ExceptionHandler will be disabled when running on development mode.
43 | const renderComponent = () => {
44 | ReactDOM.render(
45 |
46 |
47 | {createRouter()}
48 |
49 | ,
50 | document.getElementById('root')
51 | );
52 | };
53 |
54 | renderComponent();
55 |
56 | /* devblock:start */
57 | // Hot Module Replacement API
58 | if (module.hot) {
59 | module.hot.accept('./layouts/Dashboard', () => {
60 | renderComponent();
61 | });
62 | }
63 | /* devblock:end */
64 |
--------------------------------------------------------------------------------
/src/layouts/Dashboard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Switch, Route, Redirect } from 'react-router-dom';
4 | import { bindActionCreators } from 'redux';
5 | import { connect } from 'react-redux';
6 | import 'perfect-scrollbar/css/perfect-scrollbar.css';
7 | // @material-ui/core components
8 | import withStyles from '@material-ui/core/styles/withStyles';
9 | // core components
10 | import Header from '../components/Header/Header.jsx';
11 | import Footer from '../components/Footer/Footer.jsx';
12 | import Sidebar from '../components/Sidebar/Sidebar.jsx';
13 | import MessageBox from '../components/MessageBox';
14 |
15 | import dashboardRoutes from 'routes/dashboard.jsx';
16 | import dashboardStyle from './dashboardStyle.jsx';
17 |
18 | //Actions
19 | import NotificationActions from '../actions/Notifications';
20 |
21 | import { getImgSrc } from '../commons/commonFuncs';
22 | //Import may not working with Reserved proxy so using require instead.
23 | const image = getImgSrc(require('../assets/img/sidebar-2.jpg'));
24 | const logo = require('../assets/img/react_logo.svg');
25 |
26 | const switchRoutes = (
27 |
28 | {dashboardRoutes.map(
29 | (prop, key) =>
30 | prop.redirect ? (
31 |
32 | ) : (
33 |
34 | )
35 | )}
36 |
37 | );
38 |
39 | //Connect component to Redux store.
40 | @connect(
41 | state => ({
42 | messageBox: state.messageBox || {},
43 | notifications: state.notifications || []
44 | }),
45 | dispatch => ({
46 | actions: bindActionCreators(NotificationActions, dispatch)
47 | })
48 | )
49 | class App extends React.Component {
50 | constructor(props, context) {
51 | super(props, context);
52 |
53 | this.state = {
54 | mobileOpen: false
55 | };
56 | }
57 |
58 | handleDrawerToggle = () => {
59 | this.setState({ mobileOpen: !this.state.mobileOpen });
60 | };
61 | getRoute() {
62 | return this.props.location.pathname !== '/maps';
63 | }
64 | componentDidMount() {
65 | if (navigator.platform.indexOf('Win') <= -1) return;
66 | }
67 | componentDidUpdate(e) {
68 | if (e.history.location.pathname === e.location.pathname) return;
69 |
70 | this.refs.mainPanel.scrollTop = 0;
71 | if (this.state.mobileOpen) this.setState({ mobileOpen: false });
72 | }
73 |
74 | onNotificationChange = items => {
75 | this.props.actions.addOrUpdateNotifications(items);
76 | };
77 |
78 | onNotificationDelete = items => {
79 | this.props.actions.deleteNotifications(items);
80 | };
81 |
82 | render() {
83 | const { classes, notifications, messageBox, ...rest } = this.props;
84 | return (
85 |
86 |
87 |
88 |
98 |
99 |
108 | {/* On the /maps route we want the map to be on full screen - this is not possible if the content and conatiner classes are present because they have some paddings which would make the map smaller */}
109 | {this.getRoute() ? (
110 |
111 |
{switchRoutes}
112 |
113 | ) : (
114 |
{switchRoutes}
115 | )}
116 | {this.getRoute() ?
: null}
117 |
118 |
119 | );
120 | }
121 | }
122 |
123 | App.propTypes = {
124 | classes: PropTypes.object.isRequired
125 | };
126 |
127 | export default withStyles(dashboardStyle)(App);
128 |
--------------------------------------------------------------------------------
/src/layouts/ExceptionHandler.jsx:
--------------------------------------------------------------------------------
1 | /*eslint no-console: ["error", { allow: ["warn", "error"] }] */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { bindActionCreators } from 'redux';
5 | import { connect } from 'react-redux';
6 |
7 | import NotificationActions from '../actions/Notifications';
8 | import { getErrorMessage } from '../commons/exceptionService';
9 | import NotificationType from '../components/Notification/NotificationType';
10 |
11 | //Connect component to Redux store.
12 | //This one is a component however we are bot put it into components folder
13 | //Because it needs to connect to Redux actions to send the notification.
14 | @connect(
15 | undefined,
16 | dispatch => ({ actions: bindActionCreators(NotificationActions, dispatch) })
17 | )
18 | export default class ExceptionHandler extends React.Component {
19 | constructor(props, context) {
20 | super(props, context);
21 | }
22 |
23 | componentWillMount() {
24 | const { global, disabled } = this.props;
25 | if (global !== true || disabled === true) return;
26 | window.addEventListener('error', this.globalErrorHandler);
27 | }
28 |
29 | componentWillUnmount() {
30 | window.removeEventListener('error', this.globalErrorHandler);
31 | }
32 |
33 | /**
34 | * Exception handling for any error throw by any children control.
35 | *
36 | * @memberof ExceptionHandler
37 | */
38 | globalErrorHandler = event => {
39 | event.preventDefault();
40 | event.cancelBubble = true; //Stop the Bubble up
41 |
42 | const msg = getErrorMessage(event.error, event);
43 | this.props.actions.notify(NotificationType.DANGER, msg);
44 | };
45 |
46 | /**
47 | * From 16 onward all exception from children components
48 | * will be catch by parent component which implemented the componentDidCatch(error, info)
49 | * More details here https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html
50 | *
51 | * @param {*} error
52 | * @param {*} info
53 | * @memberof ExceptionHandler
54 | */
55 | componentDidCatch(error, info) {
56 | const { disabled } = this.props;
57 | if (disabled === true) {
58 | console.error(error);
59 | throw error;
60 | } else {
61 | const msg = getErrorMessage(error, info);
62 | this.props.actions.notify(NotificationType.DANGER, msg);
63 | }
64 | }
65 |
66 | render() {
67 | return this.props.children;
68 | }
69 | }
70 |
71 | ExceptionHandler.propTypes = {
72 | global: PropTypes.bool,
73 | disabled: PropTypes.bool
74 | };
75 |
--------------------------------------------------------------------------------
/src/layouts/dashboardStyle.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | drawerWidth,
3 | transition,
4 | container
5 | } from '../assets/jss/material-dashboard-react.jsx';
6 |
7 | const appStyle = theme => ({
8 | wrapper: {
9 | position: 'relative',
10 | top: '0',
11 | height: '100vh'
12 | },
13 | mainPanel: {
14 | [theme.breakpoints.up('md')]: {
15 | width: `calc(100% - ${drawerWidth}px)`
16 | },
17 | overflow: 'auto',
18 | position: 'relative',
19 | float: 'right',
20 | ...transition,
21 | maxHeight: '100%',
22 | width: '100%',
23 | overflowScrolling: 'touch'
24 | },
25 | content: {
26 | marginTop: '70px',
27 | padding: '30px 15px',
28 | minHeight: 'calc(100vh - 123px)'
29 | },
30 | container,
31 | map: {
32 | marginTop: '70px'
33 | }
34 | });
35 |
36 | export default appStyle;
37 |
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { Reducer as dashBoardReducers } from '../actions/Dashboard';
2 | import { Reducer as MessageBoxReducer } from '../actions/MessageBox';
3 | import { Reducer as NotificationReducer } from '../actions/Notifications';
4 | import { Reducer as UserReducer } from '../actions/Users';
5 | import { reducer as formReducer } from 'redux-form';
6 |
7 | const reducers = {
8 | charts: dashBoardReducers.chartsReducer,
9 | general: dashBoardReducers.generalReducer,
10 | messageBox: MessageBoxReducer,
11 | notifications: NotificationReducer,
12 | users: UserReducer,
13 | form: formReducer
14 | };
15 |
16 | export default reducers;
17 |
--------------------------------------------------------------------------------
/src/routes/dashboard.jsx:
--------------------------------------------------------------------------------
1 | // @material-ui/icons
2 | import Dashboard from '@material-ui/icons/Dashboard';
3 | import Person from '@material-ui/icons/Person';
4 | import ContentPaste from '@material-ui/icons/Assessment';
5 | import LibraryBooks from '@material-ui/icons/LibraryBooks';
6 | import BubbleChart from '@material-ui/icons/BubbleChart';
7 | import LocationOn from '@material-ui/icons/LocationOn';
8 | import Notifications from '@material-ui/icons/Notifications';
9 | import MessageBox from '@material-ui/icons/Message';
10 | import Unarchive from '@material-ui/icons/Unarchive';
11 | // core components/views
12 | //import DashboardPage from '../views/Dashboard/Dashboard.jsx';
13 | //import UserProfile from '../views/UserProfile/UserProfile.jsx';
14 | //import UserListing from '../views/UserProfile/UserListing.jsx';
15 | //import TableList from '../views/TableList/TableList.jsx';
16 | //import Typography from '../views/Typography/Typography.jsx';
17 | //import Icons from '../views/Icons/Icons.jsx';
18 | //import Maps from '../views/Maps/Maps.jsx';
19 | //import NotificationsPage from '../views/Notifications/Notifications.jsx';
20 | //import MessageBoxPage from '../views/MessageBox';
21 | //import UpgradeToPro from '../views/UpgradeToPro/UpgradeToPro.jsx';
22 |
23 | import Loader from '../views/loaders';
24 |
25 | const DashboardPage = Loader(() =>
26 | import(/* webpackChunkName: "DashboardView" */ '../views/Dashboard/Dashboard.jsx')
27 | );
28 |
29 | const UserListing = Loader(() =>
30 | import(/* webpackChunkName: "UserListingView" */ '../views/UserProfile/UserListing.jsx')
31 | );
32 |
33 | const TableList = Loader(() =>
34 | import(/* webpackChunkName: "TableListView" */ '../views/TableList/TableList.jsx')
35 | );
36 |
37 | const Typography = Loader(() =>
38 | import(/* webpackChunkName: "TypographyView" */ '../views/Typography/Typography.jsx')
39 | );
40 |
41 | const Icons = Loader(() =>
42 | import(/* webpackChunkName: "IconsView" */ '../views/Icons/Icons.jsx')
43 | );
44 |
45 | const Maps = Loader(() =>
46 | import(/* webpackChunkName: "MapsView" */ '../views/Maps/Maps.jsx')
47 | );
48 |
49 | const NotificationsPage = Loader(() =>
50 | import(/* webpackChunkName: "NotificationsView" */ '../views/Notifications/Notifications.jsx')
51 | );
52 |
53 | const MessageBoxPage = Loader(() =>
54 | import(/* webpackChunkName: "MessageBoxView" */ '../views/MessageBox')
55 | );
56 |
57 | const UpgradeToPro = Loader(() =>
58 | import(/* webpackChunkName: "UpgradeToProView" */ '../views/UpgradeToPro/UpgradeToPro.jsx')
59 | );
60 |
61 | export default [
62 | {
63 | path: '/dashboard',
64 | sidebarName: 'Dashboard',
65 | navbarName: 'Material Dashboard',
66 | icon: Dashboard,
67 | component: DashboardPage
68 | },
69 | {
70 | path: '/users',
71 | sidebarName: 'User Listing',
72 | navbarName: 'User Listing',
73 | icon: Person,
74 | component: UserListing
75 | },
76 | {
77 | path: '/table',
78 | sidebarName: 'Table List',
79 | navbarName: 'Table List',
80 | icon: ContentPaste,
81 | component: TableList
82 | },
83 | {
84 | path: '/typography',
85 | sidebarName: 'Typography',
86 | navbarName: 'Typography',
87 | icon: LibraryBooks,
88 | component: Typography
89 | },
90 | {
91 | path: '/icons',
92 | sidebarName: 'Icons',
93 | navbarName: 'Icons',
94 | icon: BubbleChart,
95 | component: Icons
96 | },
97 | {
98 | path: '/maps',
99 | sidebarName: 'Maps',
100 | navbarName: 'Map',
101 | icon: LocationOn,
102 | component: Maps
103 | },
104 | {
105 | path: '/notifications',
106 | sidebarName: 'Notifications',
107 | navbarName: 'Notifications',
108 | icon: Notifications,
109 | component: NotificationsPage
110 | },
111 | {
112 | path: '/messagebox',
113 | sidebarName: 'Message Box',
114 | navbarName: 'Message Box',
115 | icon: MessageBox,
116 | component: MessageBoxPage
117 | },
118 | {
119 | path: '/upgrade-to-pro',
120 | sidebarName: 'Upgrade To PRO',
121 | navbarName: 'Upgrade To PRO',
122 | icon: Unarchive,
123 | component: UpgradeToPro
124 | },
125 | { redirect: true, path: '/', to: '/dashboard', navbarName: 'Redirect' }
126 | ];
127 |
--------------------------------------------------------------------------------
/src/routes/index.jsx:
--------------------------------------------------------------------------------
1 | //import Dashboard from '../layouts/Dashboard.jsx';
2 | import Loader from '../views/loaders';
3 |
4 | const Dashboard = Loader(() =>
5 | import(/* webpackChunkName: "Dashboard" */ '../layouts/Dashboard.jsx')
6 | );
7 |
8 | export default [{ path: '/', component: Dashboard }];
9 |
--------------------------------------------------------------------------------
/src/settings/dev.js:
--------------------------------------------------------------------------------
1 | export const webService = 'http://react-api.azurewebsites.net';
2 |
--------------------------------------------------------------------------------
/src/settings/index.js:
--------------------------------------------------------------------------------
1 | if (process.env.NODE_ENV === 'production') {
2 | module.exports = require('./prd');
3 | } else {
4 | module.exports = require('./dev');
5 | }
6 |
--------------------------------------------------------------------------------
/src/settings/prd.js:
--------------------------------------------------------------------------------
1 | export const webService = 'http://react-api.azurewebsites.net';
2 |
--------------------------------------------------------------------------------
/src/views/Dashboard/dashboardStyle.jsx:
--------------------------------------------------------------------------------
1 | import { successColor } from "../../assets/jss/material-dashboard-react.jsx";
2 |
3 | const dashboardStyle = {
4 | successText: {
5 | color: successColor
6 | },
7 | upArrowCardCategory: {
8 | width: "16px",
9 | height: "16px"
10 | },
11 | stats: {
12 | color: "#999999",
13 | display: "inline-flex",
14 | fontSize: "12px",
15 | lineHeight: "22px",
16 | "& svg": {
17 | top: "4px",
18 | width: "16px",
19 | height: "16px",
20 | position: "relative",
21 | marginRight: "3px"
22 | }
23 | },
24 | cardCategory: {
25 | color: "#999999",
26 | margin: "0",
27 | fontSize: "14px",
28 | marginTop: "0",
29 | paddingTop: "10px",
30 | marginBottom: "0"
31 | },
32 | cardCategoryWhite: {
33 | color: "rgba(255,255,255,.62)",
34 | margin: "0",
35 | fontSize: "14px",
36 | marginTop: "0",
37 | marginBottom: "0"
38 | },
39 | cardTitle: {
40 | color: "#3C4858",
41 | marginTop: "0px",
42 | minHeight: "auto",
43 | fontWeight: "300",
44 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif",
45 | marginBottom: "3px",
46 | textDecoration: "none",
47 | "& small": {
48 | color: "#777",
49 | fontSize: "65%",
50 | fontWeight: "400",
51 | lineHeight: "1"
52 | }
53 | },
54 | cardTitleWhite: {
55 | color: "#FFFFFF",
56 | marginTop: "0px",
57 | minHeight: "auto",
58 | fontWeight: "300",
59 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif",
60 | marginBottom: "3px",
61 | textDecoration: "none",
62 | "& small": {
63 | color: "#777",
64 | fontSize: "65%",
65 | fontWeight: "400",
66 | lineHeight: "1"
67 | }
68 | }
69 | };
70 |
71 | export default dashboardStyle;
72 |
--------------------------------------------------------------------------------
/src/views/Icons/Icons.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | // @material-ui/core components
4 | import withStyles from "@material-ui/core/styles/withStyles";
5 | import Grid from "@material-ui/core/Grid";
6 | import Hidden from "@material-ui/core/Hidden";
7 | // core components
8 | import GridItem from "../../components/Grid/GridItem.jsx";
9 | import Card from "../../components/Card/Card.jsx";
10 | import CardHeader from "../../components/Card/CardHeader.jsx";
11 | import CardBody from "../../components/Card/CardBody.jsx";
12 |
13 | import iconsStyle from "./iconsStyle.jsx";
14 |
15 | function Icons(props) {
16 | const { classes } = props;
17 | return (
18 |
19 |
20 |
21 |
22 | Material Design Icons
23 |
24 | Handcrafted by our friends from{" "}
25 |
30 | Google
31 |
32 |
33 |
34 |
35 |
36 |
43 |
44 |
45 |
46 |
47 | The icons are visible on Desktop mode inside an iframe. Since
48 | the iframe is not working on Mobile and Tablets please visit
49 | the icons on their original page on Google. Check the
50 |
55 | Material Icons
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | );
65 | }
66 |
67 | Icons.propTypes = {
68 | classes: PropTypes.object.isRequired
69 | };
70 |
71 | export default withStyles(iconsStyle)(Icons);
72 |
--------------------------------------------------------------------------------
/src/views/Icons/iconsStyle.jsx:
--------------------------------------------------------------------------------
1 | import { boxShadow } from "../../assets/jss/material-dashboard-react.jsx";
2 |
3 | const iconsStyle = {
4 | iframe: {
5 | width: "100%",
6 | height: "500px",
7 | border: "0",
8 | ...boxShadow
9 | },
10 | iframeContainer: {
11 | margin: "0 -20px 0"
12 | },
13 | cardCategoryWhite: {
14 | "&,& a,& a:hover,& a:focus": {
15 | color: "rgba(255,255,255,.62)",
16 | margin: "0",
17 | fontSize: "14px",
18 | marginTop: "0",
19 | marginBottom: "0"
20 | },
21 | "& a,& a:hover,& a:focus": {
22 | color: "#FFFFFF"
23 | }
24 | },
25 | cardTitleWhite: {
26 | color: "#FFFFFF",
27 | marginTop: "0px",
28 | minHeight: "auto",
29 | fontWeight: "300",
30 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif",
31 | marginBottom: "3px",
32 | textDecoration: "none",
33 | "& small": {
34 | color: "#777",
35 | fontSize: "65%",
36 | fontWeight: "400",
37 | lineHeight: "1"
38 | }
39 | }
40 | };
41 |
42 | export default iconsStyle;
43 |
--------------------------------------------------------------------------------
/src/views/Maps/Maps.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | withScriptjs,
4 | withGoogleMap,
5 | GoogleMap,
6 | Marker
7 | } from "react-google-maps";
8 |
9 | const CustomSkinMap = withScriptjs(
10 | withGoogleMap(props => (
11 |
79 |
80 |
81 | ))
82 | );
83 |
84 | function Maps({ ...props }) {
85 | return (
86 | }
89 | containerElement={
}
90 | mapElement={
}
91 | />
92 | );
93 | }
94 |
95 | export default Maps;
96 |
--------------------------------------------------------------------------------
/src/views/UserProfile/UserEditTransition.jsx:
--------------------------------------------------------------------------------
1 | import Slide from '@material-ui/core/Slide';
2 | const UserEditTransition = props => {
3 | return ;
4 | };
5 | export default UserEditTransition;
6 |
--------------------------------------------------------------------------------
/src/views/UserProfile/UserListing.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import { Route } from 'react-router-dom';
3 | import UserProfile from './UserProfile';
4 | import { connect } from 'react-redux';
5 | import { bindActionCreators } from 'redux';
6 | import UserActions from '../../actions/Users';
7 | import MessageBoxActions from '../../actions/MessageBox';
8 | import MessageBoxType from '../../components/MessageBox/MessageBoxType';
9 |
10 | import urljoin from 'url-join';
11 | import UserTable from '../../components/User/UserTable';
12 |
13 | @connect(
14 | state => {
15 | return { users: state.users.data, isLoading: state.users.isLoading };
16 | },
17 | dispatch => {
18 | return {
19 | actions: bindActionCreators(UserActions, dispatch),
20 | messageBoxActions: bindActionCreators(MessageBoxActions, dispatch)
21 | };
22 | }
23 | )
24 | class UserListing extends PureComponent {
25 | componentWillMount() {
26 | this.props.actions.getAllUsers();
27 | }
28 | onEditClick = rowData => {
29 | this.props.history.push(urljoin(this.props.match.url, `${rowData.id}`));
30 | };
31 | onDeleteClick = rowData => {
32 | this.props.messageBoxActions.showMessage(
33 | MessageBoxType.CONFIRM,
34 | `User ${rowData.firstName} will be deleted, are you sure?`,
35 | event => {
36 | if (event.currentTarget.value === 'OK') {
37 | this.props.actions.deleteUser(rowData.id);
38 | }
39 | }
40 | );
41 | };
42 | onAddClick = () => {
43 | this.props.history.push(urljoin(this.props.match.url, '0'));
44 | };
45 | render() {
46 | const columns = [
47 | {
48 | Header: 'Username',
49 | accessor: 'username'
50 | },
51 | {
52 | Header: 'First Name',
53 | accessor: 'firstName'
54 | },
55 | {
56 | Header: 'Last Name',
57 | accessor: 'lastName'
58 | },
59 | {
60 | Header: 'Email',
61 | accessor: 'email'
62 | }
63 | ];
64 | return (
65 |
66 |
74 |
75 |
76 | );
77 | }
78 | }
79 | export default UserListing;
80 |
--------------------------------------------------------------------------------
/src/views/UserProfile/UserProfile.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import { connect } from 'react-redux';
3 | import { bindActionCreators } from 'redux';
4 | import UserActions from '../../actions/Users';
5 | import Dialog from '@material-ui/core/Dialog';
6 | import UserEditTransition from './UserEditTransition';
7 | import UserForm from '../../components/User/UserForm';
8 | import { reduxForm } from 'redux-form';
9 | import { isValidEmail, convertToFormData } from '../../commons/commonFuncs';
10 | import { isUsernameOrEmailExist } from '../../api/userApi';
11 |
12 | const validate = values => {
13 | const errors = {};
14 | const requiredFields = ['username', 'email', 'firstName', 'lastName'];
15 | requiredFields.forEach(field => {
16 | if (!values[field]) {
17 | errors[field] = 'Required';
18 | }
19 | });
20 | if (!isValidEmail(values.email)) {
21 | errors.email = 'Invalid email address';
22 | }
23 | return errors;
24 | };
25 | const asyncValidate = (values, dispatch, props, blurredField) => {
26 | const id = values.id !== undefined ? values.id : 0;
27 | if (blurredField === 'email' && values.email) {
28 | return isUsernameOrEmailExist(values.email, id).then(response => {
29 | if (response) {
30 | throw { email: `${values.email} is already taken` };
31 | }
32 | });
33 | }
34 | return isUsernameOrEmailExist(values.username, id).then(response => {
35 | if (response) {
36 | throw { username: `${values.username} is already taken` };
37 | }
38 | });
39 | };
40 | @connect(
41 | (state, props) => {
42 | const id = props.match.params['id'];
43 | let result = state.users.data.find(i => i.id == id);
44 | return { user: result, initialValues: result };
45 | },
46 | dispatch => {
47 | return {
48 | actions: bindActionCreators(UserActions, dispatch)
49 | };
50 | }
51 | )
52 | @reduxForm({
53 | form: 'UserProfile',
54 | validate,
55 | asyncValidate,
56 | asyncBlurFields: ['username', 'email']
57 | })
58 | class UserProfile extends PureComponent {
59 | constructor(props) {
60 | super(props);
61 | this.state = {
62 | user: props.user || {
63 | id: 0,
64 | username: '',
65 | email: '',
66 | firstName: '',
67 | lastName: '',
68 | avatar: ''
69 | },
70 | open: props.match.params['id'] != undefined,
71 | file: null,
72 | avatarChanged: false
73 | };
74 | this.handleClose = this.handleClose.bind(this);
75 | this.onSave = this.onSave.bind(this);
76 | }
77 | handleClose = () => {
78 | this.props.history.push('/users');
79 | };
80 | onSave = e => {
81 | const data = convertToFormData(e);
82 | data.append('avatar', this.state.file);
83 | this.props.actions.saveUser(data);
84 | this.handleClose();
85 | };
86 | componentWillUpdate(nextProps) {
87 | if (this.props.user !== nextProps.user) {
88 | this.setState((prevState, props) => {
89 | return {
90 | user: {
91 | ...props.user
92 | }
93 | };
94 | });
95 | }
96 | }
97 | onChangeAvatar = e => {
98 | let val = e.target.value;
99 | let _this = this;
100 | const file = e.target.files[0];
101 | if (e.target.type === 'file') {
102 | let reader = new FileReader();
103 | reader.onload = function(pe) {
104 | val = pe.target.result;
105 | _this.setState((prevState, props) => {
106 | return {
107 | user: {
108 | ...prevState.user,
109 | avatar: val
110 | },
111 | file: file,
112 | avatarChanged: true
113 | };
114 | });
115 | };
116 | reader.readAsDataURL(file);
117 | }
118 | };
119 | render() {
120 | return (
121 |
126 |
134 |
135 | );
136 | }
137 | }
138 |
139 | export default UserProfile;
140 |
--------------------------------------------------------------------------------
/src/views/loaders/ComponentLoader.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import LinearProgress from '@material-ui/core/LinearProgress';
3 |
4 | const loading = () => ;
5 | export default loading;
6 |
--------------------------------------------------------------------------------
/src/views/loaders/index.ts:
--------------------------------------------------------------------------------
1 | import Loadable from 'react-loadable';
2 | import loading from './ComponentLoader';
3 |
4 | const Loader = (loader: any) =>
5 | Loadable({
6 | loader,
7 | loading,
8 | timeout: 10000,
9 | /* devblock:start */
10 | delay: 1000
11 | /* devblock:end */
12 | });
13 |
14 | export default Loader;
15 |
--------------------------------------------------------------------------------
/tests/_dummy_data/general.jsx:
--------------------------------------------------------------------------------
1 | // ##############################
2 | // // // Tasks for TasksCard - see Dashboard view
3 | // #############################
4 |
5 | const bugs = [
6 | "Sign contract for \"What are conference organizers afraid of?\"",
7 | "Lines From Great Russian Literature? Or E-mails From My Boss?",
8 | "Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit",
9 | "Create 4 Invisible User Experiences you Never Knew About"
10 | ];
11 | const website = [
12 | "Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit",
13 | "Sign contract for \"What are conference organizers afraid of?\""
14 | ];
15 | const server = [
16 | "Lines From Great Russian Literature? Or E-mails From My Boss?",
17 | "Flooded: One year later, assessing what was lost and what was found when a ravaging rain swept through metro Detroit",
18 | "Sign contract for \"What are conference organizers afraid of?\""
19 | ];
20 |
21 | export default {
22 | // these 3 are used to create the tasks lists in TasksCard - Dashboard view
23 | bugs,
24 | website,
25 | server
26 | };
27 |
--------------------------------------------------------------------------------
/tests/_dummy_data/simulator.js:
--------------------------------------------------------------------------------
1 | export default function(data, inSecond = 5) {
2 | return new Promise(resolve =>
3 | setTimeout(() => resolve(data), inSecond * 1000)
4 | );
5 | }
6 |
--------------------------------------------------------------------------------
/tests/_dummy_data/users.js:
--------------------------------------------------------------------------------
1 | export const users = [{
2 | id: 1,
3 | username: 'Tuan',
4 | email: 'xuantuan93@gmail.com',
5 | firstname: 'Tuan',
6 | lastname: 'Nguyen',
7 | avatar: null
8 | }, {
9 | id: 2,
10 | username: 'Steven',
11 | email: 'baoduy2412@outlook.com',
12 | firstname: 'Steven',
13 | lastname: 'Hoang',
14 | avatar: null
15 | }];
--------------------------------------------------------------------------------
/tests/commons/commonFuncs.test.ts:
--------------------------------------------------------------------------------
1 | require('jest-localstorage-mock');
2 |
3 | import { getImgSrc, newGuid } from '../../src/commons/commonFuncs';
4 |
5 | window.sessionStorage.setItem('BASE_URL', '/ReactJs');
6 |
7 | test('2 GUID must be difference', () => {
8 | const g1 = newGuid();
9 | const g2 = newGuid();
10 |
11 | expect(g1).not.toBe(g2);
12 | });
13 |
14 | test('getImgSrc should add basename to url', () => {
15 | expect(getImgSrc('/img/a.png')).toContain('/ReactJs');
16 | });
17 |
18 | test('getImgSrc should not add basename to url', () => {
19 | expect(getImgSrc('/ReactJs/img/a.png')).toBe('/ReactJs/img/a.png');
20 | });
21 |
22 | test('getImgSrc should return original object', () => {
23 | const url: any = { a: 1 };
24 | expect(getImgSrc(url)).toBe(url);
25 | });
26 |
27 | test('getImgSrc should return original string', () => {
28 | const url = '123';
29 | window.sessionStorage.setItem('BASE_URL', '/');
30 |
31 | expect(getImgSrc(url)).toBe(url);
32 | });
33 |
34 | test('getImgSrc should do nothing', () => {
35 | const url = '123';
36 | window.sessionStorage.setItem('BASE_URL', '');
37 |
38 | expect(getImgSrc(url)).toBe(url);
39 | });
40 |
--------------------------------------------------------------------------------
/tests/commons/guard.test.ts:
--------------------------------------------------------------------------------
1 | import * as guard from '../../src/commons/guard';
2 |
3 | describe('Testing Guard common functions', () => {
4 | test('Check Null and Undefined', () => {
5 | expect(() => guard.argumentNotNull(null)).toThrowError();
6 | expect(() => guard.argumentNotNull(undefined)).toThrowError();
7 |
8 | expect(() => guard.argumentNotNull('')).not.toThrowError();
9 | expect(() => guard.argumentNotNull('Duy')).not.toThrowError();
10 | });
11 |
12 | test('Check Empty', () => {
13 | expect(() => guard.argumentNotEmpty(null)).toThrowError();
14 | expect(() => guard.argumentNotEmpty(undefined)).toThrowError();
15 | expect(() => guard.argumentNotEmpty('')).toThrowError();
16 |
17 | expect(() => guard.argumentNotEmpty('Duy')).not.toThrowError();
18 | });
19 |
20 | test('Check Function', () => {
21 | expect(() => guard.argumentIsFunc(null)).toThrowError();
22 | expect(() => guard.argumentIsFunc(undefined)).toThrowError();
23 | expect(() => guard.argumentIsFunc('')).toThrowError();
24 |
25 | expect(() => guard.argumentIsFunc(() => {})).not.toThrowError();
26 | });
27 |
28 | test('Check String', () => {
29 | expect(() => guard.argumentIsString(null)).toThrowError();
30 | expect(() => guard.argumentIsString(undefined)).toThrowError();
31 | expect(() => guard.argumentIsString(123)).toThrowError();
32 | expect(() => guard.argumentIsString(true)).toThrowError();
33 |
34 | expect(() => guard.argumentIsString('')).not.toThrowError();
35 | expect(() => guard.argumentIsString('Duy')).not.toThrowError();
36 | });
37 |
38 | test('Array Test', () => {
39 | expect(() => guard.argumentIsArray(null)).toThrowError();
40 | expect(() => guard.argumentIsArray(undefined)).toThrowError();
41 | expect(() => guard.argumentIsArray(123)).toThrowError();
42 | expect(() => guard.argumentIsArray(true)).toThrowError();
43 |
44 | expect(() => guard.argumentIsArray([])).not.toThrowError();
45 | expect(() => guard.argumentIsArray([1, 2, 3])).not.toThrowError();
46 | });
47 |
48 | test('Array Not Empty Test', () => {
49 | expect(() => guard.argumentIsArrayAndNotEmpty([])).toThrowError();
50 | expect(() => guard.argumentIsArray([1, 2, 3])).not.toThrowError();
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/tests/components/MessageBox/index.test.tsx:
--------------------------------------------------------------------------------
1 | /*eslint no-console: ["off", { allow: ["warn", "error"] }] */
2 |
3 | import * as React from 'react';
4 |
5 | import MessageBox from '../../../src/components/MessageBox';
6 | import Type from '../../../src/components/MessageBox/MessageBoxType';
7 | import { mount } from 'enzyme';
8 |
9 | const render = ({ callBack, ...rest }: any = {}) => {
10 | if (!callBack) callBack = () => true;
11 |
12 | const item = mount( );
13 |
14 | if (item.mount) item.mount();
15 | return item;
16 | };
17 |
18 | describe(`Testing ${MessageBox.displayName} component`, () => {
19 | test('render without error', () => {
20 | const item = render({ message: 'Hello', open: true });
21 | expect(item).toMatchSnapshot();
22 | });
23 |
24 | test(`render ${Type.INFO}`, () => {
25 | const item = render({ type: Type.INFO, message: 'Hello' });
26 | expect(item).toMatchSnapshot();
27 | });
28 |
29 | test(`render ${Type.CONFIRM}`, () => {
30 | const item = render({ type: Type.CONFIRM, message: 'Hello' });
31 | expect(item).toMatchSnapshot();
32 | });
33 |
34 | test(`render ${Type.DANGER}`, () => {
35 | const item = render({ type: Type.DANGER, message: 'Hello' });
36 | expect(item).toMatchSnapshot();
37 | });
38 |
39 | test(`render ${Type.SUCCESS}`, () => {
40 | const item = render({ type: Type.SUCCESS, message: 'Hello' });
41 | expect(item).toMatchSnapshot();
42 | });
43 |
44 | test(`render ${Type.WARNING}`, () => {
45 | const item = render({ type: Type.WARNING, message: 'Hello' });
46 | expect(item).toMatchSnapshot();
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/tests/components/User/UserForm.test.tsx.ignore:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import UserForm from '../../../src/components/User/UserForm';
4 | import { mount } from 'enzyme';
5 |
6 | const render = ({ user, onClose, onSave }: any = {}) => {
7 | const item = mount(
8 | {}}
13 | />
14 | );
15 |
16 | if (item.mount) item.mount();
17 | return item;
18 | };
19 | describe('Testing UserForm', () => {
20 | const user = {
21 | id: 0,
22 | username: '',
23 | email: '',
24 | firstName: '',
25 | lastName: '',
26 | avatar: null
27 | };
28 | test('render component', () => {
29 | const item = render({ user: user });
30 | expect(item).toMatchSnapshot();
31 | });
32 | test('on click save', () => {
33 | const onSaveClick = jest.fn();
34 | const wrapper = render({ onSave: onSaveClick, user: user });
35 | const btn = wrapper.find('button[type="submit"]');
36 | btn.simulate('submit');
37 | expect(onSaveClick).toBeCalled();
38 | });
39 | test('on click close', () => {
40 | const onCloseClick = jest.fn();
41 | const wrapper = render({ onClose: onCloseClick, user: user });
42 | const btn = wrapper.find('button[type="button"]');
43 | btn.simulate('click');
44 | expect(onCloseClick).toBeCalled();
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/tests/components/User/UserTable.test.tsx.ignore:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import UserTable from '../../../src/components/User/UserTable';
4 | import { mount } from 'enzyme';
5 |
6 | const render = ({
7 | data,
8 | onEditClick,
9 | onAddClick,
10 | onDeleteClick,
11 | columns,
12 | defaultPageSize
13 | }: any = {}) => {
14 | const item = mount(
15 |
23 | );
24 |
25 | if (item.mount) item.mount();
26 | return item;
27 | };
28 |
29 | describe('Testing UserTable', () => {
30 | test('render component', () => {
31 | const item = render();
32 | expect(item).toMatchSnapshot();
33 | });
34 |
35 | test('on click add', () => {
36 | const onAddClick = jest.fn();
37 | const wrapper = render({ onAddClick: onAddClick });
38 | const btn = wrapper.find('button[aria-label="Add"]');
39 | expect(wrapper).toMatchSnapshot();
40 | btn.simulate('click');
41 | expect(onAddClick).toBeCalled();
42 | });
43 |
44 | test('on click edit', () => {
45 | const onEditClick = jest.fn();
46 | const data = [{ name: 'tuan' }];
47 | const columns = [
48 | {
49 | Header: 'Name',
50 | accessor: 'name'
51 | }
52 | ];
53 | const wrapper = render({
54 | onEditClick: onEditClick,
55 | data: data,
56 | columns: columns
57 | });
58 |
59 | const btn = wrapper.find('button[title="Edit"]');
60 | expect(wrapper).toMatchSnapshot();
61 | if (btn) btn.simulate('click');
62 | expect(onEditClick).toBeCalled();
63 | });
64 |
65 | test('on click delete', () => {
66 | const onDeleteClick = jest.fn();
67 | const data = [{ name: 'tuan' }];
68 | const columns = [
69 | {
70 | Header: 'Name',
71 | accessor: 'name'
72 | }
73 | ];
74 | const wrapper = render({
75 | onDeleteClick: onDeleteClick,
76 | data: data,
77 | columns: columns
78 | });
79 | const btn = wrapper.find('button[title="Delete"]');
80 |
81 | expect(wrapper).toMatchSnapshot();
82 | btn.simulate('click');
83 | expect(onDeleteClick).toBeCalled();
84 | });
85 | });
86 |
--------------------------------------------------------------------------------
/tests/components/notification/NotificationPopup.test.tsx:
--------------------------------------------------------------------------------
1 | /*eslint no-console: ["off", { allow: ["warn", "error"] }] */
2 |
3 | import * as React from 'react';
4 |
5 | import NotificationPopup from '../../../src/components/Notification/NotificationPopup';
6 | import Type from '../../../src/components/Notification/NotificationType';
7 | import { mount } from 'enzyme';
8 |
9 | const render = ({ callBack, ...rest }: any = {}) => {
10 | if (!callBack) callBack = () => true;
11 |
12 | const item = mount( );
13 |
14 | if (item.mount) item.mount();
15 | return item;
16 | };
17 |
18 | describe(`Render NotificationPopup tests`, () => {
19 | test('Render 3 items', () => {
20 | const item = render({
21 | dataSource: [
22 | {
23 | type: Type.CONFIRM,
24 | message: 'Hello'
25 | },
26 | {
27 | type: Type.INFO,
28 | message: 'Hello'
29 | },
30 | {
31 | type: Type.DANGER,
32 | message: 'Hello'
33 | }
34 | ]
35 | });
36 |
37 | expect(item).toMatchSnapshot();
38 | expect(item.find('svg').length).toBe(6);
39 | });
40 |
41 | test('Error when no DataSource', () => {
42 | const original = console.error;
43 | console.error = jest.fn();
44 | render();
45 |
46 | expect(console.error).toHaveBeenCalled();
47 | console.error = original;
48 | });
49 |
50 | test('Error when DataSource is wrong type', () => {
51 | const original = console.error;
52 | console.error = jest.fn();
53 | render({ dataSource: [{}, {}, {}] });
54 |
55 | expect(console.error).toHaveBeenCalled();
56 | console.error = original;
57 | });
58 |
59 | test('onClose called', () => {
60 | const item = render({
61 | dataSource: [
62 | {
63 | type: Type.CONFIRM,
64 | message: 'Hello'
65 | },
66 | {
67 | type: Type.INFO,
68 | message: 'Hello'
69 | },
70 | {
71 | type: Type.DANGER,
72 | message: 'Hello',
73 | onClose: () => true
74 | }
75 | ],
76 | displayIn: 2,
77 | subsequentDelay: 1
78 | });
79 |
80 | const p = new Promise((r, j) => {
81 | item.setProps({ onClose: () => r(true) });
82 | setTimeout(() => j(false), 4000);
83 | });
84 |
85 | return expect(p).resolves.toBe(true);
86 | });
87 | });
88 |
--------------------------------------------------------------------------------
/tests/components/notification/__snapshots__/NotificationPopup.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Render NotificationPopup tests Render 3 items 1`] = `""`;
4 |
--------------------------------------------------------------------------------
/tests/components/notification/__snapshots__/index.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Render Notification tests Render 3 items 1`] = `
4 | Array [
5 | Array [
6 |
27 |
30 |
37 |
40 |
41 |
42 |
45 | ,
46 | "",
47 | ],
48 | "",
49 | "",
50 | ]
51 | `;
52 |
--------------------------------------------------------------------------------
/tests/components/notification/index.test.tsx:
--------------------------------------------------------------------------------
1 | /*eslint no-console: ["off", { allow: ["warn", "error"] }] */
2 |
3 | import * as React from 'react';
4 |
5 | import Notification from '../../../src/components/Notification';
6 | import Type from '../../../src/components/Notification/NotificationType';
7 | import { mount } from 'enzyme';
8 |
9 | const render = ({ callBack, ...rest }: any = {}) => {
10 | if (!callBack) callBack = () => true;
11 |
12 | const item = mount( );
13 |
14 | if (item.mount) item.mount();
15 | return item;
16 | };
17 |
18 | describe(`Render Notification tests`, () => {
19 | test('Render 3 items', () => {
20 | const item = render({
21 | dataSource: [
22 | {
23 | type: Type.CONFIRM,
24 | message: 'Hello'
25 | },
26 | {
27 | type: Type.INFO,
28 | message: 'Hello'
29 | },
30 | {
31 | type: Type.DANGER,
32 | message: 'Hello'
33 | }
34 | ]
35 | });
36 |
37 | expect(item).toMatchSnapshot();
38 | expect(item.find('svg').length).toBe(6);
39 | });
40 |
41 | test('Error when no DataSource', () => {
42 | const original = console.error;
43 | console.error = jest.fn();
44 | render();
45 |
46 | expect(console.error).toHaveBeenCalled();
47 | console.error = original;
48 | });
49 |
50 | test('Error when DataSource is wrong type', () => {
51 | const original = console.error;
52 | console.error = jest.fn();
53 | render({ dataSource: [{}, {}, {}] });
54 |
55 | expect(console.error).toHaveBeenCalled();
56 | console.error = original;
57 | });
58 |
59 | test('onClose called', () => {
60 | const item = render({
61 | dataSource: [
62 | {
63 | type: Type.CONFIRM,
64 | message: 'Hello'
65 | },
66 | {
67 | type: Type.INFO,
68 | message: 'Hello'
69 | },
70 | {
71 | type: Type.DANGER,
72 | message: 'Hello',
73 | onClose: () => true
74 | }
75 | ],
76 | displayIn: 2,
77 | subsequentDelay: 1
78 | });
79 |
80 | const p = new Promise((r, j) => {
81 | item.setProps({ onClose: () => r(true) });
82 | setTimeout(() => j(false), 4000);
83 | });
84 |
85 | return expect(p).resolves.toBe(true);
86 | });
87 | });
88 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "module": "es2015",
5 | "target": "es5",
6 | "lib": ["es6", "esnext", "dom"],
7 | //"sourceMap": true,
8 | "allowJs": true,
9 | "jsx": "react",
10 | "moduleResolution": "node",
11 | "rootDir": "src",
12 | //"noEmit": true,
13 | "pretty": true,
14 | "skipLibCheck": true,
15 | "removeComments": false,
16 | "forceConsistentCasingInFileNames": true,
17 | //"emitDeclarationOnly": true,
18 | "allowSyntheticDefaultImports": true,
19 | "noImplicitReturns": true,
20 | "noImplicitThis": true,
21 | "noImplicitAny": true,
22 | "strictNullChecks": true,
23 | "suppressImplicitAnyIndexErrors": true,
24 | "noUnusedLocals": true,
25 | "experimentalDecorators": true,
26 | //"declaration": true,
27 | "strict": true
28 | },
29 | "include": ["./src/**/*.tsx", "./src/**/*.ts", "tests/*.ts"],
30 | "exclude": [
31 | "node_modules",
32 | "build",
33 | "dist",
34 | "tests",
35 | "configs",
36 | "scripts",
37 | "acceptance-tests",
38 | "webpack",
39 | "jest",
40 | "src/setupTests.ts",
41 | "sample"
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------
/tsconfig.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "module": "commonjs"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------