-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add header component * Add UserProfile endpoint
- Loading branch information
Showing
17 changed files
with
328 additions
and
134 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
|
||
export interface User { | ||
principalName: string | ||
azureAdId: string | ||
displayName: string | ||
firstName: string | ||
lastName: string | ||
email: string | ||
manager?: User | ||
photo?: string | ||
} | ||
|
||
|
||
export const getUserProfile = async (accessToken: string): Promise<User> => { | ||
return fetch('/api/userProfile', { | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'Authorization': `Bearer ${accessToken}` | ||
} | ||
}).then(response => { | ||
if (!response.ok) { | ||
console.error('Request failed with status:', response.status); | ||
throw new Error('Request failed'); | ||
} | ||
return response.json(); | ||
}).then(data => data as User) | ||
.catch(error => { | ||
console.error('Error during fetching userProfile:', error); | ||
throw error; | ||
}); | ||
}; | ||
|
||
export const getUserProfileFallback = (accessToken: string): User => { | ||
const jwt = JSON.parse(atob(accessToken.split('.')[1])); | ||
return { | ||
principalName: jwt.upn, | ||
azureAdId: jwt.oid, // not the real azureAdId, this is actually keycloaks oid | ||
displayName: jwt.name, | ||
firstName: jwt.given_name, | ||
lastName: jwt.family_name, | ||
email: jwt.email | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import styles from './avatar.module.scss'; | ||
import { useNavigate } from 'react-router-dom'; | ||
|
||
interface PageLayoutProps { | ||
fullName: string, | ||
image?: string, | ||
} | ||
|
||
export default function Avatar({ fullName }: PageLayoutProps) { | ||
const navigate = useNavigate(); | ||
const handleClick = () => { | ||
const path_to_go = encodeURI(`/teammedlemmer/${fullName}`); | ||
navigate(path_to_go); | ||
}; | ||
|
||
const userProfile = JSON.parse(localStorage.getItem('userProfile') || '{}'); | ||
const base64Image = userProfile?.photo; | ||
const imageSrc = base64Image ? `data:image/png;base64,${base64Image}` : null; | ||
|
||
return ( | ||
<div className={styles.avatar} onClick={handleClick}> | ||
{imageSrc ? <img src={imageSrc} alt="User" /> : | ||
<div className={styles.initials}>{`${userProfile.firstName[0]}${userProfile.lastName[0]}`}</div>} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
@use '@statisticsnorway/ssb-component-library/src/style/variables' as variables; | ||
|
||
.avatar { | ||
width: 50px; | ||
height: 50px; | ||
margin: 0 1.5rem 0 0; | ||
border: 1px solid variables.$ssb-dark-2; | ||
border-radius: 50%; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
background-color: #fff; | ||
transition: transform 0.3s; | ||
cursor: pointer; | ||
|
||
.initials { | ||
font-size: 1.5rem; | ||
font-weight: 700; | ||
color: variables.$ssb-dark-5; | ||
} | ||
|
||
img { | ||
width: 50px; | ||
height: 50px; | ||
border-radius: 50%; | ||
object-fit: cover; | ||
border: 2px solid #ffffff; | ||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,33 @@ | ||
import styles from './header.module.scss' | ||
|
||
import { Link } from 'react-router-dom'; | ||
import { Link } from '@statisticsnorway/ssb-component-library'; | ||
import Avatar from '../Avatar/Avatar'; | ||
import { useNavigate } from 'react-router-dom'; | ||
import { | ||
jwtRegex | ||
} from '../../utils/regex'; | ||
|
||
export default function Header(props) { | ||
export default function Header(props: { isLoggedIn: boolean }) { | ||
const { isLoggedIn } = props | ||
|
||
const token = localStorage.getItem('access_token'); | ||
let decoded_jwt; | ||
|
||
if (token && jwtRegex.test(token)) | ||
decoded_jwt = JSON.parse(atob(token.split('.')[1])); | ||
|
||
const navigate = useNavigate(); | ||
return ( | ||
<div className={styles.header}> | ||
<span>Dapla ctrl</span> | ||
{isLoggedIn && <Link to="/medlemmer">Medlemmer</Link>} | ||
<h2 className={styles.title} onClick={() => navigate("/")}>Dapla ctrl</h2> | ||
{isLoggedIn && | ||
<div className={styles.navigation}> | ||
<Link href="/teammedlemmer">Teammedlemmer</Link> | ||
{token && <Avatar | ||
fullName={decoded_jwt.name} | ||
/>} | ||
</div> | ||
} | ||
</div> | ||
) | ||
} |
Oops, something went wrong.