Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/user avatar #86

Merged
merged 8 commits into from
Sep 8, 2023
8 changes: 4 additions & 4 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"dependencies": {
"@aws-amplify/ui-react": "^5.0.0",
"@bcgov-nr/nr-fsa-theme": "^1.0.7",
"@bcgov-nr/nr-fsa-theme": "^1.0.10",
"@carbon/react": "^1.27.0",
"@testing-library/jest-dom": "^6.1.2",
"@testing-library/react": "^14.0.0",
Expand Down
23 changes: 14 additions & 9 deletions frontend/src/actions/userAction.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { USER_DETAILS_REQUEST, USER_DETAILS_SUCCESS, USER_DETAILS_FAIL } from '../constants/userConstants'
import { isCurrentAuthUser } from '../services/AuthService'

const FAM_LOGIN_USER = 'famLoginUser';
export const getUserDetails = () => async (dispatch: any) => {
try {
dispatch({
type: USER_DETAILS_REQUEST
})
// readt the localStorage Here
const data = await isCurrentAuthUser()
type: USER_DETAILS_REQUEST,
});
//first call the isCurrent and only after that extract the JSON
const data = await isCurrentAuthUser();

const userJSON = localStorage.getItem(FAM_LOGIN_USER); // Retrieve the JSON string from local storage
const user = userJSON ? JSON.parse(userJSON) : null; // Parse the JSON string to a JavaScript object

dispatch({
type: USER_DETAILS_SUCCESS,
payload: { TestUser: 'Jazz as always', isLoggedIn: data }
})
payload: { ...user, isLoggedIn: data},
});
} catch (error) {
dispatch({
type: USER_DETAILS_FAIL,
payload: { error }
})
payload: { error: error },
});
}
}
};
10 changes: 9 additions & 1 deletion frontend/src/components/AvatarImage/AvatarImage.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
.profile-image {
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
background-color: #c7d4e7;
color: #072251;
font-size: 1.4rem;
}

.small {
Expand All @@ -10,4 +17,5 @@
.large {
width: 4rem;
height: 4rem;
}
}

24 changes: 19 additions & 5 deletions frontend/src/components/AvatarImage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import React from 'react';

import emptyUser from '../../assets/img/emptyUser.jpg';
import './AvatarImage.scss';

type Size = 'small' | 'large';

interface AvatarImageProps {
userName: string;
source?: string;
size: Size;
}

const AvatarImage = ({ userName, source, size }: AvatarImageProps) => (
<img src={source || emptyUser} alt={`${userName}`} className={`profile-image ${size}`} />
);
const getInitials = (userName: string) => {
const nameParts = userName.split(' ');
DerekRoberts marked this conversation as resolved.
Show resolved Hide resolved
if (nameParts.length >= 2) {
return nameParts[0][0] + nameParts[1][0];
} else if (nameParts.length === 1) {
return nameParts[0][0];
}
return '';
};

const AvatarImage = ({ userName, size }: AvatarImageProps) => {
const initials = getInitials(userName);

return (
<div className={`profile-image ${size}`}>
<div className="initials">{initials}</div>
</div>
);
};

export default AvatarImage;
16 changes: 9 additions & 7 deletions frontend/src/components/MyProfile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useCallback, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

import { useSelector } from 'react-redux';
import {
SideNavLink
} from '@carbon/react';
Expand All @@ -16,8 +16,9 @@ import { logout } from '../../services/AuthService';

const MyProfile = () => {
const { theme, setTheme } = useThemePreference();
const userData = {firstName:'Jazz', lastName:"Grewal", idirUsername:"Jasgrewal", email:"[email protected]"};

const userData = {firstName:'Catherine', lastName:"Meng", idirUsername:"Jasgrewal", email:"[email protected]"};
const userDetails = useSelector((state:any) => state.userDetails)

const [goToURL, setGoToURL] = useState<string>('');
const [goTo, setGoTo] = useState<boolean>(false);

Expand Down Expand Up @@ -45,12 +46,13 @@ const MyProfile = () => {
<>
<div className="user-info-section">
<div className="user-image">
<AvatarImage userName={`${userData.firstName} ${userData.lastName}`} size="large" />
<AvatarImage userName={`${userDetails.user.firstName} ${userDetails.user.lastName}`} size="large" />
DerekRoberts marked this conversation as resolved.
Show resolved Hide resolved
</div>
<div className="user-data">
<p className="user-name">{`${userData.firstName} ${userData.lastName}`}</p>
<p>{`IDIR: ${userData.idirUsername}`}</p>
<p>{userData.email}</p>
<p className="user-name">{`${userDetails.user.firstName} ${userDetails.user.lastName}`}</p>
<p>{`IDIR: ${userDetails.user.userName}`}</p>
<p>{`Email:${userDetails.user.email}`}</p>

</div>
</div>
<hr className="divisory" />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const root = createRoot(container);

root.render(
<React.StrictMode>
<ClassPrefix prefix='bx'>
<ClassPrefix prefix='bcgov'>
<ThemePreference>
<Provider store={store}>
<App />
Expand Down
43 changes: 27 additions & 16 deletions frontend/src/services/AuthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,11 @@ export const handlePostLogin = async () => {
async function refreshToken (): Promise<FamLoginUser | undefined> {
try {
console.log('Refreshing Token...')
const currentAuthToken: CognitoUserSession =
await Auth.currentSession()
console.log('currentAuthToken: ', currentAuthToken)
const currentAuthToken: CognitoUserSession = await Auth.currentSession()
const famLoginUser = parseToken(currentAuthToken);
await storeFamUser(famLoginUser);
return famLoginUser;

const famLoginUser = parseToken(currentAuthToken)
storeFamUser(famLoginUser)
return famLoginUser
} catch (error) {
console.error(
'Problem refreshing token or token is invalidated:',
Expand All @@ -86,20 +84,33 @@ async function refreshToken (): Promise<FamLoginUser | undefined> {
* Note, current user data return for 'userData.username' is matched to "cognito:username" on Cognito.
* Which isn't what we really want to display. The display username is "custom:idp_username" from token.
*/
function parseToken (authToken: CognitoUserSession): FamLoginUser {
const decodedIdToken = authToken.getIdToken().decodePayload()
const decodedAccessToken = authToken.getAccessToken().decodePayload()

function parseToken(authToken: CognitoUserSession): FamLoginUser {
const decodedIdToken = authToken.getIdToken().decodePayload();
const decodedAccessToken = authToken.getAccessToken().decodePayload();

// Extract the first name and last name from the displayName and remove unwanted part
const displayName = decodedIdToken['custom:idp_display_name'];
const [lastName, firstName] = displayName.split(', ');
const sanitizedFirstName = firstName.split(' ')[0].trim(); // Remove unwanted part
const famLoginUser = {
username: decodedIdToken['custom:idp_username'],
idpProvider: decodedIdToken.identities.providerName,
userName: decodedIdToken['custom:idp_username'],
displayName,
email: decodedIdToken['email'],
idpProvider: decodedIdToken['identities']['providerName'],
roles: decodedAccessToken['cognito:groups'],
authToken
}
return famLoginUser
authToken: authToken,
firstName: sanitizedFirstName,
lastName, // Add lastName field
};

return famLoginUser;
}

function removeFamUser () {
storeFamUser(undefined)

function removeFamUser() {
storeFamUser(undefined);

// clean up local storage for selected application
}

Expand Down