Skip to content

Commit

Permalink
Merge pull request #2530 from airqo-platform/feat-google-login
Browse files Browse the repository at this point in the history
Move redirect check to protected route file in analytics platform
  • Loading branch information
Baalmart authored Feb 25, 2025
2 parents dae166f + 41c7754 commit 963fc29
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 93 deletions.
79 changes: 77 additions & 2 deletions src/platform/src/core/utils/protectedRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,87 @@ import React, { useEffect } from 'react';
import { useRouter } from 'next/router';
import { useSelector, useDispatch } from 'react-redux';
import LogoutUser from '@/core/utils/LogoutUser';
import Cookies from 'js-cookie';
import jwt_decode from 'jwt-decode';
import {
setUserInfo,
setSuccess,
} from '@/lib/store/services/account/LoginSlice';
import { getIndividualUserPreferences } from '@/lib/store/services/account/UserDefaultsSlice';
import { getUserDetails } from '@/core/apis/Account';
import Spinner from '../../common/components/Spinner';

const MAX_RETRIES = 3;
const RETRY_DELAY = 1000;

export default function withAuth(Component) {
return function WithAuthComponent(props) {
const dispatch = useDispatch();
const router = useRouter();
const userCredentials = useSelector((state) => state.login);
const [isRedirecting, setIsRedirecting] = React.useState(
router.query.success === 'google',
);

const retryWithDelay = async (fn, retries = MAX_RETRIES) => {
try {
return await fn();
} catch (error) {
if (retries > 0 && error.response?.status === 429) {
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
return retryWithDelay(fn, retries - 1);
}
throw error;
}
};

const setupUserSession = async (user) => {
if (!user.groups[0]?.grp_title) {
throw new Error(
'Server error. Contact support to add you to the AirQo Organisation',
);
}

localStorage.setItem('loggedUser', JSON.stringify(user));

const preferencesResponse = await retryWithDelay(() =>
dispatch(getIndividualUserPreferences({ identifier: user._id })),
);
if (preferencesResponse.payload.success) {
const preferences = preferencesResponse.payload.preferences;
const activeGroup = preferences[0]?.group_id
? user.groups.find((group) => group._id === preferences[0].group_id)
: user.groups.find((group) => group.grp_title === 'airqo');
localStorage.setItem('activeGroup', JSON.stringify(activeGroup));
}

dispatch(setUserInfo(user));
dispatch(setSuccess(true));
};

useEffect(() => {
if (typeof window !== 'undefined') {
const storedUserGroup = localStorage.getItem('activeGroup');
// Handle Google redirect first
if (router.query.success === 'google') {
const token = Cookies.get('access_token');
if (token) {
localStorage.setItem('token', token);
const decoded = jwt_decode(token);
retryWithDelay(() => getUserDetails(decoded._id, token))
.then((response) => setupUserSession(response.users[0]))
.catch((error) => {
console.error('Google auth error:', error);
setIsRedirecting(false);
router.push('/account/login');
});
} else {
setIsRedirecting(false);
router.push('/account/login');
}
return; // Exit early to prevent further checks until redirect is resolved
}

const storedUserGroup = localStorage.getItem('activeGroup');
if (!userCredentials.success) {
router.push('/account/login');
}
Expand All @@ -21,7 +91,12 @@ export default function withAuth(Component) {
LogoutUser(dispatch, router);
}
}
}, [userCredentials, dispatch, router]);
}, [userCredentials, dispatch, router, retryWithDelay, isRedirecting]);

// Block rendering until redirect is handled
if (isRedirecting) {
return <Spinner width={20} height={20} />;
}

// Render the component if the user is authenticated
return userCredentials.success ? <Component {...props} /> : null;
Expand Down
91 changes: 0 additions & 91 deletions src/platform/src/pages/Home/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,6 @@ import {
import HomeSkeleton from '@/components/skeletons/HomeSkeleton';
import CustomModal from '@/components/Modal/videoModals/CustomModal';
import StepProgress from '@/components/steppers/CircularStepper';
import Cookies from 'js-cookie';
import jwt_decode from 'jwt-decode';
import { useRouter } from 'next/router';
import {
setUserInfo,
setSuccess,
} from '@/lib/store/services/account/LoginSlice';
import { getIndividualUserPreferences } from '@/lib/store/services/account/UserDefaultsSlice';
import { getUserDetails } from '@/core/apis/Account';

const MAX_RETRIES = 3;
const RETRY_DELAY = 1000;

// Video URL constant
const ANALYTICS_VIDEO_URL =
Expand Down Expand Up @@ -72,16 +60,13 @@ const createSteps = (handleModal, handleCardClick) => [

const Home = () => {
const dispatch = useDispatch();
const router = useRouter();

// Selectors
const checkListData = useSelector((state) => state.checklists.checklist);
const cardCheckList = useSelector((state) => state.cardChecklist.cards);
const checkListStatus = useSelector((state) => state.checklists.status);

// State hooks
const [loading, setLoading] = useState(false);

const [open, setOpen] = useState(false);
const [step, setStep] = useState(0);
const totalSteps = 4;
Expand All @@ -100,82 +85,6 @@ const Home = () => {
return null;
}, []);

const retryWithDelay = async (fn, retries = MAX_RETRIES) => {
try {
return await fn();
} catch (error) {
if (retries > 0 && error.response?.status === 429) {
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
return retryWithDelay(fn, retries - 1);
}
throw error;
}
};

// Refactored session setup logic for reuse
const setupUserSession = async (user) => {
if (!user.groups[0]?.grp_title) {
throw new Error(
'Server error. Contact support to add you to the AirQo Organisation',
);
}

localStorage.setItem('loggedUser', JSON.stringify(user));

const preferencesResponse = await retryWithDelay(() =>
dispatch(getIndividualUserPreferences({ identifier: user._id })),
);
if (preferencesResponse.payload.success) {
const preferences = preferencesResponse.payload.preferences;
const activeGroup = preferences[0]?.group_id
? user.groups.find((group) => group._id === preferences[0].group_id)
: user.groups.find((group) => group.grp_title === 'airqo');
localStorage.setItem('activeGroup', JSON.stringify(activeGroup));
}

dispatch(setUserInfo(user));
dispatch(setSuccess(true));
router.push('/Home');
};

// Handle Google redirect
useEffect(() => {
const handleGoogleRedirect = async () => {
if (router.query.success === 'google') {
setLoading(true);
try {
// Retrieve the access_token cookie using js-cookie
const token = Cookies.get('access_token');
if (!token) {
throw new Error('No access_token cookie found');
}

// Store the token in localStorage as 'token'
localStorage.setItem('token', token);
const decoded = jwt_decode(token);

// Fetch user details using the token
const response = await retryWithDelay(() =>
getUserDetails(decoded._id, token),
);
const user = response.users[0];

await setupUserSession(user);
} catch (error) {
dispatch(setSuccess(false));
setLoading(false);
throw error;
}
}
};

handleGoogleRedirect();
}, [router, dispatch]);

if (loading) {
return <HomeSkeleton />;
}

// Handlers
const handleModal = useCallback(() => {
setOpen((prev) => !prev);
Expand Down

0 comments on commit 963fc29

Please sign in to comment.