diff --git a/server.js b/server.js index 3a919da6..c88cf9d3 100644 --- a/server.js +++ b/server.js @@ -145,21 +145,46 @@ async function getTeamOverviewTeams(token, teams) { } app.get('/api/userProfile/:principalName', tokenVerificationMiddleware, async (req, res, next) => { - const token = req.token; - const principalName = req.params.principalName; - const userProfileUrl = `${DAPLA_TEAM_API_URL}/users/${principalName}`; - try { - const [userProfile] = await Promise.all([ - fetchAPIData(token, userProfileUrl, 'Failed to fetch userProfile') + const token = req.token; + const principalName = req.params.principalName; + const userProfileUrl = `${DAPLA_TEAM_API_URL}/users/${principalName}`; + const userManagerUrl = `${DAPLA_TEAM_API_URL}/users/${principalName}/manager`; + const userPhotoUrl = `${DAPLA_TEAM_API_URL}/users/${principalName}/photo`; + + const cacheKey = `userProfile-${principalName}`; + const cachedUserProfile = cache.get(cacheKey); + if (cachedUserProfile) { + return res.json(cachedUserProfile); + } + + const [userProfile, userManager, userPhoto] = await Promise.all([ + fetchAPIData(token, userProfileUrl, 'Failed to fetch userProfile'), + fetchAPIData(token, userManagerUrl, "Failed to fetch user manager"), + fetchPhoto(token, userPhotoUrl, "Failed to fetch user photo") ]) - res.json(userProfile); + const data = { ...userProfile, manager: { ...userManager }, photo: userPhoto }; + cache.put(cacheKey, data, 3600000); + + return res.json(data); } catch (error) { next(error) } }); +async function fetchPhoto(token, url, fallbackErrorMessage) { + const response = await fetch(url, getFetchOptions(token)); + + if (!response.ok) { + throw new Error(fallbackErrorMessage); + } + + const arrayBuffer = await response.arrayBuffer(); + const photoBuffer = Buffer.from(arrayBuffer); + return photoBuffer.toString('base64'); +} + async function getUserProfileTeamData(token, principalName, teams) { const teamPromises = teams._embedded.teams.map(async (team) => { const teamUniformName = team.uniform_name; @@ -250,42 +275,6 @@ async function fetchAPIData(token, url, fallbackErrorMessage) { return response.json(); } - -async function fetchUserProfile(token, principalName) { - const url = `${DAPLA_TEAM_API_URL}/users/${principalName}`; - const response = await fetch(url, getFetchOptions(token)); - - if (!response.ok) { - throw new APIError('Failed to fetch user profile', response.status); - } - - return response.json(); -} - -async function fetchUserManager(token, principalName) { - const url = `${DAPLA_TEAM_API_URL}/users/${principalName}/manager`; - const response = await fetch(url, getFetchOptions(token)); - - if (!response.ok) { - throw new APIError('Failed to fetch user manager', response.status); - } - - return response.json(); -} - -async function fetchPhoto(token, email) { - const url = `${DAPLA_TEAM_API_URL}/users/${email}/photo`; - const response = await fetch(url, getFetchOptions(token)); - - if (!response.ok) { - throw new APIError('Failed to fetch photo', response.status); - } - - const arrayBuffer = await response.arrayBuffer(); - const photoBuffer = Buffer.from(arrayBuffer); - return photoBuffer.toString('base64'); -} - function parseWwwAuthenticate(header) { const parts = header.split(','); const result = {}; diff --git a/src/App.tsx b/src/App.tsx index 56fcabbc..8405f5ff 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,12 +8,15 @@ import Login from './pages/Login/Login'; import TeamOverview from './pages/TeamOverview/TeamOverview'; import UserProfile from './pages/UserProfile/UserProfile'; -import { Routes, Route } from 'react-router-dom'; +import { Routes, Route, useLocation } from 'react-router-dom'; import { jwtRegex } from './utils/regex'; export default function App() { const accessToken = localStorage.getItem('access_token'); - const isLoggedIn = accessToken !== null && jwtRegex.test(accessToken); + const isLoggedIn = ( + useLocation().pathname !== '/login' && + accessToken !== null && + jwtRegex.test(accessToken as string)); return ( <> diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index d6cc6179..3de46d27 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -17,12 +17,11 @@ export default function Avatar() { return; } - const userProfile = JSON.parse(storedUserProfile) as User; if (!userProfile) return; setUserProfileData(userProfile); - setEncodedURI(`/teammedlemmer/${encodeURIComponent(userProfile.principal_name ? userProfile.principal_name.split('@')[0] : userProfile.email)}`); + setEncodedURI(`/teammedlemmer/${encodeURIComponent(userProfile.principal_name ? userProfile.principal_name.split('@')[0] : userProfile.email.split('@')[0])}`); setFallbackInitials(userProfile.first_name[0] + userProfile.last_name[0]); const base64Image = userProfile?.photo; diff --git a/src/pages/UserProfile.tsx b/src/pages/UserProfile.tsx deleted file mode 100644 index 0fa6d447..00000000 --- a/src/pages/UserProfile.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { Dialog } from '@statisticsnorway/ssb-component-library'; -import PageLayout from "../components/PageLayout/PageLayout" -import { useContext, useEffect, useState } from "react" -import { DaplaCtrlContext } from "../provider/DaplaCtrlProvider"; - -import { getUserProfile } from '../api/userProfile'; - -import { User } from "../@types/user"; -import { useParams } from "react-router-dom"; -import { ErrorResponse } from "../@types/error"; -import { Skeleton } from '@mui/material'; - -export default function UserProfile() { - const { setData } = useContext(DaplaCtrlContext); - const [error, setError] = useState(); - const [loading, setLoading] = useState(); - const [userProfileData, setUserProfileData] = useState(); - const { principalName } = useParams(); - - useEffect(() => { - getUserProfile(principalName as string).then(response => { - if ((response as ErrorResponse).error) { - setError(response as ErrorResponse); - } else { - setUserProfileData(response as User); - } - }).finally(() => setLoading(false)) - .catch((error) => { - setError({ error: { message: error.message, code: "500" } }); - }) - }, []); - - // NOTE: This is where we set the data to the context, so that the breadcrumb can access it - useEffect(() => { - if (userProfileData) { - const displayName = userProfileData.display_name.split(', ').reverse().join(' '); - userProfileData.display_name = displayName; - setData({ "displayName": displayName }); - } - }, [userProfileData]); - - function renderErrorAlert() { - return ( - - {error?.error.message} - - ) - } - - function renderSkeletonOnLoad() { - return ( - <> - - - - - ) - } - - function renderContent() { - if (error) return renderErrorAlert(); - if (loading) return renderSkeletonOnLoad(); - - return ( - <> -

{userProfileData?.display_name}

- - ) - } - - return ( - - ) -}