Files
ota-admin-portal/src/components/Contexts/UserContext.jsx
John Wu 86eeaab869 Development (#94)
* CEC-371 Car ECU display (#79)

* Merge Development (#53)

* Use responsive iframe control for charts (#49)

* Use responsive iframe control to charts

* Move external Grafana link to Dashboard page

* Remove unused embedded style class

* Add button label

* added delete button to deploy packages

* Fix unit test warning
Remove unused route from test

* Fix styling of button

* minor fixes per pr review

Co-authored-by: jcw-fisker <jwatson@fiskerinc.com>
Co-authored-by: John Cotten Watson <83605808+jcw-fisker@users.noreply.github.com>

* Development Merge (#57)

* CEC-287 Car connection status (#59) (#60)

* Car connection status

* Formatting

* Merge Development (#64)

* Add connection status to vehicles page

* ConnectedIcon control

* Handle Style

* Development (#67)

* preliminary map for vehicles

* weird zoom bug

* passing react tests

* fixing warnings and updating snapshots

* update node environment to 14

* addressing comments by changing variable types and adding styles to home page title

* adding CODEOWNERS file

* fixing token error

* CEC-371 Update car ECUs display (#78)

* Clean up className styles
Update car status page to show update and ECUs

* Add update ecu version button
Show all ECUs on car status page
Only show car ecus for search

Co-authored-by: jcw-fisker <jwatson@fiskerinc.com>
Co-authored-by: John Cotten Watson <83605808+jcw-fisker@users.noreply.github.com>
Co-authored-by: Drew Taylor <69828061+drew-fisker@users.noreply.github.com>

* CEC-394 Car update log (#81)

* CEC-394 Car update status control

* Remove Datadog RUM
Remove package update components
Move control components into Controls folder
Add Car update status page

* Display update status log
Clean up unused update package code

* Remove console.logs

* no vars

* adding timestamp to vehicle popup

* modifying vehicle data query

* removing extraneous code

* removing console log

* Clean up SonarCloud warnings (#83)

* Clean up SonarCloud warnings

* Bogus security warning

* Fix another warning

* Fix unauthorized locations request

* Fix update progress control

* CEC-563 New manifest format (#88)

* Add ManifestCreateContext
Update create manifest page

* Finish UI changes and API integration

* Fixes

* Fix test

* Remove manifest ECU file version and type

* Fixes

* Add manifest ecu file type control

* Fix Sonar warnings

* Fix test

* Update codeowners

* Formatting

* CEC-553 Change file type to string (#90)

* CEC-553 File type uses string enum

* Fix test timeout

* Fix

* Merge development

* Increase timeout

* Clean up (#95)

* Clean up
Mock missing methods

* Smell

Co-authored-by: jcw-fisker <jwatson@fiskerinc.com>
Co-authored-by: John Cotten Watson <83605808+jcw-fisker@users.noreply.github.com>
Co-authored-by: Drew Taylor <69828061+drew-fisker@users.noreply.github.com>
Co-authored-by: Drew Taylor <dtaylor@fiskerinc.com>
2021-10-14 12:23:16 -07:00

171 lines
4.1 KiB
JavaScript

import React, { useContext, useEffect, useState } from "react";
import auth from "../../services/auth";
import getTimerWorker from "../../services/getTimerWorker";
import { parsePayload } from "../../utils/jwt";
import { getGroups } from "../../utils/roles";
const UserContext = React.createContext();
export const UserProvider = ({ children }) => {
const [fetching, setFetching] = useState(false);
const [token, setToken] = useState(null);
const [groups, setGroups] = useState(null);
const [error, setError] = useState(null);
let timer;
useEffect(() => {
try {
if (!localStorage) return;
const t = JSON.parse(localStorage.getItem("token"));
if (!t) return;
if (!t.idToken || !t.idToken.jwtToken) throw new Error("Invalid token");
setToken(t);
} catch (e) {
document.location = signOut();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (!token) return;
verifyToken();
return () => {
if (timer) timer.terminate();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [token]);
const refreshTokens = async () => {
if (!token || !token.refreshToken || !token.refreshToken.token) return null;
return refresh(token.refreshToken.token);
};
const startSessionTimer = () => {
if (!token || !token.idToken || !token.idToken.jwtToken) {
throw new Error("No id token");
}
const payload = parsePayload(token.idToken.jwtToken);
if (!payload || !payload.exp) throw new Error("Bad id token payload");
const duration = 1000 * payload.exp - new Date().getTime();
if (!timer) {
timer = getTimerWorker();
timer.onMessage(async (e) => {
if (e.data === "timeout") {
const t = await refreshTokens();
if (t && !t.error) return;
document.location = signOut();
}
});
}
timer.start(duration);
};
const verifyToken = async () => {
try {
const {
idToken: { jwtToken: idToken },
} = token;
const result = await auth.verify(idToken);
if (!result || !result.valid) {
const t = await refreshTokens();
if (!t || t.error) throw new Error("Unable to refresh token");
}
setGroups(getGroups(idToken));
startSessionTimer();
} catch (e) {
setError(`Verify error. ${e.message}`);
document.location = signOut();
}
};
const signIn = async (code) => {
let result = null;
try {
if (!code) return;
setFetching(true);
setError(null);
result = await auth.signIn(code);
if (result.message) {
throw new Error(result.message);
}
signedIn(result);
} catch (err) {
setError(`Sign in error. ${err.message}`);
} finally {
setFetching(false);
}
return result;
};
const signOut = () => {
setGroups(null);
setToken(null);
if (localStorage) {
localStorage.removeItem("token");
}
return getLogoutURL();
};
const signedIn = (value) => {
setToken(value);
if (!localStorage || !value || !value.idToken) return;
localStorage.setItem("token", JSON.stringify(value));
};
const refresh = async (value) => {
let result = null;
try {
if (!value) {
throw new Error("Token required");
}
setFetching(true);
setError(null);
result = await auth.refresh(value);
if (result.message) {
throw new Error(result.message);
}
signedIn(result);
} catch (err) {
setError(`Refresh error. ${err.message}`);
} finally {
setFetching(false);
}
return result;
};
const getAuthorizeURL = () => auth.ssoAuthorize();
const getLogoutURL = () => auth.ssoLogout();
return (
<UserContext.Provider
value={{
error,
fetching,
groups,
token,
getAuthorizeURL,
getLogoutURL,
setError,
signIn,
signOut,
refresh,
}}
>
{children}
</UserContext.Provider>
);
};
export const useUserContext = () => useContext(UserContext);