mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ui.git
				synced 2025-10-30 18:27:58 +00:00 
			
		
		
		
	TW-166 Login Done
This commit is contained in:
		
							
								
								
									
										29
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| BSD 3-Clause License | ||||
|  | ||||
| Copyright (c) 2020, Telecom Infra Project | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
| 1. Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
|  | ||||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|    this list of conditions and the following disclaimer in the documentation | ||||
|    and/or other materials provided with the distribution. | ||||
|  | ||||
| 3. Neither the name of the copyright holder nor the names of its | ||||
|    contributors may be used to endorse or promote products derived from | ||||
|    this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| @@ -5,15 +5,19 @@ | ||||
|     Install Dependencies | ||||
|     	`npm install` | ||||
|  | ||||
|    To link cu-ui package locally for development: | ||||
|       `npm link ../cu-ui`  | ||||
| To link wlan-cloud-ui-library package locally for development: | ||||
| `npm link ../wlan-cloud-ui-library` | ||||
|  | ||||
| ## Run: | ||||
|  | ||||
| ### Development | ||||
|  | ||||
|      `npm start` | ||||
|  | ||||
| ### Tests | ||||
|  | ||||
|      `npm run test` | ||||
|  | ||||
| ### Production | ||||
|  | ||||
|      `npm run build` | ||||
|   | ||||
| @@ -3,9 +3,10 @@ import T from 'prop-types'; | ||||
| import { Route, Redirect } from 'react-router-dom'; | ||||
|  | ||||
| import MasterLayout from 'containers/MasterLayout'; | ||||
| import { getItem } from 'utils/localStorage'; | ||||
| import { AUTH_TOKEN } from 'constants/index'; | ||||
|  | ||||
| import { getItem } from 'utils/localStorage'; | ||||
|  | ||||
| const ProtectedRouteWithLayout = ({ component: Component, ...rest }) => ( | ||||
|   <Route | ||||
|     {...rest} | ||||
|   | ||||
| @@ -2,11 +2,13 @@ import React from 'react'; | ||||
| import { Helmet } from 'react-helmet'; | ||||
| import { Switch, Route } from 'react-router-dom'; | ||||
|  | ||||
| import { ThemeProvider, Login, Dashboard } from 'cu-ui'; | ||||
| import { ThemeProvider, Dashboard } from 'wlan-cloud-ui-library'; | ||||
|  | ||||
| import logo from 'images/logo-light.png'; | ||||
| import logoMobile from 'images/logoxmobile.jpg'; | ||||
|  | ||||
| import Login from 'containers/Login'; | ||||
|  | ||||
| import ProtectedRouteWithLayout from './components/ProtectedRouteWithLayout'; | ||||
|  | ||||
| const App = () => ( | ||||
|   | ||||
							
								
								
									
										33
									
								
								app/containers/Login/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/containers/Login/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| import React from 'react'; | ||||
| import gql from 'graphql-tag'; | ||||
| import { useMutation, useApolloClient } from '@apollo/react-hooks'; | ||||
|  | ||||
| import { Login as LoginPage } from 'wlan-cloud-ui-library'; | ||||
|  | ||||
| import { AUTH_TOKEN } from 'constants/index'; | ||||
|  | ||||
| import { setItem } from 'utils/localStorage'; | ||||
|  | ||||
| const AUTHENTICATE_USER = gql` | ||||
|   mutation AuthenticateUser($email: String!, $password: String!) { | ||||
|     authenticateUser(email: $email, password: $password) { | ||||
|       token | ||||
|     } | ||||
|   } | ||||
| `; | ||||
|  | ||||
| const Login = () => { | ||||
|   const client = useApolloClient(); | ||||
|   const [authenticateUser] = useMutation(AUTHENTICATE_USER); | ||||
|  | ||||
|   const handleLogin = (email, password) => { | ||||
|     authenticateUser({ variables: { email, password } }).then(({ data }) => { | ||||
|       client.resetStore(); | ||||
|       setItem(AUTH_TOKEN, data.authenticateUser.token, data.authenticateUser.token.expires_in); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   return <LoginPage onLogin={handleLogin} />; | ||||
| }; | ||||
|  | ||||
| export default Login; | ||||
| @@ -1,13 +1,25 @@ | ||||
| import React from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { useLocation } from 'react-router-dom'; | ||||
| import { useApolloClient } from '@apollo/react-hooks'; | ||||
|  | ||||
| import { AppLayout as Layout } from 'cu-ui'; | ||||
| import { AppLayout as Layout } from 'wlan-cloud-ui-library'; | ||||
|  | ||||
| import { AUTH_TOKEN } from 'constants/index'; | ||||
|  | ||||
| import { removeItem } from 'utils/localStorage'; | ||||
|  | ||||
| const MasterLayout = ({ children }) => { | ||||
|   const client = useApolloClient(); | ||||
|   const location = useLocation(); | ||||
|  | ||||
|   const handleLogout = () => { | ||||
|     removeItem(AUTH_TOKEN); | ||||
|     client.resetStore(); | ||||
|   }; | ||||
|  | ||||
|   return ( | ||||
|     <Layout onLogout={() => {}} locationState={location}> | ||||
|     <Layout onLogout={handleLogout} locationState={location}> | ||||
|       {children} | ||||
|     </Layout> | ||||
|   ); | ||||
|   | ||||
							
								
								
									
										51
									
								
								app/index.js
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								app/index.js
									
									
									
									
									
								
							| @@ -3,6 +3,7 @@ import ReactDOM from 'react-dom'; | ||||
| import { BrowserRouter as Router } from 'react-router-dom'; | ||||
| import ApolloClient from 'apollo-boost'; | ||||
| import { ApolloProvider } from '@apollo/react-hooks'; | ||||
| import gql from 'graphql-tag'; | ||||
|  | ||||
| import 'styles/antd.less'; | ||||
| import 'styles/index.scss'; | ||||
| @@ -10,27 +11,65 @@ import 'styles/index.scss'; | ||||
| import App from 'containers/App'; | ||||
| import { AUTH_TOKEN } from 'constants/index'; | ||||
|  | ||||
| import { getItem } from 'utils/localStorage'; | ||||
|  | ||||
| const MOUNT_NODE = document.getElementById('root'); | ||||
|  | ||||
| const REFRESH_TOKEN = gql` | ||||
|   mutation UpdateToken($refreshToken: String!) { | ||||
|     updateToken(refreshToken: $refreshToken) { | ||||
|       token | ||||
|     } | ||||
|   } | ||||
| `; | ||||
|  | ||||
| const client = new ApolloClient({ | ||||
|   // uri: "" | ||||
|   uri: 'http://localhost:4000/', | ||||
|   request: operation => { | ||||
|     const token = localStorage.getItem(AUTH_TOKEN); | ||||
|     const token = getItem(AUTH_TOKEN); | ||||
|     operation.setContext({ | ||||
|       headers: { | ||||
|         authorization: token ? `Bearer ${token}` : '', | ||||
|         authorization: token ? `Bearer ${token.access_token}` : '', | ||||
|       }, | ||||
|     }); | ||||
|   }, | ||||
|   onError: ({ graphQLErrors, operation, forward }) => { | ||||
|     if (graphQLErrors) { | ||||
|       graphQLErrors.forEach(err => { | ||||
|         // handle errors differently based on its error code | ||||
|         switch (err.extensions.code) { | ||||
|           case 'UNAUTHENTICATED': | ||||
|             operation.setContext({ | ||||
|               headers: { | ||||
|                 ...operation.getContext().headers, | ||||
|                 authorization: client | ||||
|                   .mutate({ | ||||
|                     mutation: REFRESH_TOKEN, | ||||
|                     variables: { | ||||
|                       refreshToken: getItem(AUTH_TOKEN).refresh_token, | ||||
|                     }, | ||||
|                   }) | ||||
|                   .then(data => { | ||||
|                     return data.updateToken.token; | ||||
|                   }), | ||||
|               }, | ||||
|             }); | ||||
|             return forward(operation); | ||||
|           default: | ||||
|             return forward(operation); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| const render = () => { | ||||
|   ReactDOM.render( | ||||
|     <ApolloProvider client={client}> | ||||
|     <Router> | ||||
|       <ApolloProvider client={client}> | ||||
|         <App /> | ||||
|       </Router> | ||||
|     </ApolloProvider>, | ||||
|       </ApolloProvider> | ||||
|     </Router>, | ||||
|     MOUNT_NODE | ||||
|   ); | ||||
| }; | ||||
|   | ||||
| @@ -22,17 +22,15 @@ export const removeItem = key => { | ||||
| }; | ||||
|  | ||||
| export const getItem = key => { | ||||
|   let value; | ||||
|   let value = null; | ||||
|   try { | ||||
|     value = JSON.parse(window.localStorage.getItem(key) || '{}'); | ||||
|     value = JSON.parse(window.localStorage.getItem(key)); | ||||
|   } catch (err) { | ||||
|     removeItem(); | ||||
|  | ||||
|     return {}; | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   if (isItemExpired(value)) { | ||||
|     return removeItem(); | ||||
|     return removeItem(key); | ||||
|   } | ||||
|  | ||||
|   return value; | ||||
|   | ||||
							
								
								
									
										75
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										75
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| { | ||||
|   "name": "cu-portal", | ||||
|   "name": "wlan-cloud-ui", | ||||
|   "version": "0.1.0", | ||||
|   "lockfileVersion": 1, | ||||
|   "requires": true, | ||||
| @@ -49,6 +49,63 @@ | ||||
|         "tslib": "^1.10.0" | ||||
|       } | ||||
|     }, | ||||
|     "@apollo/react-components": { | ||||
|       "version": "3.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/@apollo/react-components/-/react-components-3.1.4.tgz", | ||||
|       "integrity": "sha512-dLZFeJ+x48nPuo2BjFjfbl8afQyazoqU8xBTidMnYy99w9DcTHtnURTw18o2dT5jkfuIJEWjbTfxyjJnHk+clw==", | ||||
|       "requires": { | ||||
|         "@apollo/react-common": "^3.1.4", | ||||
|         "@apollo/react-hooks": "^3.1.4", | ||||
|         "prop-types": "^15.7.2", | ||||
|         "ts-invariant": "^0.4.4", | ||||
|         "tslib": "^1.10.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "@apollo/react-common": { | ||||
|           "version": "3.1.4", | ||||
|           "resolved": "https://registry.npmjs.org/@apollo/react-common/-/react-common-3.1.4.tgz", | ||||
|           "integrity": "sha512-X5Kyro73bthWSCBJUC5XYQqMnG0dLWuDZmVkzog9dynovhfiVCV4kPSdgSIkqnb++cwCzOVuQ4rDKVwo2XRzQA==", | ||||
|           "requires": { | ||||
|             "ts-invariant": "^0.4.4", | ||||
|             "tslib": "^1.10.0" | ||||
|           } | ||||
|         }, | ||||
|         "@apollo/react-hooks": { | ||||
|           "version": "3.1.4", | ||||
|           "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.1.4.tgz", | ||||
|           "integrity": "sha512-yamD5a1Gu9fGQjZYEQn2nSG+BRyde4dy055agtYOvP/5/njJBSJ25tRFbjxKf7+YW9fsu2Xguib3anoQTuesNg==", | ||||
|           "requires": { | ||||
|             "@apollo/react-common": "^3.1.4", | ||||
|             "@wry/equality": "^0.1.9", | ||||
|             "ts-invariant": "^0.4.4", | ||||
|             "tslib": "^1.10.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "@apollo/react-hoc": { | ||||
|       "version": "3.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/@apollo/react-hoc/-/react-hoc-3.1.4.tgz", | ||||
|       "integrity": "sha512-dCzVM2/JzEWqwTocwozb9/msOgVY5EG7gh593IIXYcBfHcthSK21nIsbH/uDgwCcLSIZE2EOC3n0aKgDuoMtjA==", | ||||
|       "requires": { | ||||
|         "@apollo/react-common": "^3.1.4", | ||||
|         "@apollo/react-components": "^3.1.4", | ||||
|         "hoist-non-react-statics": "^3.3.0", | ||||
|         "ts-invariant": "^0.4.4", | ||||
|         "tslib": "^1.10.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "@apollo/react-common": { | ||||
|           "version": "3.1.4", | ||||
|           "resolved": "https://registry.npmjs.org/@apollo/react-common/-/react-common-3.1.4.tgz", | ||||
|           "integrity": "sha512-X5Kyro73bthWSCBJUC5XYQqMnG0dLWuDZmVkzog9dynovhfiVCV4kPSdgSIkqnb++cwCzOVuQ4rDKVwo2XRzQA==", | ||||
|           "requires": { | ||||
|             "ts-invariant": "^0.4.4", | ||||
|             "tslib": "^1.10.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "@apollo/react-hooks": { | ||||
|       "version": "3.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.1.3.tgz", | ||||
| @@ -3650,10 +3707,6 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "cu-ui": { | ||||
|       "version": "git+https://sean_macfarlane@bitbucket.org/connectustechnologies/connectus-wlan-ui-workspace.git#c7be790677869070cb390411bdd4ba453e788606", | ||||
|       "from": "git+https://sean_macfarlane@bitbucket.org/connectustechnologies/connectus-wlan-ui-workspace.git" | ||||
|     }, | ||||
|     "currently-unhandled": { | ||||
|       "version": "0.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", | ||||
| @@ -6097,6 +6150,14 @@ | ||||
|         "minimalistic-crypto-utils": "^1.0.1" | ||||
|       } | ||||
|     }, | ||||
|     "hoist-non-react-statics": { | ||||
|       "version": "3.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", | ||||
|       "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", | ||||
|       "requires": { | ||||
|         "react-is": "^16.7.0" | ||||
|       } | ||||
|     }, | ||||
|     "home-or-tmp": { | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", | ||||
| @@ -13562,6 +13623,10 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "wlan-cloud-ui-library": { | ||||
|       "version": "git+ssh://git@github.com/Telecominfraproject/wlan-cloud-ui-library.git#abbb7f2c8eaaeec30662331c0aed190be66c0de6", | ||||
|       "from": "git+ssh://git@github.com/Telecominfraproject/wlan-cloud-ui-library.git" | ||||
|     }, | ||||
|     "word-wrap": { | ||||
|       "version": "1.2.3", | ||||
|       "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| { | ||||
|   "name": "cu-portal", | ||||
|   "name": "wlan-cloud-ui", | ||||
|   "version": "0.1.0", | ||||
|   "author": "ConnectUs", | ||||
|   "description": "", | ||||
|   "description": "React Portal", | ||||
|   "engines": { | ||||
|     "npm": ">=5", | ||||
|     "node": ">=8" | ||||
| @@ -17,12 +17,14 @@ | ||||
|   "license": "MIT", | ||||
|   "dependencies": { | ||||
|     "@ant-design/icons": "^4.0.2", | ||||
|     "@apollo/react-hoc": "^3.1.4", | ||||
|     "@apollo/react-hooks": "^3.1.3", | ||||
|     "antd": "^4.0.2", | ||||
|     "apollo-boost": "^0.4.7", | ||||
|     "clean-webpack-plugin": "^3.0.0", | ||||
|     "cu-ui": "git+https://sean_macfarlane@bitbucket.org/connectustechnologies/connectus-wlan-ui-workspace.git", | ||||
|     "wlan-cloud-ui-library": "git+ssh://git@github.com/Telecominfraproject/wlan-cloud-ui-library.git", | ||||
|     "graphql": "^14.6.0", | ||||
|     "graphql-tag": "^2.10.3", | ||||
|     "html-webpack-plugin": "^3.2.0", | ||||
|     "mini-css-extract-plugin": "^0.9.0", | ||||
|     "optimize-css-assets-webpack-plugin": "^5.0.3", | ||||
|   | ||||
| @@ -43,12 +43,19 @@ module.exports = { | ||||
|     modules: [ | ||||
|       'node_modules', | ||||
|       'app', | ||||
|       path.resolve(__dirname, '../', 'node_modules', 'cu-ui', 'src'), | ||||
|       path.resolve(__dirname, '../', 'node_modules', 'wlan-cloud-ui-library', 'src'), | ||||
|     ], | ||||
|     alias: { | ||||
|       app: path.resolve(__dirname, '../', 'app'), | ||||
|       react: path.resolve(__dirname, '../', 'node_modules', 'react'), | ||||
|       'cu-ui': path.resolve(__dirname, '../', 'node_modules', 'cu-ui', 'src'), | ||||
|       'react-router-dom': path.resolve('./node_modules/react-router-dom'), | ||||
|       'wlan-cloud-ui-library': path.resolve( | ||||
|         __dirname, | ||||
|         '../', | ||||
|         'node_modules', | ||||
|         'wlan-cloud-ui-library', | ||||
|         'src' | ||||
|       ), | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sean Macfarlane
					Sean Macfarlane