diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 1ac30799..543d7b20 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -14,6 +14,8 @@ import { Box, Container, Heading } from "@radix-ui/themes"; import { color } from "../common/constants"; import { useAtom, useAtomValue } from "jotai"; import { AnimatePresence } from "motion/react"; +import withRetry from "../service/helper/retryHelper"; +import { useNotification } from "../service/helper/notificationHelper"; const Header = styled.div` padding-top: 12px; @@ -46,6 +48,7 @@ const Layout: React.FC = () => { const navigate = useNavigate(); const location = useLocation(); const [backToHomeParam, setBackToHomeParam] = React.useState(null); + const { addNotification } = useNotification(); React.useEffect(() => { if (!isSignInLoading && !isSignIn) { @@ -57,13 +60,16 @@ const Layout: React.FC = () => { return; } - getUserData() + withRetry(getUserData) .then(({ categories, accounts }) => { setCategories(categories); setAccounts(accounts); setIsLoading(false); }) - .catch((err) => log("getUserData failed", err)); + .catch((err) => { + addNotification("Please try restarting the app.", "danger"); + log("getUserData failed", err); + }); }, [isSignIn, isSignInLoading, redirectToSignIn, setAccounts, setCategories]); return isLoading ? ( diff --git a/src/service/helper/retryHelper.ts b/src/service/helper/retryHelper.ts new file mode 100644 index 00000000..4857a00e --- /dev/null +++ b/src/service/helper/retryHelper.ts @@ -0,0 +1,18 @@ +const DEFAULT_RETRY_DELAY = 1000; + +const withRetry = async (fn: () => Promise, retryCount: number = 3): Promise => { + try { + return await fn(); + } catch (err) { + if (retryCount === 0) { + throw err; + } + + const delay = DEFAULT_RETRY_DELAY * 2 ** (retryCount - 1); + + await new Promise((resolve) => setTimeout(resolve, delay)); + return withRetry(fn, retryCount - 1); + } +}; + +export default withRetry;