@flare/tuitio-react-client

master
Tudor Stanciu 2023-02-14 01:36:06 +02:00
parent e1c4b2ca04
commit 7f6056baf4
14 changed files with 409 additions and 506 deletions

8
.env
View File

@ -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_NETWORK_RESURRECTOR_API_URL=http://localhost:5064
#REACT_APP_NETWORK_RESURRECTOR_API_URL=https://lab.code-rove.com/network-resurrector-api
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=https://lab.code-rove.com/network-resurrector-api
#600000 milliseconds = 10 minutes
REACT_APP_MACHINE_PING_INTERVAL=600000

View File

@ -1,5 +1,5 @@
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
#900000 milliseconds = 15 minutes

694
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
},
"private": true,
"dependencies": {
"@flare/js-utils": "^1.0.2",
"@flare/tuitio-react-client": "^1.0.0",
"@material-ui/core": "^4.11.2",
"@material-ui/icons": "^4.11.2",
"@testing-library/jest-dom": "^5.11.6",

View File

@ -2,7 +2,7 @@ import React from "react";
import ApplicationStepper from "./stepper/ApplicationStepper";
import Switcher from "./Switcher";
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";
const useStyles = makeStyles(() => ({
@ -16,7 +16,7 @@ const useStyles = makeStyles(() => ({
const Main = () => {
const classes = useStyles();
const { validateToken } = useAuthorizationToken();
const { validate: validateToken } = useTuitioToken();
const tokenIsValid = validateToken();
return (

View File

@ -1,4 +1,4 @@
import React, { useState, useCallback } from "react";
import React, { useState, useMemo } from "react";
import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/core/styles";
import {
@ -18,35 +18,29 @@ import LoginComponent from "./LoginComponent";
import { useTranslation } from "react-i18next";
import { useToast } from "../../../hooks";
import styles from "../styles";
import { useTuitioUser } from "@flare/tuitio-react-client";
const useStyles = makeStyles(styles);
const LoggedInComponent = ({
credentials,
token,
onChange,
onLogin,
onLogout
}) => {
const LoggedInComponent = ({ credentials, onChange, onLogin, onLogout }) => {
const classes = useStyles();
const { t } = useTranslation();
const [expanded, setExpanded] = useState(false);
const { info } = useToast();
const { lastLoginDate, userName } = useTuitioUser();
const handleExpandLogin = () => {
setExpanded(!expanded);
};
const getTokenValidFrom = useCallback(() => {
const tokenValidFrom = token?.validFrom;
if (tokenValidFrom) {
const valueForDisplay = t("LONG_DATE", { date: tokenValidFrom });
const loginDate = useMemo(() => {
if (lastLoginDate) {
const valueForDisplay = t("LONG_DATE", { date: lastLoginDate });
return valueForDisplay;
}
return "N/A";
}, [token, t]);
}, [lastLoginDate, t]);
const handleLogin = async () => {
const result = await onLogin();
@ -65,15 +59,11 @@ const LoggedInComponent = ({
<AccountBox />
</Avatar>
}
title={
<strong>
{t("Login.Hello", { username: credentials.userName })}
</strong>
}
title={<strong>{t("Login.Hello", { username: userName })}</strong>}
subheader={
<Tooltip title={t("Login.AuthenticationDate")}>
<Typography variant="caption" display="block">
{getTokenValidFrom()}
{loginDate}
</Typography>
</Tooltip>
}
@ -117,7 +107,6 @@ const LoggedInComponent = ({
LoggedInComponent.propTypes = {
credentials: PropTypes.object.isRequired,
token: PropTypes.object,
onChange: PropTypes.func.isRequired,
onLogin: PropTypes.func.isRequired,
onLogout: PropTypes.func.isRequired

View File

@ -1,59 +1,49 @@
import React, { useContext } from "react";
import React, { useState } from "react";
import LoginCard from "./LoginCard";
import { authenticate, invalidate } from "../../../utils/identity";
import {
ApplicationStateContext,
ApplicationDispatchContext
} from "../../../state/ApplicationContexts";
import { useToast, useAuthorizationToken } from "../../../hooks";
import { useToast } from "../../../hooks";
import { useTranslation } from "react-i18next";
import LoggedInComponent from "./LoggedInComponent";
import { useTuitioClient, useTuitioToken } from "@flare/tuitio-react-client";
const LoginContainer = () => {
const state = useContext(ApplicationStateContext);
const dispatchActions = useContext(ApplicationDispatchContext);
const [credentials, setCredentials] = useState({
userName: "",
password: ""
});
const { error } = useToast();
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 => {
dispatchActions.onCredentialsChange(prop, event.target.value);
setCredentials(prev => ({ ...prev, [prop]: event.target.value }));
};
const handleLogin = async () => {
const { userName, password } = state.credentials;
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 handleLogin = () => {
const { userName, password } = credentials;
return login(userName, password);
};
const handleLogout = () => {
invalidate();
invalidateToken();
logout();
};
return (
<>
{tokenIsValid ? (
<LoggedInComponent
credentials={state.credentials}
token={getToken()}
credentials={credentials}
onChange={handleChange}
onLogin={handleLogin}
onLogout={handleLogout}
/>
) : (
<LoginCard
credentials={state.credentials}
credentials={credentials}
onChange={handleChange}
onLogin={handleLogin}
/>

View File

@ -1,2 +1 @@
export { useToast } from "./useToast";
export { useAuthorizationToken } from "./useAuthorizationToken";

View File

@ -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 };
};

View File

@ -4,11 +4,14 @@ import "./index.css";
import "./utils/i18n";
import App from "./components/App";
import { BrowserRouter as Router } from "react-router-dom";
import { TuitioProvider } from "@flare/tuitio-react-client";
ReactDOM.render(
<Router basename={process.env.PUBLIC_URL || ""}>
<Suspense fallback={<div>Loading...</div>}>
<App />
<TuitioProvider tuitioUrl={process.env.REACT_APP_TUITIO_URL}>
<App />
</TuitioProvider>
</Suspense>
</Router>,
document.getElementById("root")

View File

@ -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 = {
credentials: {
userName: userName || "",
password: ""
},
security: {
authorization: {
token
}
},
network: {
machines: Object.assign([], { loaded: false }),
test: ""

View File

@ -1,15 +1,5 @@
export function reducer(state, action) {
switch (action.type) {
case "onCredentialsChange": {
const { prop, value } = action.payload;
return {
...state,
credentials: {
...state.credentials,
[prop]: value
}
};
}
case "onNetworkChange": {
const { prop, value } = action.payload;
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: {
return state;
}
@ -40,10 +17,6 @@ export function reducer(state, action) {
}
export const dispatchActions = dispatch => ({
onCredentialsChange: (prop, value) =>
dispatch({ type: "onCredentialsChange", payload: { prop, value } }),
onNetworkChange: (prop, value) =>
dispatch({ type: "onNetworkChange", payload: { prop, value } }),
onAuthorizationTokenChange: token =>
dispatch({ type: "onAuthorizationTokenChange", payload: { token } })
dispatch({ type: "onNetworkChange", payload: { prop, value } })
});

View File

@ -1,12 +1,9 @@
import axios from "axios";
import i18next from "i18next";
import { localStorage } from "@flare/js-utils";
import { storageKeys } from "./identity";
const { getItem } = localStorage;
import { fetch as fetchTuitioData } from "@flare/tuitio-client";
function getHeaders() {
const token = getItem(storageKeys.TOKEN);
const { token } = fetchTuitioData();
const language = i18next.language;
return {

View File

@ -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 };