Skip to content

Commit

Permalink
Update Account Page (#131)
Browse files Browse the repository at this point in the history
* current updates

* password checking + using userContext

* refined form, update userData, err checking, fix blocking

* fix eslint errors

* fix monitorlog path

* include both vers for ProtectedRoutes
  • Loading branch information
PhillipChn authored May 26, 2022
1 parent 930da02 commit d4a5aa9
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 185 deletions.
7 changes: 3 additions & 4 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,9 @@ function App() {
exact
path="/account"
element={
<AccountPage
changesMade={accMadeChanges}
setChangesMade={setAccMadeChanges}
/>
<ProtectedRoute redirectPath="/logout" roles={[ADMIN_ROLE, VOLUNTEER_ROLE]}>
<AccountPage setChangesMade={setAccMadeChanges} />
</ProtectedRoute>
}
/>
<Route
Expand Down
15 changes: 12 additions & 3 deletions src/common/ProtectedRoute.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable react/prop-types */
/* eslint-disable react/forbid-prop-types */
import React, { useState, useEffect } from 'react';
import { Navigate } from 'react-router-dom';
import { PropTypes, instanceOf } from 'prop-types';
Expand Down Expand Up @@ -36,7 +38,7 @@ const userIsAuthenticated = async (roles, cookies) => {
* @param {Cookies} cookies The user's current cookies
* @returns The relevant path to redirect the user to depending on authentication state.
*/
const ProtectedRoute = ({ Component, redirectPath, roles, cookies }) => {
const ProtectedRoute = ({ Component, children, redirectPath, roles, cookies }) => {
const [isLoading, setIsLoading] = useState(true);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const { setUserData } = useUserContext();
Expand All @@ -53,13 +55,20 @@ const ProtectedRoute = ({ Component, redirectPath, roles, cookies }) => {
return <h1>LOADING...</h1>;
}
if (isAuthenticated) {
return <Component />;
const childCount = React.Children.count(children);
return childCount ? children : <Component />;
}
return <Navigate to={redirectPath} />;
};

ProtectedRoute.defaultProps = {
Component: PropTypes.elementType,
children: PropTypes.node,
};

ProtectedRoute.propTypes = {
Component: PropTypes.elementType.isRequired,
Component: PropTypes.elementType,
children: PropTypes.node,
redirectPath: PropTypes.string.isRequired,
roles: PropTypes.arrayOf(PropTypes.string).isRequired,
cookies: instanceOf(Cookies).isRequired,
Expand Down
34 changes: 34 additions & 0 deletions src/common/auth_utils.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
sendPasswordResetEmail,
confirmPasswordReset,
applyActionCode,
reauthenticateWithCredential,
EmailAuthProvider,
updatePassword,
} from 'firebase/auth';

import { useNavigate } from 'react-router-dom';
Expand Down Expand Up @@ -299,6 +302,36 @@ const addAuthInterceptor = axiosInstance => {
);
};

/**
* Cross checks old password by reauthenticating with firebase and applying changes afterwards
* @param {string} newPassword Password that the user wants to change to
* @param {string} oldPassword Previous password used to check with firebase
*/
const updateUserPassword = async (newPassword, oldPassword) => {
const user = auth.currentUser;

const cred = EmailAuthProvider.credential(user.email, oldPassword);

try {
await reauthenticateWithCredential(user, cred);
// User entered correct credentials
// Update password
await updatePassword(auth.currentUser, newPassword);
console.log('password updated succesfully');
return 'success';
} catch (e) {
console.log(e.code, e.message);
// Could be incorrect credentials
if (e.code === 'auth/wrong-password') {
return 'password';
}
if (e.code === 'auth/weak-password') {
return 'weak';
}
return 'error';
}
};

addAuthInterceptor(OCHBackend);

// -------- ADMIN INVITE ROUTES START HERE ------------------------------------------
Expand Down Expand Up @@ -343,4 +376,5 @@ export {
confirmNewPassword,
confirmVerifyEmail,
initiateInviteProcess,
updateUserPassword,
};
8 changes: 6 additions & 2 deletions src/components/Navbar/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,12 @@ const Navbar = ({ isAdmin, onAdminPortal, setOnAdminPortal, changesMade }) => {
{/* TO DO: if user is not signed in, only logo */}
<HStack h="inherit" spacing={6} pr={4}>
{isAdmin && onAdminPortal
? admin.map(a => <NavbarLink key={a.text} text={a.text} path={a.path} />)
: volunteer.map(v => <NavbarLink key={v.text} text={v.text} path={v.path} />)}
? admin.map(a => (
<NavbarLink key={a.text} text={a.text} path={a.path} changesMade={changesMade} />
))
: volunteer.map(v => (
<NavbarLink key={v.text} text={v.text} path={v.path} changesMade={changesMade} />
))}
{(!isAdmin || (isAdmin && !onAdminPortal)) && (
<Link to="/create-log">
<Button
Expand Down
13 changes: 11 additions & 2 deletions src/components/Toast.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import PropTypes from 'prop-types';

// Pass in toast because can't call hooks in conditionals
const Toast = (toast, status) => {
const containerStyle = { width: '100vw', fontWeight: 550 };
Expand All @@ -8,12 +7,17 @@ const Toast = (toast, status) => {
const isClosable = true;
const duration = 5000;
let description = '';

if (status === '') {
return null;
}

if (status === 'success') {
description = 'Successfully saved changes!';
}

if (status === 'error') {
description = 'Error: Unable to save';
description = 'Error: Unable to save, please try again later.';
}

if (status === 'password') {
Expand All @@ -27,6 +31,11 @@ const Toast = (toast, status) => {
if (status === 'unsaved') {
description = 'Careful - you have unsaved changes';
}

if (status === 'weak') {
description = 'Error - Password should be at least 6 characters';
}

return toast({
description,
position,
Expand Down
Loading

0 comments on commit d4a5aa9

Please sign in to comment.