@flare/tuitio-react-client
parent
e1c4b2ca04
commit
7f6056baf4
8
.env
8
.env
|
@ -1,8 +1,8 @@
|
||||||
#REACT_APP_IDENTITY_AUTHENTICATION_URL=http://localhost:5063/identity/authenticate?UserName={username}&Password={password}
|
#REACT_APP_TUITIO_URL=http://localhost:5063/identity/authenticate?UserName={username}&Password={password}
|
||||||
|
|
||||||
REACT_APP_IDENTITY_AUTHENTICATION_URL=https://lab.code-rove.com/tuitio/identity/authenticate?UserName={username}&Password={password}
|
REACT_APP_TUITIO_URL=https://lab.code-rove.com/tuitio
|
||||||
REACT_APP_NETWORK_RESURRECTOR_API_URL=http://localhost:5064
|
#REACT_APP_NETWORK_RESURRECTOR_API_URL=http://localhost:5064
|
||||||
#REACT_APP_NETWORK_RESURRECTOR_API_URL=https://lab.code-rove.com/network-resurrector-api
|
REACT_APP_NETWORK_RESURRECTOR_API_URL=https://lab.code-rove.com/network-resurrector-api
|
||||||
|
|
||||||
#600000 milliseconds = 10 minutes
|
#600000 milliseconds = 10 minutes
|
||||||
REACT_APP_MACHINE_PING_INTERVAL=600000
|
REACT_APP_MACHINE_PING_INTERVAL=600000
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
PUBLIC_URL=/network-resurrector/
|
PUBLIC_URL=/network-resurrector/
|
||||||
REACT_APP_IDENTITY_AUTHENTICATION_URL=https://lab.code-rove.com/tuitio/identity/authenticate?UserName={username}&Password={password}
|
REACT_APP_TUITIO_URL=https://lab.code-rove.com/tuitio
|
||||||
REACT_APP_NETWORK_RESURRECTOR_API_URL=https://lab.code-rove.com/network-resurrector-api
|
REACT_APP_NETWORK_RESURRECTOR_API_URL=https://lab.code-rove.com/network-resurrector-api
|
||||||
|
|
||||||
#900000 milliseconds = 15 minutes
|
#900000 milliseconds = 15 minutes
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,7 +13,7 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flare/js-utils": "^1.0.2",
|
"@flare/tuitio-react-client": "^1.0.0",
|
||||||
"@material-ui/core": "^4.11.2",
|
"@material-ui/core": "^4.11.2",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"@testing-library/jest-dom": "^5.11.6",
|
"@testing-library/jest-dom": "^5.11.6",
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
import ApplicationStepper from "./stepper/ApplicationStepper";
|
import ApplicationStepper from "./stepper/ApplicationStepper";
|
||||||
import Switcher from "./Switcher";
|
import Switcher from "./Switcher";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { useAuthorizationToken } from "../../hooks";
|
import { useTuitioToken } from "@flare/tuitio-react-client";
|
||||||
import LoginContainer from "../../features/login/components/LoginContainer";
|
import LoginContainer from "../../features/login/components/LoginContainer";
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
|
@ -16,7 +16,7 @@ const useStyles = makeStyles(() => ({
|
||||||
|
|
||||||
const Main = () => {
|
const Main = () => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { validateToken } = useAuthorizationToken();
|
const { validate: validateToken } = useTuitioToken();
|
||||||
const tokenIsValid = validateToken();
|
const tokenIsValid = validateToken();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useCallback } from "react";
|
import React, { useState, useMemo } from "react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import {
|
import {
|
||||||
|
@ -18,35 +18,29 @@ import LoginComponent from "./LoginComponent";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useToast } from "../../../hooks";
|
import { useToast } from "../../../hooks";
|
||||||
import styles from "../styles";
|
import styles from "../styles";
|
||||||
|
import { useTuitioUser } from "@flare/tuitio-react-client";
|
||||||
|
|
||||||
const useStyles = makeStyles(styles);
|
const useStyles = makeStyles(styles);
|
||||||
|
|
||||||
const LoggedInComponent = ({
|
const LoggedInComponent = ({ credentials, onChange, onLogin, onLogout }) => {
|
||||||
credentials,
|
|
||||||
token,
|
|
||||||
onChange,
|
|
||||||
onLogin,
|
|
||||||
onLogout
|
|
||||||
}) => {
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
const { info } = useToast();
|
const { info } = useToast();
|
||||||
|
const { lastLoginDate, userName } = useTuitioUser();
|
||||||
|
|
||||||
const handleExpandLogin = () => {
|
const handleExpandLogin = () => {
|
||||||
setExpanded(!expanded);
|
setExpanded(!expanded);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTokenValidFrom = useCallback(() => {
|
const loginDate = useMemo(() => {
|
||||||
const tokenValidFrom = token?.validFrom;
|
if (lastLoginDate) {
|
||||||
|
const valueForDisplay = t("LONG_DATE", { date: lastLoginDate });
|
||||||
if (tokenValidFrom) {
|
|
||||||
const valueForDisplay = t("LONG_DATE", { date: tokenValidFrom });
|
|
||||||
return valueForDisplay;
|
return valueForDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "N/A";
|
return "N/A";
|
||||||
}, [token, t]);
|
}, [lastLoginDate, t]);
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
const result = await onLogin();
|
const result = await onLogin();
|
||||||
|
@ -65,15 +59,11 @@ const LoggedInComponent = ({
|
||||||
<AccountBox />
|
<AccountBox />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
}
|
}
|
||||||
title={
|
title={<strong>{t("Login.Hello", { username: userName })}</strong>}
|
||||||
<strong>
|
|
||||||
{t("Login.Hello", { username: credentials.userName })}
|
|
||||||
</strong>
|
|
||||||
}
|
|
||||||
subheader={
|
subheader={
|
||||||
<Tooltip title={t("Login.AuthenticationDate")}>
|
<Tooltip title={t("Login.AuthenticationDate")}>
|
||||||
<Typography variant="caption" display="block">
|
<Typography variant="caption" display="block">
|
||||||
{getTokenValidFrom()}
|
{loginDate}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
|
@ -117,7 +107,6 @@ const LoggedInComponent = ({
|
||||||
|
|
||||||
LoggedInComponent.propTypes = {
|
LoggedInComponent.propTypes = {
|
||||||
credentials: PropTypes.object.isRequired,
|
credentials: PropTypes.object.isRequired,
|
||||||
token: PropTypes.object,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
onLogin: PropTypes.func.isRequired,
|
onLogin: PropTypes.func.isRequired,
|
||||||
onLogout: PropTypes.func.isRequired
|
onLogout: PropTypes.func.isRequired
|
||||||
|
|
|
@ -1,59 +1,49 @@
|
||||||
import React, { useContext } from "react";
|
import React, { useState } from "react";
|
||||||
import LoginCard from "./LoginCard";
|
import LoginCard from "./LoginCard";
|
||||||
import { authenticate, invalidate } from "../../../utils/identity";
|
import { useToast } from "../../../hooks";
|
||||||
import {
|
|
||||||
ApplicationStateContext,
|
|
||||||
ApplicationDispatchContext
|
|
||||||
} from "../../../state/ApplicationContexts";
|
|
||||||
import { useToast, useAuthorizationToken } from "../../../hooks";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import LoggedInComponent from "./LoggedInComponent";
|
import LoggedInComponent from "./LoggedInComponent";
|
||||||
|
import { useTuitioClient, useTuitioToken } from "@flare/tuitio-react-client";
|
||||||
|
|
||||||
const LoginContainer = () => {
|
const LoginContainer = () => {
|
||||||
const state = useContext(ApplicationStateContext);
|
const [credentials, setCredentials] = useState({
|
||||||
const dispatchActions = useContext(ApplicationDispatchContext);
|
userName: "",
|
||||||
|
password: ""
|
||||||
|
});
|
||||||
|
|
||||||
const { error } = useToast();
|
const { error } = useToast();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { tokenIsValid, invalidateToken, getToken } = useAuthorizationToken();
|
const { login, logout } = useTuitioClient({
|
||||||
|
onLoginFailed: response => error(t("Login.IncorrectCredentials")),
|
||||||
|
onLoginError: err => error(err.message)
|
||||||
|
});
|
||||||
|
const { valid: tokenIsValid } = useTuitioToken();
|
||||||
|
|
||||||
const handleChange = prop => event => {
|
const handleChange = prop => event => {
|
||||||
dispatchActions.onCredentialsChange(prop, event.target.value);
|
setCredentials(prev => ({ ...prev, [prop]: event.target.value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleLogin = () => {
|
||||||
const { userName, password } = state.credentials;
|
const { userName, password } = credentials;
|
||||||
|
return login(userName, password);
|
||||||
try {
|
|
||||||
const response = await authenticate(userName, password);
|
|
||||||
if (response.status === "SUCCESS") {
|
|
||||||
dispatchActions.onAuthorizationTokenChange(response.token);
|
|
||||||
return response.token;
|
|
||||||
} else if (response.status === "BAD_CREDENTIALS") {
|
|
||||||
error(t("Login.IncorrectCredentials"));
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
error(err.message);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
invalidate();
|
logout();
|
||||||
invalidateToken();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{tokenIsValid ? (
|
{tokenIsValid ? (
|
||||||
<LoggedInComponent
|
<LoggedInComponent
|
||||||
credentials={state.credentials}
|
credentials={credentials}
|
||||||
token={getToken()}
|
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onLogin={handleLogin}
|
onLogin={handleLogin}
|
||||||
onLogout={handleLogout}
|
onLogout={handleLogout}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<LoginCard
|
<LoginCard
|
||||||
credentials={state.credentials}
|
credentials={credentials}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onLogin={handleLogin}
|
onLogin={handleLogin}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
export { useToast } from "./useToast";
|
export { useToast } from "./useToast";
|
||||||
export { useAuthorizationToken } from "./useAuthorizationToken";
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import { useContext } from "react";
|
|
||||||
import {
|
|
||||||
ApplicationStateContext,
|
|
||||||
ApplicationDispatchContext
|
|
||||||
} from "../state/ApplicationContexts";
|
|
||||||
|
|
||||||
export const useAuthorizationToken = () => {
|
|
||||||
const state = useContext(ApplicationStateContext);
|
|
||||||
const dispatchActions = useContext(ApplicationDispatchContext);
|
|
||||||
|
|
||||||
const getToken = () => state.security.authorization.token;
|
|
||||||
const validateToken = () => {
|
|
||||||
const token = getToken();
|
|
||||||
if (!token) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const valid = new Date(token.validUntil) >= new Date();
|
|
||||||
return valid;
|
|
||||||
};
|
|
||||||
|
|
||||||
const tokenIsValid = validateToken();
|
|
||||||
|
|
||||||
const invalidateToken = () => {
|
|
||||||
dispatchActions.onAuthorizationTokenChange(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
return { getToken, validateToken, tokenIsValid, invalidateToken };
|
|
||||||
};
|
|
|
@ -4,11 +4,14 @@ import "./index.css";
|
||||||
import "./utils/i18n";
|
import "./utils/i18n";
|
||||||
import App from "./components/App";
|
import App from "./components/App";
|
||||||
import { BrowserRouter as Router } from "react-router-dom";
|
import { BrowserRouter as Router } from "react-router-dom";
|
||||||
|
import { TuitioProvider } from "@flare/tuitio-react-client";
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Router basename={process.env.PUBLIC_URL || ""}>
|
<Router basename={process.env.PUBLIC_URL || ""}>
|
||||||
<Suspense fallback={<div>Loading...</div>}>
|
<Suspense fallback={<div>Loading...</div>}>
|
||||||
<App />
|
<TuitioProvider tuitioUrl={process.env.REACT_APP_TUITIO_URL}>
|
||||||
|
<App />
|
||||||
|
</TuitioProvider>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Router>,
|
</Router>,
|
||||||
document.getElementById("root")
|
document.getElementById("root")
|
||||||
|
|
|
@ -1,20 +1,4 @@
|
||||||
import { localStorage } from "@flare/js-utils";
|
|
||||||
import { storageKeys } from "../utils/identity";
|
|
||||||
|
|
||||||
const { getItem } = localStorage;
|
|
||||||
const token = getItem(storageKeys.TOKEN);
|
|
||||||
const userName = getItem(storageKeys.USER);
|
|
||||||
|
|
||||||
export const initialState = {
|
export const initialState = {
|
||||||
credentials: {
|
|
||||||
userName: userName || "",
|
|
||||||
password: ""
|
|
||||||
},
|
|
||||||
security: {
|
|
||||||
authorization: {
|
|
||||||
token
|
|
||||||
}
|
|
||||||
},
|
|
||||||
network: {
|
network: {
|
||||||
machines: Object.assign([], { loaded: false }),
|
machines: Object.assign([], { loaded: false }),
|
||||||
test: ""
|
test: ""
|
||||||
|
|
|
@ -1,15 +1,5 @@
|
||||||
export function reducer(state, action) {
|
export function reducer(state, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "onCredentialsChange": {
|
|
||||||
const { prop, value } = action.payload;
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
credentials: {
|
|
||||||
...state.credentials,
|
|
||||||
[prop]: value
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case "onNetworkChange": {
|
case "onNetworkChange": {
|
||||||
const { prop, value } = action.payload;
|
const { prop, value } = action.payload;
|
||||||
return {
|
return {
|
||||||
|
@ -20,19 +10,6 @@ export function reducer(state, action) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "onAuthorizationTokenChange": {
|
|
||||||
const { token } = action.payload;
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
security: {
|
|
||||||
...state.security,
|
|
||||||
authorization: {
|
|
||||||
...state.security.authorization,
|
|
||||||
token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
default: {
|
default: {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -40,10 +17,6 @@ export function reducer(state, action) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dispatchActions = dispatch => ({
|
export const dispatchActions = dispatch => ({
|
||||||
onCredentialsChange: (prop, value) =>
|
|
||||||
dispatch({ type: "onCredentialsChange", payload: { prop, value } }),
|
|
||||||
onNetworkChange: (prop, value) =>
|
onNetworkChange: (prop, value) =>
|
||||||
dispatch({ type: "onNetworkChange", payload: { prop, value } }),
|
dispatch({ type: "onNetworkChange", payload: { prop, value } })
|
||||||
onAuthorizationTokenChange: token =>
|
|
||||||
dispatch({ type: "onAuthorizationTokenChange", payload: { token } })
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { localStorage } from "@flare/js-utils";
|
import { fetch as fetchTuitioData } from "@flare/tuitio-client";
|
||||||
import { storageKeys } from "./identity";
|
|
||||||
|
|
||||||
const { getItem } = localStorage;
|
|
||||||
|
|
||||||
function getHeaders() {
|
function getHeaders() {
|
||||||
const token = getItem(storageKeys.TOKEN);
|
const { token } = fetchTuitioData();
|
||||||
const language = i18next.language;
|
const language = i18next.language;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import { request } from "./axios";
|
|
||||||
import { localStorage } from "@flare/js-utils";
|
|
||||||
|
|
||||||
const { setItem, getItem, removeItem } = localStorage;
|
|
||||||
|
|
||||||
const storageKeys = {
|
|
||||||
TOKEN: "AUTHORIZATION_TOKEN",
|
|
||||||
USER: "USER_NAME"
|
|
||||||
};
|
|
||||||
|
|
||||||
const authenticate = async (userName, password) => {
|
|
||||||
const urlTemplate = process.env.REACT_APP_IDENTITY_AUTHENTICATION_URL;
|
|
||||||
const url = urlTemplate
|
|
||||||
.replace("{username}", userName)
|
|
||||||
.replace("{password}", password);
|
|
||||||
const options = {
|
|
||||||
method: "post"
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await request(url, options);
|
|
||||||
if (response.status === "SUCCESS") {
|
|
||||||
setItem(storageKeys.TOKEN, response.token);
|
|
||||||
setItem(storageKeys.USER, userName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
};
|
|
||||||
|
|
||||||
const invalidate = () => {
|
|
||||||
const token = getItem(storageKeys.TOKEN);
|
|
||||||
if (token) {
|
|
||||||
removeItem(storageKeys.TOKEN);
|
|
||||||
removeItem(storageKeys.USER);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export { storageKeys, authenticate, invalidate };
|
|
Loading…
Reference in New Issue