🐛 fix(authContext.tsx): initialize accessToken and refreshToken with values from cookies to maintain user session

✨ feat(authContext.tsx): add support for process.env.PORT environment variable to be able to run app on a configurable port
🐛 fix(tabsContext.tsx): import missing AuthContext and use getAuthentication function to conditionally fetch data
🐛 fix(typesContext.tsx): import missing AuthContext and use getAuthentication function to conditionally fetch data
🐛 fix(api.tsx): add check to not refresh token if refreshToken is "auto"
This commit is contained in:
Cristhian Zanforlin Lousa 2023-08-25 19:08:38 -03:00
commit 89d69af7f8
4 changed files with 61 additions and 58 deletions

View file

@ -24,13 +24,13 @@ const initialValue: AuthContextType = {
export const AuthContext = createContext<AuthContextType>(initialValue); export const AuthContext = createContext<AuthContextType>(initialValue);
export function AuthProvider({ children }): React.ReactElement { export function AuthProvider({ children }): React.ReactElement {
const [accessToken, setAccessToken] = useState<string | null>(null); const cookies = new Cookies();
const [refreshToken, setRefreshToken] = useState<string | null>(null); const [accessToken, setAccessToken] = useState<string | null>(cookies.get("access_token"));
const [refreshToken, setRefreshToken] = useState<string | null>(cookies.get("refresh_token"));
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false); const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const [isAdmin, setIsAdmin] = useState<boolean>(false); const [isAdmin, setIsAdmin] = useState<boolean>(false);
const [userData, setUserData] = useState<Users | null>(null); const [userData, setUserData] = useState<Users | null>(null);
const [autoLogin, setAutoLogin] = useState<boolean>(false); const [autoLogin, setAutoLogin] = useState<boolean>(false);
const cookies = new Cookies();
useEffect(() => { useEffect(() => {
const storedAccessToken = cookies.get("access_token"); const storedAccessToken = cookies.get("access_token");

View file

@ -1,3 +1,4 @@
import { AxiosError } from "axios";
import _ from "lodash"; import _ from "lodash";
import { import {
ReactNode, ReactNode,
@ -21,7 +22,7 @@ import {
import { APIClassType, APITemplateType } from "../types/api"; import { APIClassType, APITemplateType } from "../types/api";
import { tweakType } from "../types/components"; import { tweakType } from "../types/components";
import { FlowType, NodeDataType, NodeType } from "../types/flow"; import { FlowType, NodeDataType, NodeType } from "../types/flow";
import { TabsContextType, TabsState, errorsVarType } from "../types/tabs"; import { TabsContextType, TabsState } from "../types/tabs";
import { import {
addVersionToDuplicates, addVersionToDuplicates,
updateIds, updateIds,
@ -29,8 +30,8 @@ import {
} from "../utils/reactflowUtils"; } from "../utils/reactflowUtils";
import { getRandomDescription, getRandomName } from "../utils/utils"; import { getRandomDescription, getRandomName } from "../utils/utils";
import { alertContext } from "./alertContext"; import { alertContext } from "./alertContext";
import { AuthContext } from "./authContext";
import { typesContext } from "./typesContext"; import { typesContext } from "./typesContext";
import { AxiosError } from "axios";
const uid = new ShortUniqueId({ length: 5 }); const uid = new ShortUniqueId({ length: 5 });
@ -69,7 +70,9 @@ export const TabsContext = createContext<TabsContextType>(
); );
export function TabsProvider({ children }: { children: ReactNode }) { export function TabsProvider({ children }: { children: ReactNode }) {
const { setErrorData, setNoticeData, setSuccessData } = useContext(alertContext); const { setErrorData, setNoticeData, setSuccessData } =
useContext(alertContext);
const { getAuthentication } = useContext(AuthContext);
const [tabId, setTabId] = useState(""); const [tabId, setTabId] = useState("");
@ -113,7 +116,6 @@ export function TabsProvider({ children }: { children: ReactNode }) {
} }
function refreshFlows() { function refreshFlows() {
setTimeout(() => {
getTabsDataFromDB().then((DbData) => { getTabsDataFromDB().then((DbData) => {
if (DbData && Object.keys(templates).length > 0) { if (DbData && Object.keys(templates).length > 0) {
try { try {
@ -124,20 +126,22 @@ export function TabsProvider({ children }: { children: ReactNode }) {
} }
} }
}); });
}, 2000);
} }
useEffect(() => { useEffect(() => {
// get data from db if (getAuthentication() === true) {
//get tabs locally saved // get data from db
// let tabsData = getLocalStorageTabsData(); //get tabs locally saved
refreshFlows(); // let tabsData = getLocalStorageTabsData();
}, [templates]); refreshFlows();
}
}, [templates, getAuthentication()]);
function getTabsDataFromDB() { function getTabsDataFromDB() {
//get tabs from db //get tabs from db
return readFlowsFromDatabase(); return readFlowsFromDatabase();
} }
function processDBData(DbData: FlowType[]) { function processDBData(DbData: FlowType[]) {
DbData.forEach((flow: FlowType) => { DbData.forEach((flow: FlowType) => {
try { try {
@ -605,7 +609,10 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}); });
} }
} catch (err) { } catch (err) {
setErrorData({title: "Error while saving changes",list:[(err as AxiosError).message]}); setErrorData({
title: "Error while saving changes",
list: [(err as AxiosError).message],
});
} }
} }

View file

@ -10,6 +10,7 @@ import { getAll, getHealth } from "../controllers/API";
import { APIKindType } from "../types/api"; import { APIKindType } from "../types/api";
import { typesContextType } from "../types/typesContext"; import { typesContextType } from "../types/typesContext";
import { alertContext } from "./alertContext"; import { alertContext } from "./alertContext";
import { AuthContext } from "./authContext";
//context to share types adn functions from nodes to flow //context to share types adn functions from nodes to flow
@ -37,60 +38,55 @@ export function TypesProvider({ children }: { children: ReactNode }) {
const [data, setData] = useState({}); const [data, setData] = useState({});
const [fetchError, setFetchError] = useState(false); const [fetchError, setFetchError] = useState(false);
const { setLoading } = useContext(alertContext); const { setLoading } = useContext(alertContext);
const { getAuthentication } = useContext(AuthContext);
useEffect(() => { useEffect(() => {
if (getAuthentication() === true) {
getTypes();
}
}, [getAuthentication()]);
setTimeout(() => { async function getTypes(): Promise<void> {
// We will keep a flag to handle the case where the component is unmounted before the API call resolves. // We will keep a flag to handle the case where the component is unmounted before the API call resolves.
let isMounted = true; let isMounted = true;
try {
async function getTypes(): Promise<void> { const result = await getAll();
try { // Make sure to only update the state if the component is still mounted.
const result = await getAll(); if (isMounted && result?.status === 200) {
// Make sure to only update the state if the component is still mounted. setLoading(false);
if (isMounted && result?.status === 200) { setData(result.data);
setLoading(false); setTemplates(
setData(result.data); Object.keys(result.data).reduce((acc, curr) => {
setTemplates( Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => {
Object.keys(result.data).reduce((acc, curr) => { acc[c] = result.data[curr][c];
});
return acc;
}, {})
);
// Set the types by reducing over the keys of the result data and updating the accumulator.
setTypes(
// Reverse the keys so the tool world does not overlap
Object.keys(result.data)
.reverse()
.reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => {
acc[c] = result.data[curr][c]; acc[c] = curr;
// Add the base classes to the accumulator as well.
result.data[curr][c].base_classes?.forEach((b) => {
acc[b] = curr;
});
}); });
return acc; return acc;
}, {}) }, {})
); );
// Set the types by reducing over the keys of the result data and updating the accumulator.
setTypes(
// Reverse the keys so the tool world does not overlap
Object.keys(result.data)
.reverse()
.reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach(
(c: keyof APIKindType) => {
acc[c] = curr;
// Add the base classes to the accumulator as well.
result.data[curr][c].base_classes?.forEach((b) => {
acc[b] = curr;
});
}
);
return acc;
}, {})
);
}
} catch (error) {
console.error("An error has occurred while fetching types.");
await getHealth().catch((e) => {
setFetchError(true);
});
} }
} catch (error) {
console.error("An error has occurred while fetching types.");
await getHealth().catch((e) => {
setFetchError(true);
});
} }
}
getTypes();
}, 2000);
}, []);
function deleteNode(idx: string) { function deleteNode(idx: string) {
reactFlowInstance!.setNodes( reactFlowInstance!.setNodes(

View file

@ -24,7 +24,7 @@ function ApiInterceptor() {
async (error: AxiosError) => { async (error: AxiosError) => {
if (error.response?.status === 401) { if (error.response?.status === 401) {
const refreshToken = cookies.get("refresh_token"); const refreshToken = cookies.get("refresh_token");
if (refreshToken) { if (refreshToken && refreshToken !== "auto") {
authenticationErrorCount = authenticationErrorCount + 1; authenticationErrorCount = authenticationErrorCount + 1;
if (authenticationErrorCount > 3) { if (authenticationErrorCount > 3) {
authenticationErrorCount = 0; authenticationErrorCount = 0;