From 59b51aee75ce40c8822c7bb86bb1a72416e4aa29 Mon Sep 17 00:00:00 2001
From: John Sparger <john.sparger@ess.eu>
Date: Thu, 9 Jun 2022 20:35:08 +0200
Subject: [PATCH] Fix loading in UserProvider, don't render UserProvider
 children before user initialized, be more careful with when loading flag is
 set in useAsync and useQueuedResponse, start with loading=true when using
 call=true in useAsync

---
 src/api/SwaggerApi.js | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/src/api/SwaggerApi.js b/src/api/SwaggerApi.js
index 11b626a6..66cede9d 100644
--- a/src/api/SwaggerApi.js
+++ b/src/api/SwaggerApi.js
@@ -43,6 +43,7 @@ export function UserProvider({ children }) {
   const [loginError, setLoginError] = useState();
   const [loginResponse, loginFcn, /*reset*/, loginLoading] = useLogin(onLoginError);
   const [logoutFcn, logoutLoading] = useLogout();
+  const [initialized, setInitialized] = useState(false);
 
   const resetLoginError = useCallback(() => setLoginError(null), [setLoginError]);
 
@@ -68,13 +69,19 @@ export function UserProvider({ children }) {
 
   const [value, setValue] = useState(createValue());
 
+  useEffect(() => {
+    if (!loading) {
+      setInitialized(true);
+    }
+  }, [loading, ])
+
   useEffect(() => {
     if (!loading) {
      setValue(createValue())
     }
   }, [loading, setValue, createValue])
 
-  return (
+  return ( initialized &&
     <userContext.Provider value={value}>
       {children}
     </userContext.Provider>
@@ -120,11 +127,11 @@ export function useAPIErrorHandler(onError) {
   return useCallback(errorHandler, [logout]);
 }
 
-export function useQueuedResponse({ init = null, onError = null }) {
+export function useQueuedResponse({ init = null, onError = null, initLoading = false}) {
   const queueRef = useRef([]);
   const busyRef = useRef(false);
   const [response, setResponse] = useState(init);
-  const [loading, setLoading] = useState(false);
+  const [loading, setLoading] = useState(initLoading);
   const errorHandler = useAPIErrorHandler(onError);
   const MAX_QUEUE_LENGTH = 10;
 
@@ -144,16 +151,17 @@ export function useQueuedResponse({ init = null, onError = null }) {
       }
 
       queueRef.current = []
-      setLoading(false);
       busyRef.current = false;
 
       const { status, value, reason } = responses.pop();
       if (status === "rejected") {
+        setLoading(false);
         errorHandler(reason);
         return;
       }
 
       setResponse(value);
+      setLoading(false);
     }, [errorHandler])
 
   const enqueue = useCallback((promise) => {
@@ -168,7 +176,7 @@ export function useQueuedResponse({ init = null, onError = null }) {
 }
 
 export function useAsync({ fcn, call = true, init = null, onError = null }) {
-  const { response, setResponse, loading, enqueue } = useQueuedResponse({ init, onError });
+  const { response, setResponse, loading, enqueue } = useQueuedResponse({ init, onError, call });
 
   const reset = useCallback(() => setResponse(init), [setResponse, init]);
 
@@ -571,29 +579,33 @@ export function useUser() {
   const [userInfo, getUserInfo, resetUserInfo, userInfoLoading] = useUserInfo(onError);
   const [userRoles, getUserRoles, resetUserRoles, userRolesLoading] = useUserRoles(onError);
   const [user, setUser] = useState();
+  const [loading, setLoading] = useState(true);
+
+  const dataLoading = userInfoLoading || userRolesLoading;
 
   useEffect(() => {
     // userInfo and user Roles should:
     // - both be defined when logged in
     // - both be undefined when logged out
     const loginStateConsistent = Boolean(userInfo) === Boolean(userRoles);
-    if (loginStateConsistent) {
+    if (loginStateConsistent && !dataLoading) {
       setUser({ userInfo, userRoles });
+      setLoading(false);
     }
-  }, [userInfo, userRoles])
+  }, [dataLoading, userInfo, userRoles])
 
   const getUser = useCallback(() => {
+    setLoading(true);
     getUserInfo();
     getUserRoles();
   }, [getUserInfo, getUserRoles]);
 
   const resetUser = useCallback(() => {
+    setLoading(true);
     resetUserInfo();
     resetUserRoles();
   }, [resetUserInfo, resetUserRoles]);
 
-  const loading = userInfoLoading || userRolesLoading;
-
   return [user, getUser, resetUser, loading]
 }
 
-- 
GitLab