diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index dfae3959f..888557725 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -39,7 +39,6 @@ import { useGetUserCertificationProgress, useLearnBreadcrumb, userCertificationProgressAutocompleteCourse, - userCertificationProgressCompleteCourseAsync, UserCertificationProgressProviderData, userCertificationProgressStartAsync, UserCertificationProgressStatus, @@ -54,6 +53,7 @@ import { } from '../learn.routes' import { LearnConfig } from '../learn-config' +import { useCheckAndMarkCourseCompleted } from './hooks/use-mark-course-completed' import { FccFrame } from './fcc-frame' import { FccSidebar } from './fcc-sidebar' import { TitleNav } from './title-nav' @@ -419,48 +419,13 @@ const FreeCodeCamp: FC<{}> = () => { location.state, ]) - useEffect(() => { - - // if we don't yet have the user's handle, - // or if the cert isn't complete, - // or the cert isn't in progress, - // there's nothing to do - if ( - !profile?.handle - || certificateProgress?.certificationProgressPercentage !== 100 - || certificateProgress?.status !== UserCertificationProgressStatus.inProgress - ) { - return - } - - // it's safe to complete the course - userCertificationProgressCompleteCourseAsync( - certificateProgress.id, - certificationParam, - profile.handle, - providerParam, - ) - .then(setCertificateProgress) - .then(() => { - const completedPath: string = getCertificationCompletedPath( - providerParam, - certificationParam, - ) - navigate(completedPath, { - state: { - tcaCertInfo: location.state?.tcaCertInfo, - }, - }) - }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ + useCheckAndMarkCourseCompleted( + !!profile?.userId, + providerParam, certificateProgress, - certificationParam, profile?.handle, - profile?.userId, - providerParam, - location.state, - ]) + setCertificateProgress, + ) useEffect(() => { if (courseDataReady && courseData) { diff --git a/src-ts/tools/learn/free-code-camp/hooks/use-mark-course-completed.tsx b/src-ts/tools/learn/free-code-camp/hooks/use-mark-course-completed.tsx new file mode 100644 index 000000000..1d427e2fc --- /dev/null +++ b/src-ts/tools/learn/free-code-camp/hooks/use-mark-course-completed.tsx @@ -0,0 +1,67 @@ +import { noop } from 'lodash' +import { MutableRefObject, useEffect, useRef } from 'react' +import { NavigateFunction, useLocation, useNavigate } from 'react-router-dom' + +import { + LearnUserCertificationProgress, + userCertificationProgressCompleteCourseAsync, + UserCertificationProgressStatus, +} from '../../learn-lib' +import { getCertificationCompletedPath } from '../../learn.routes' + +export const useCheckAndMarkCourseCompleted: ( + isLoggedIn: boolean, + providerName: string, + certificateProgress?: LearnUserCertificationProgress, + userHandle?: string, + setCertificateProgress?: (progess: LearnUserCertificationProgress) => void +) => void = (isLoggedIn, providerName, certificateProgress, userHandle, setCertificateProgress = noop) => { + const navigate: NavigateFunction = useNavigate() + const location: any = useLocation() + const isUpdating: MutableRefObject = useRef(false) + + useEffect(() => { + // if we don't yet have the user's handle, + // or if the cert isn't complete, + // or the cert isn't in progress, + // there's nothing to do + if ( + isUpdating.current + || !isLoggedIn + || certificateProgress?.certificationProgressPercentage !== 100 + || certificateProgress?.status !== UserCertificationProgressStatus.inProgress + ) { + return + } + + // Prevent further calls to the backend until this one is completed + isUpdating.current = true + // it's safe to complete the course + userCertificationProgressCompleteCourseAsync( + certificateProgress?.id, + certificateProgress.certification, + userHandle as string, + providerName, + ) + .then(setCertificateProgress) + .then(() => { + const completedPath: string = getCertificationCompletedPath( + providerName, + certificateProgress.certification, + ) + isUpdating.current = false + navigate(completedPath, { + state: { + tcaCertInfo: location.state?.tcaCertInfo, + }, + }) + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + certificateProgress, + isLoggedIn, + userHandle, + providerName, + location.state, + ]) +}