diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx index 548ee04..104a90c 100644 --- a/src/components/ProtectedRoute.tsx +++ b/src/components/ProtectedRoute.tsx @@ -2,36 +2,44 @@ import { useEffect, useState } from 'react' import { useNavigate, Outlet } from 'react-router-dom' import { getUserProfile } from '../services/userProfile' import { fetchUserInformationFromAuthToken } from '../utils/services' -import { Effect } from 'effect' +import { Cause, Effect, Option as O } from 'effect' import { customLogger } from '../utils/logger.ts' +import { ApiError } from '../utils/services.ts' + +import { User } from '../services/userProfile.ts' const ProtectedRoute = () => { const [isAuthenticated, setIsAuthenticated] = useState(false) const navigate = useNavigate() const from = location.pathname - useEffect(() => { - const setData = async () => { - try { - if (localStorage.getItem('userProfile') !== null) { - setIsAuthenticated(true) - return - } + const fetchUserProfile = (): Effect.Effect => + Effect.gen(function* () { + const userProfileData = yield* Effect.promise(fetchUserInformationFromAuthToken) + const userProfile = yield* Effect.tryPromise(() => getUserProfile(userProfileData.email)).pipe( + Effect.flatMap((x) => (x instanceof ApiError ? Effect.fail(x) : Effect.succeed(x))), + Effect.map(JSON.stringify) + ) + yield* Effect.logInfo(`UserProfile set in localStorage: ${userProfile}`) + yield* Effect.sync(() => localStorage.setItem('userProfile', userProfile)) + yield* Effect.sync(() => setIsAuthenticated(true)) + }).pipe(Effect.provide(customLogger)) - const userProfileData = await fetchUserInformationFromAuthToken() - const userProfile = JSON.stringify(await getUserProfile(userProfileData.email)) - Effect.logInfo(`UserProfile set in localStorage: ${userProfile}`).pipe( - Effect.provide(customLogger), - Effect.runSync - ) - localStorage.setItem('userProfile', userProfile) - setIsAuthenticated(true) - } catch (error) { - console.error('Error occurred when updating userProfile data') - console.error(error) - } - } - setData() + useEffect(() => { + const cachedUserProfile: O.Option = O.fromNullable(localStorage.getItem('userProfile')).pipe( + O.flatMap(O.liftThrowable(JSON.parse)) + ) + O.match(cachedUserProfile, { + onNone: () => fetchUserProfile(), + onSome: (userProfile) => + // invalidate cached user profile if 'job_title' field is missing + userProfile.job_title + ? Effect.sync(() => setIsAuthenticated(true)) + : Effect.zipRight( + Effect.logInfo("'job_title' field missing, invalidating UserProfile cache"), + fetchUserProfile() + ).pipe(Effect.provide(customLogger)), + }).pipe(Effect.runPromise) }, [from, navigate]) return isAuthenticated ? : null