From 0bcf276e891473f336c00319fadc38f975826297 Mon Sep 17 00:00:00 2001 From: Brooke Date: Tue, 6 Dec 2022 11:43:13 -0800 Subject: [PATCH 01/18] TCA-755 #comment This commit adds the basic sprig html snippet and fixes some lint issues. #time 1h --- public/index.html | 53 +++++++++------ src-ts/App.tsx | 6 +- .../learn/free-code-camp/FreeCodeCamp.tsx | 65 +++++++++++++------ 3 files changed, 83 insertions(+), 41 deletions(-) diff --git a/public/index.html b/public/index.html index 7df78700f..546e6a325 100644 --- a/public/index.html +++ b/public/index.html @@ -2,24 +2,26 @@ - - - - - - - - - - - - - - - Topcoder Top Technology Talent On-Demand + Topcoder Top Technology Talent On-Demand - -
- + + + diff --git a/src-ts/App.tsx b/src-ts/App.tsx index ce3dad70d..7a81a3fe7 100644 --- a/src-ts/App.tsx +++ b/src-ts/App.tsx @@ -7,7 +7,7 @@ import { routeContext, RouteContextData } from './lib' const App: FC<{}> = () => { - const [ready, setReady]: [boolean, Dispatch>] = useState(false) + const [ready, setReady]: [boolean, Dispatch>] = useState(false) const { allRoutes, getRouteElement }: RouteContextData = useContext(routeContext) const routeElements: Array = allRoutes @@ -19,9 +19,9 @@ const App: FC<{}> = () => { useEffect(() => { if (ready) { - document.getElementById('root')?.classList.add('app-ready'); + document.getElementById('root')?.classList.add('app-ready') } - }, [ready]); + }, [ready]) return ( <> diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 0e507be63..3bf8e2612 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -17,12 +17,15 @@ import { LoadingSpinner, profileContext, ProfileContextData, + textFormatGetSafeString, } from '../../../lib' import { CoursesProviderData, LearnLesson, LearnModule, LearnModuleProgress, + LearnModuleStatus, + LearnUserCertificationProgress, LessonProviderData, useGetCourses, useGetLesson, @@ -52,11 +55,14 @@ const FreeCodeCamp: FC<{}> = () => { const navigate: NavigateFunction = useNavigate() const routeParams: Params = useParams() - const providerParam: string = routeParams.provider ?? '' + const providerParam: string = textFormatGetSafeString(routeParams.provider) - const [certificationParam, setCourseParam]: [string, Dispatch>] = useState(routeParams.certification ?? '') - const [moduleParam, setModuleParam]: [string, Dispatch>] = useState(routeParams.module ?? '') - const [lessonParam, setLessonParam]: [string, Dispatch>] = useState(routeParams.lesson ?? '') + const [certificationParam, setCourseParam]: [string, Dispatch>] + = useState(textFormatGetSafeString(routeParams.certification)) + const [moduleParam, setModuleParam]: [string, Dispatch>] + = useState(textFormatGetSafeString(routeParams.module)) + const [lessonParam, setLessonParam]: [string, Dispatch>] + = useState(textFormatGetSafeString(routeParams.lesson)) const { certificationProgress: certificateProgress, @@ -83,11 +89,11 @@ const FreeCodeCamp: FC<{}> = () => { const ready: boolean = profileReady && courseDataReady && lessonReady && (!isLoggedIn || progressReady) - const certification: string = lesson?.course.certification ?? '' - const module: string = lesson?.module.title ?? '' + const certification: string = textFormatGetSafeString(lesson?.course.certification) + const module: string = textFormatGetSafeString(lesson?.module.title) const breadcrumb: Array = useLearnBreadcrumb([ { - name: lesson?.course.title ?? '', + name: textFormatGetSafeString(lesson?.course.title), url: getCoursePath(providerParam, certification), }, { @@ -96,7 +102,8 @@ const FreeCodeCamp: FC<{}> = () => { }, ]) - const currentModuleData: LearnModule | undefined = useMemo(() => courseData?.modules.find(d => d.key === moduleParam), [courseData, moduleParam]) + const currentModuleData: LearnModule | undefined + = useMemo(() => courseData?.modules.find(d => d.key === moduleParam), [courseData, moduleParam]) const currentStepIndex: number = useMemo(() => { if (!currentModuleData) { @@ -155,7 +162,7 @@ const FreeCodeCamp: FC<{}> = () => { } } - function handleFccLessonReady(lessonPath: string): void { + const handleFccLessonReady: (lessonPath: string) => void = useCallback((lessonPath: string) => { const [nLessonPath, modulePath, coursePath]: Array = lessonPath.replace(/\/$/, '') .split('/') @@ -195,9 +202,10 @@ const FreeCodeCamp: FC<{}> = () => { .then(setCertificateProgress) }, 500) } - } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) - function handleFccLessonComplete(challengeUuid: string): void { + const handleFccLessonComplete: (challengeUuid: string) => void = useCallback((challengeUuid: string) => { const currentLesson: { [key: string]: string } = { lesson: lessonParam, module: moduleParam, @@ -209,15 +217,29 @@ const FreeCodeCamp: FC<{}> = () => { UserCertificationUpdateProgressActions.completeLesson, currentLesson, ) - .then(setCertificateProgress) + .then((progress: LearnUserCertificationProgress) => { + + setCertificateProgress(progress) + + // if this is the last lesson of the first module, show the survey + const firstModule: LearnModuleProgress = progress.modules[0] + + if (moduleParam === firstModule.module + && firstModule.moduleStatus === LearnModuleStatus.completed) { + + // TODO: use the Sprig SDK to send the event w/the user + window.Sprig('track', 'TCA First Module Completed') + } + }) } - } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) /** * Handle the navigation away from the last step of the course in the FCC frame * @returns */ - function handleFccLastLessonNavigation(): void { + const handleFccLastLessonNavigation: () => void = useCallback(() => { if (!certificateProgress) { return } @@ -236,15 +258,18 @@ const FreeCodeCamp: FC<{}> = () => { // course is not completed yet, // so we find the first incomplete lesson // and redirect user to it for a continuous flow - const firstIncompleteModule: LearnModuleProgress | undefined = certificateProgress.modules.find(m => m.completedPercentage !== 100) - const moduleLessons: Array | undefined = courseData?.modules.find(m => m.key === firstIncompleteModule?.module)?.lessons + const firstIncompleteModule: LearnModuleProgress | undefined + = certificateProgress.modules.find(m => m.completedPercentage !== 100) + const moduleLessons: Array | undefined + = courseData?.modules.find(m => m.key === firstIncompleteModule?.module)?.lessons if (!firstIncompleteModule || !moduleLessons) { // case unknown, return return } const completedLessons: Array = firstIncompleteModule.completedLessons.map(l => l.dashedName) - const firstIncompleteLesson: LearnLesson | undefined = moduleLessons.find(l => !completedLessons.includes(l.dashedName)) + const firstIncompleteLesson: LearnLesson | undefined + = moduleLessons.find(l => !completedLessons.includes(l.dashedName)) if (!firstIncompleteLesson) { // case unknown, return return @@ -258,7 +283,8 @@ const FreeCodeCamp: FC<{}> = () => { ) navigate(nextLessonPath) - } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) useEffect(() => { @@ -300,7 +326,8 @@ const FreeCodeCamp: FC<{}> = () => { useEffect(() => { if (courseDataReady && courseData) { - const moduleParamData: LearnModule = courseData.modules.find(m => m.key === moduleParam) ?? courseData.modules[0] + const moduleParamData: LearnModule = courseData.modules.find(m => m.key === moduleParam) + ?? courseData.modules[0] const lessonParamExists: boolean = !!moduleParamData?.lessons.find(l => l.dashedName === lessonParam) if (!lessonParamExists) { From 375a554c1992443bb4824b25c1d74d49d5daeee7 Mon Sep 17 00:00:00 2001 From: Brooke Date: Tue, 6 Dec 2022 14:06:30 -0800 Subject: [PATCH 02/18] TCA-755 #comment This commit adds the Sprig SDK and creates a wrapper function for surveys. #time 1h --- package.json | 1 + public/index.html | 13 ---- .../environment.default.config.ts | 3 + .../environments/environment.prod.config.ts | 3 + src-ts/lib/functions/index.ts | 1 + .../lib/functions/survey-functions/index.ts | 1 + .../survey-functions/survey.functions.tsx | 22 +++++++ src-ts/lib/global-config.model.ts | 3 + src-ts/lib/index.ts | 1 + .../learn/free-code-camp/FreeCodeCamp.tsx | 66 ++++++++++++------- yarn.lock | 5 ++ 11 files changed, 82 insertions(+), 37 deletions(-) create mode 100644 src-ts/lib/functions/survey-functions/index.ts create mode 100644 src-ts/lib/functions/survey-functions/survey.functions.tsx diff --git a/package.json b/package.json index e247c0e8e..b2e953eb2 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "@datadog/browser-logs": "^4.21.2", "@heroicons/react": "^1.0.6", + "@sprig-technologies/sprig-browser": "^2.20.1", "@stripe/react-stripe-js": "1.13.0", "@stripe/stripe-js": "1.41.0", "apexcharts": "^3.36.0", diff --git a/public/index.html b/public/index.html index 546e6a325..374c41cfc 100644 --- a/public/index.html +++ b/public/index.html @@ -46,19 +46,6 @@ To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> - - - diff --git a/src-ts/config/environments/environment.default.config.ts b/src-ts/config/environments/environment.default.config.ts index 0c0b89f95..3ee4c6d72 100644 --- a/src-ts/config/environments/environment.default.config.ts +++ b/src-ts/config/environments/environment.default.config.ts @@ -20,6 +20,9 @@ export const EnvironmentConfigDefault: EnvironmentConfigModel = { SERVICE: 'platform-ui', }, REAUTH_OFFSET: 55, + SPRIG: { + ENVIRONMENT_ID: 'bUcousVQ0-yF', + }, // TODO: Move stripe creds to .env file STRIPE: { ADMIN_TOKEN: diff --git a/src-ts/config/environments/environment.prod.config.ts b/src-ts/config/environments/environment.prod.config.ts index c1b9d8caa..03db09f04 100644 --- a/src-ts/config/environments/environment.prod.config.ts +++ b/src-ts/config/environments/environment.prod.config.ts @@ -18,6 +18,9 @@ export const EnvironmentConfigProd: EnvironmentConfigModel = { }, DISABLED_TOOLS: [], ENV: 'prod', + SPRIG: { + ENVIRONMENT_ID: 'a-IZBZ6-r7bU', + }, // TODO: Move stripe creds to .env file STRIPE: { ADMIN_TOKEN: diff --git a/src-ts/lib/functions/index.ts b/src-ts/lib/functions/index.ts index 3bf2087c5..26d8df237 100644 --- a/src-ts/lib/functions/index.ts +++ b/src-ts/lib/functions/index.ts @@ -10,5 +10,6 @@ export * from './error-functions' export * from './file-functions' export * from './logging-functions' export * from './text-format-functions' +export * from './survey-functions' export * from './user-functions' export * from './xhr-functions' diff --git a/src-ts/lib/functions/survey-functions/index.ts b/src-ts/lib/functions/survey-functions/index.ts new file mode 100644 index 000000000..b4deb0990 --- /dev/null +++ b/src-ts/lib/functions/survey-functions/index.ts @@ -0,0 +1 @@ +export { triggerForUser as surveyTriggerForUser } from './survey.functions' diff --git a/src-ts/lib/functions/survey-functions/survey.functions.tsx b/src-ts/lib/functions/survey-functions/survey.functions.tsx new file mode 100644 index 000000000..303aa9366 --- /dev/null +++ b/src-ts/lib/functions/survey-functions/survey.functions.tsx @@ -0,0 +1,22 @@ +import { sprig, SprigAPI } from '@sprig-technologies/sprig-browser' + +import { EnvironmentConfig } from '../../../config' + +const Sprig: SprigAPI = sprig.configure({ + environmentId: EnvironmentConfig.SPRIG.ENVIRONMENT_ID, +}) + +export function triggerForUser(surveyName: string, userId?: number): void { + + if (!userId) { + Sprig.track(surveyName) + return + } + + Sprig.identifyAndTrack({ + anonymousId: '', + eventName: surveyName, + metadata: undefined, + userId: `${userId}`, + }) +} diff --git a/src-ts/lib/global-config.model.ts b/src-ts/lib/global-config.model.ts index ddf9b8ce4..8d5576c9b 100644 --- a/src-ts/lib/global-config.model.ts +++ b/src-ts/lib/global-config.model.ts @@ -16,6 +16,9 @@ export interface GlobalConfig { SERVICE: string } REAUTH_OFFSET: number + SPRIG: { + ENVIRONMENT_ID: string + } STRIPE: { ADMIN_TOKEN: string API_KEY: string diff --git a/src-ts/lib/index.ts b/src-ts/lib/index.ts index ea3a4dd85..99e14a759 100644 --- a/src-ts/lib/index.ts +++ b/src-ts/lib/index.ts @@ -18,6 +18,7 @@ export { logError, logInfo, logInitialize, + surveyTriggerForUser, textFormatDateLocaleShortString, textFormatGetSafeString, textFormatMoneyLocaleString, diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 3bf8e2612..3ecf233fa 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -17,6 +17,7 @@ import { LoadingSpinner, profileContext, ProfileContextData, + surveyTriggerForUser, textFormatGetSafeString, } from '../../../lib' import { @@ -203,43 +204,55 @@ const FreeCodeCamp: FC<{}> = () => { }, 500) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [ + certificateProgress, + lesson?.course.certificationId, + lesson?.course.id, + profile?.userId, + ]) const handleFccLessonComplete: (challengeUuid: string) => void = useCallback((challengeUuid: string) => { + const currentLesson: { [key: string]: string } = { lesson: lessonParam, module: moduleParam, uuid: challengeUuid, } - if (certificateProgress) { - userCertificationProgressUpdateAsync( - certificateProgress.id, - UserCertificationUpdateProgressActions.completeLesson, - currentLesson, - ) - .then((progress: LearnUserCertificationProgress) => { - setCertificateProgress(progress) + if (!certificateProgress) { + return + } - // if this is the last lesson of the first module, show the survey - const firstModule: LearnModuleProgress = progress.modules[0] + userCertificationProgressUpdateAsync( + certificateProgress.id, + UserCertificationUpdateProgressActions.completeLesson, + currentLesson, + ) + .then((progress: LearnUserCertificationProgress) => { - if (moduleParam === firstModule.module - && firstModule.moduleStatus === LearnModuleStatus.completed) { + setCertificateProgress(progress) - // TODO: use the Sprig SDK to send the event w/the user - window.Sprig('track', 'TCA First Module Completed') - } - }) - } + // if this is the last lesson of the first module, show the survey + const firstModule: LearnModuleProgress = progress.modules[0] + if (moduleParam === firstModule.module + && firstModule.moduleStatus === LearnModuleStatus.completed) { + + surveyTriggerForUser('TCA First Module Completed', profile?.userId) + } + }) // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [ + certificateProgress, + lessonParam, + moduleParam, + ]) /** * Handle the navigation away from the last step of the course in the FCC frame * @returns */ const handleFccLastLessonNavigation: () => void = useCallback(() => { + if (!certificateProgress) { return } @@ -284,7 +297,12 @@ const FreeCodeCamp: FC<{}> = () => { navigate(nextLessonPath) // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [ + certificateProgress, + certificationParam, + courseData?.modules, + providerParam, + ]) useEffect(() => { @@ -315,13 +333,13 @@ const FreeCodeCamp: FC<{}> = () => { ) navigate(completedPath) }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ certificateProgress, certificationParam, - navigate, - providerParam, profile?.handle, - setCertificateProgress, + profile?.userId, + providerParam, ]) useEffect(() => { @@ -341,13 +359,13 @@ const FreeCodeCamp: FC<{}> = () => { navigate(lessonPath) } } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ certificationParam, courseData, courseDataReady, lessonParam, moduleParam, - navigate, providerParam, ]) diff --git a/yarn.lock b/yarn.lock index 9ebde0202..76fe3a862 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2070,6 +2070,11 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@sprig-technologies/sprig-browser@^2.20.1": + version "2.20.1" + resolved "https://registry.yarnpkg.com/@sprig-technologies/sprig-browser/-/sprig-browser-2.20.1.tgz#4c655052dc02514370e92886724cc740337b7d16" + integrity sha512-Qkt1yEhSz9FIXpDMjMzWklscF0HmKCmLebYDvVpJxqbEeYzCEQjzeD4WW5RTpvCgyuwzXT0At4Xx9UijCWAS8Q== + "@stripe/react-stripe-js@1.13.0": version "1.13.0" resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.13.0.tgz#8e0bde2b116870d2aca52976f46a92d81983e235" From a19ad9694d13ce4b21a7e410c6c4b26643068fc2 Mon Sep 17 00:00:00 2001 From: Brooke Date: Tue, 6 Dec 2022 16:28:04 -0800 Subject: [PATCH 03/18] TCA-755 #comment Update the trigger to run the first time any module is completed --- .../learn/free-code-camp/FreeCodeCamp.tsx | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 3ecf233fa..33829d44c 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -223,6 +223,10 @@ const FreeCodeCamp: FC<{}> = () => { return } + // get the current module as it exists before it's completed + const currentModule: LearnModuleProgress | undefined = getModuleFromProgress(certificateProgress) + const certWasInProgress: boolean = currentModule?.moduleStatus !== LearnModuleStatus.completed + userCertificationProgressUpdateAsync( certificateProgress.id, UserCertificationUpdateProgressActions.completeLesson, @@ -231,14 +235,8 @@ const FreeCodeCamp: FC<{}> = () => { .then((progress: LearnUserCertificationProgress) => { setCertificateProgress(progress) + handleSurvey(certWasInProgress, progress) - // if this is the last lesson of the first module, show the survey - const firstModule: LearnModuleProgress = progress.modules[0] - if (moduleParam === firstModule.module - && firstModule.moduleStatus === LearnModuleStatus.completed) { - - surveyTriggerForUser('TCA First Module Completed', profile?.userId) - } }) // eslint-disable-next-line react-hooks/exhaustive-deps }, [ @@ -247,6 +245,37 @@ const FreeCodeCamp: FC<{}> = () => { moduleParam, ]) + function getModuleFromProgress(certProgress: LearnUserCertificationProgress): + LearnModuleProgress | undefined { + + return certProgress.modules.find(m => m.module === moduleParam) + } + + function handleSurvey(certWasInProgress: boolean, progress: LearnUserCertificationProgress): void { + + // if the current module wasn't in progress, there's nothing to do + if (!certWasInProgress) { + return + } + + // if the updated module isn't completed now, there's nothing to do + const moduleResult: LearnModuleProgress | undefined = getModuleFromProgress(progress) + if (moduleResult?.moduleStatus !== LearnModuleStatus.completed) { + return + } + + // if there are any other modules that have been completed, there's nothing to do + if (progress.modules + .some(m => m.module !== moduleParam && m.moduleStatus === LearnModuleStatus.completed) + ) { + return + } + + // this is the last lesson to be completed in the first module completed, + // so it's good to show the trigger + surveyTriggerForUser('TCA First Module Completed', profile?.userId) + } + /** * Handle the navigation away from the last step of the course in the FCC frame * @returns From 8c10a2cac01e4d787c25b8691779053a0605f1ab Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 7 Dec 2022 10:34:51 -0800 Subject: [PATCH 04/18] TCA-790 #comment add delay if the cert is completed #time 2h --- src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 33829d44c..64517b891 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -271,9 +271,17 @@ const FreeCodeCamp: FC<{}> = () => { return } - // this is the last lesson to be completed in the first module completed, - // so it's good to show the trigger - surveyTriggerForUser('TCA First Module Completed', profile?.userId) + // This is the last lesson to be completed in the first module completed, + // so it's time to trigger the survey + + // If there is only one assessment in a cert (e.g. Data Analysis w/Python), + // the cert is also completed, which redirects the user to the cert page. + // So the survey needs to be delayed so that it appears on the completed + // cert page instead of the current lesson. + const delay: number = progress.status === UserCertificationProgressStatus.completed ? 3000 : 0 + setTimeout(async () => { + surveyTriggerForUser('TCA First Module Completed', profile?.userId) + }, delay) } /** From 3e0ee9904ae589c941d5ae04f3c73ab112b5a347 Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 7 Dec 2022 15:22:49 -0800 Subject: [PATCH 05/18] TCA-790 #comment This commit sets a timeout and uses the cert progress #time 1h --- src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 64517b891..bdac73d99 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -273,15 +273,19 @@ const FreeCodeCamp: FC<{}> = () => { // This is the last lesson to be completed in the first module completed, // so it's time to trigger the survey + const surveyTrigger: string = 'TCA First Module Completed' // If there is only one assessment in a cert (e.g. Data Analysis w/Python), // the cert is also completed, which redirects the user to the cert page. // So the survey needs to be delayed so that it appears on the completed // cert page instead of the current lesson. - const delay: number = progress.status === UserCertificationProgressStatus.completed ? 3000 : 0 - setTimeout(async () => { - surveyTriggerForUser('TCA First Module Completed', profile?.userId) - }, delay) + if (progress.certificationProgressPercentage === 100) { + setTimeout(async () => { + surveyTriggerForUser(surveyTrigger, profile?.userId) + }, 1000) + } else { + surveyTriggerForUser(surveyTrigger, profile?.userId) + } } /** From 7b4d8b94512615f1a1e2f9b9a4b17dc38277214a Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 7 Dec 2022 15:41:31 -0800 Subject: [PATCH 06/18] TCA-652 #comment This commit sets all env to cache. #time 15m --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7870c4bdb..288a51234 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -28,7 +28,7 @@ install_dependency: &install_dependency install_deploysuite: &install_deploysuite name: Installation of install_deploysuite. command: | - git clone --branch v1.4.12 https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript + git clone --branch v1.4.13 https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript cp ./../buildscript/master_deploy.sh . cp ./../buildscript/buildenv.sh . cp ./../buildscript/awsconfiguration.sh . @@ -184,7 +184,7 @@ jobs: environment: DEPLOY_ENV: "PROD" LOGICAL_ENV: "prod" - ENABLE_CACHE: false + ENABLE_CACHE: true APPNAME: "platform-ui-mvp" steps: *deploy_steps From fe608e4ac3ed29da28db7ce70068b7d7f49540cd Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Thu, 8 Dec 2022 17:10:40 +0200 Subject: [PATCH 07/18] Use progress.status to check certification completion status --- src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 33829d44c..d860f092c 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -287,7 +287,7 @@ const FreeCodeCamp: FC<{}> = () => { } // course is completed, return user to course completed screen - if (certificateProgress.courseProgressPercentage === 100) { + if (certificateProgress.status === UserCertificationProgressStatus.completed) { const completedPath: string = getCertificationCompletedPath( providerParam, certificationParam, From 70d01164f9f290fee5beff3ee91bbcf4fdc38aed Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Thu, 8 Dec 2022 17:11:08 +0200 Subject: [PATCH 08/18] user-certification-progress.ready - convert to boolean --- .../user-certification-progress.provider.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certification-progress.provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certification-progress.provider.tsx index 7bffd5039..9909a3a1c 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certification-progress.provider.tsx +++ b/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certification-progress.provider.tsx @@ -27,10 +27,12 @@ export function useGetUserCertificationProgress( isPaused: () => !userId || !certification, }) + const certificationProgress: LearnUserCertificationProgress | undefined = find(data, { certification }) + return { - certificationProgress: find(data, { certification }), + certificationProgress, loading: !!userId && !data && !error, - ready: !userId || data || error, + ready: !userId || !!data || !!error, refetch: () => mutate(), setCertificateProgress: progress => mutate([progress]), } From 96367c809ab219404f6c17abe31e3c4b39c1f2f9 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Thu, 8 Dec 2022 17:12:47 +0200 Subject: [PATCH 09/18] debounce lessonCompleted & lastLesson events from FCC --- src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index d860f092c..47f360465 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -45,6 +45,7 @@ import { FccFrame } from './fcc-frame' import { FccSidebar } from './fcc-sidebar' import { TitleNav } from './title-nav' import styles from './FreeCodeCamp.module.scss' +import { debounce } from 'lodash' const FreeCodeCamp: FC<{}> = () => { @@ -211,7 +212,7 @@ const FreeCodeCamp: FC<{}> = () => { profile?.userId, ]) - const handleFccLessonComplete: (challengeUuid: string) => void = useCallback((challengeUuid: string) => { + const handleFccLessonComplete: (challengeUuid: string) => void = useCallback(debounce((challengeUuid: string) => { const currentLesson: { [key: string]: string } = { lesson: lessonParam, @@ -239,7 +240,7 @@ const FreeCodeCamp: FC<{}> = () => { }) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ + }, 30), [ certificateProgress, lessonParam, moduleParam, @@ -280,7 +281,7 @@ const FreeCodeCamp: FC<{}> = () => { * Handle the navigation away from the last step of the course in the FCC frame * @returns */ - const handleFccLastLessonNavigation: () => void = useCallback(() => { + const handleFccLastLessonNavigation: () => void = useCallback(debounce(() => { if (!certificateProgress) { return @@ -326,7 +327,7 @@ const FreeCodeCamp: FC<{}> = () => { navigate(nextLessonPath) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ + }, 30), [ certificateProgress, certificationParam, courseData?.modules, From 5436a5a4ecce183aee1ffd8269ab38164a7633b9 Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Thu, 8 Dec 2022 17:15:15 +0200 Subject: [PATCH 10/18] When user starts a new course, call swr.mutate with the new certificationProgress data. --- src-ts/tools/learn/course-details/CourseDetailsPage.tsx | 2 ++ .../course-details/course-curriculum/CourseCurriculum.tsx | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src-ts/tools/learn/course-details/CourseDetailsPage.tsx b/src-ts/tools/learn/course-details/CourseDetailsPage.tsx index 1af5be961..ef9a2836b 100644 --- a/src-ts/tools/learn/course-details/CourseDetailsPage.tsx +++ b/src-ts/tools/learn/course-details/CourseDetailsPage.tsx @@ -48,6 +48,7 @@ const CourseDetailsPage: FC<{}> = () => { const { certificationProgress: progress, ready: progressReady, + setCertificateProgress, }: UserCertificationProgressProviderData = useGetUserCertificationProgress( profile?.userId, routeParams.provider, @@ -214,6 +215,7 @@ const CourseDetailsPage: FC<{}> = () => { progress={progress} progressReady={progressReady} profile={profile} + setCertificateProgress={setCertificateProgress} /> diff --git a/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx b/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx index 1b8e80b6a..408c65466 100644 --- a/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx +++ b/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx @@ -31,6 +31,7 @@ interface CourseCurriculumProps { profile?: UserProfile progress?: LearnUserCertificationProgress progressReady?: boolean + setCertificateProgress: (d: LearnUserCertificationProgress) => void } const CourseCurriculum: FC = (props: CourseCurriculumProps) => { @@ -108,7 +109,7 @@ const CourseCurriculum: FC = (props: CourseCurriculumProp } if (!props.progress?.id) { - await userCertificationProgressStartAsync( + const progress: LearnUserCertificationProgress = await userCertificationProgressStartAsync( props.profile.userId, props.course.certificationId, props.course.id, @@ -117,6 +118,9 @@ const CourseCurriculum: FC = (props: CourseCurriculumProp module: props.course.modules[0].meta.dashedName, }, ) + + // update progress with data returned from calling the start progress endpoint + props.setCertificateProgress(progress) } else { await userCertificationProgressUpdateAsync( props.progress.id, From db66c098f6598ae5622c90a1eafc1e5d5447f58a Mon Sep 17 00:00:00 2001 From: Brooke Date: Thu, 8 Dec 2022 12:28:56 -0800 Subject: [PATCH 11/18] TCA-790 fix naming --- .../{survey.functions.tsx => survey.functions.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src-ts/lib/functions/survey-functions/{survey.functions.tsx => survey.functions.ts} (100%) diff --git a/src-ts/lib/functions/survey-functions/survey.functions.tsx b/src-ts/lib/functions/survey-functions/survey.functions.ts similarity index 100% rename from src-ts/lib/functions/survey-functions/survey.functions.tsx rename to src-ts/lib/functions/survey-functions/survey.functions.ts From 181918fc68b0e8db026a350ff6ec62dc2977daed Mon Sep 17 00:00:00 2001 From: Brooke Date: Thu, 8 Dec 2022 15:58:08 -0800 Subject: [PATCH 12/18] TCA-790 #comment This commit supports the fact that a certificate can actually be more than 100% when data isn't in sync w/FCC. #time 15m --- src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index bdac73d99..b565da434 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -279,7 +279,7 @@ const FreeCodeCamp: FC<{}> = () => { // the cert is also completed, which redirects the user to the cert page. // So the survey needs to be delayed so that it appears on the completed // cert page instead of the current lesson. - if (progress.certificationProgressPercentage === 100) { + if (progress.certificationProgressPercentage >= 100) { setTimeout(async () => { surveyTriggerForUser(surveyTrigger, profile?.userId) }, 1000) From 67defd52af786f1853822f9fb5709a07bbc3aff7 Mon Sep 17 00:00:00 2001 From: Brooke Date: Thu, 8 Dec 2022 16:00:18 -0800 Subject: [PATCH 13/18] TCA-790 comments --- src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index b565da434..fb7764d0e 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -279,6 +279,11 @@ const FreeCodeCamp: FC<{}> = () => { // the cert is also completed, which redirects the user to the cert page. // So the survey needs to be delayed so that it appears on the completed // cert page instead of the current lesson. + + // NOTE: we can't use the cert's status here bc it doesn't get set to + // completed until the UI notices the cert is complete and initiates + // the completion. And we have to use >= instead of === because it's + // possible TCA data isn't in sync w/the latest FCC curriculum. if (progress.certificationProgressPercentage >= 100) { setTimeout(async () => { surveyTriggerForUser(surveyTrigger, profile?.userId) From a5788de1e015e9ff5bac7a0cba13cb85f59dd105 Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 14 Dec 2022 11:40:55 -0800 Subject: [PATCH 14/18] TCA-663 Delay survey --- .../learn/free-code-camp/FreeCodeCamp.tsx | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 8a889a015..bfc91cc3a 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -1,3 +1,4 @@ +import { debounce } from 'lodash' import { Dispatch, FC, @@ -45,7 +46,6 @@ import { FccFrame } from './fcc-frame' import { FccSidebar } from './fcc-sidebar' import { TitleNav } from './title-nav' import styles from './FreeCodeCamp.module.scss' -import { debounce } from 'lodash' const FreeCodeCamp: FC<{}> = () => { @@ -274,24 +274,11 @@ const FreeCodeCamp: FC<{}> = () => { // This is the last lesson to be completed in the first module completed, // so it's time to trigger the survey - const surveyTrigger: string = 'TCA First Module Completed' - - // If there is only one assessment in a cert (e.g. Data Analysis w/Python), - // the cert is also completed, which redirects the user to the cert page. - // So the survey needs to be delayed so that it appears on the completed - // cert page instead of the current lesson. - - // NOTE: we can't use the cert's status here bc it doesn't get set to - // completed until the UI notices the cert is complete and initiates - // the completion. And we have to use >= instead of === because it's - // possible TCA data isn't in sync w/the latest FCC curriculum. - if (progress.certificationProgressPercentage >= 100) { - setTimeout(async () => { - surveyTriggerForUser(surveyTrigger, profile?.userId) - }, 1000) - } else { - surveyTriggerForUser(surveyTrigger, profile?.userId) - } + + // NOTE: We have to add a delay, otherwise the survey closes when the user + // is automatically redirected to the next lesson. + surveyTriggerForUser('TCA First Module Completed', profile?.userId) + } /** From 69effc0b55e0c785b5d1ac688dd613eba146a744 Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 14 Dec 2022 11:43:47 -0800 Subject: [PATCH 15/18] TCA-790 assessments add delay --- .../learn/free-code-camp/FreeCodeCamp.tsx | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 8a889a015..f56e83ba5 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -274,24 +274,12 @@ const FreeCodeCamp: FC<{}> = () => { // This is the last lesson to be completed in the first module completed, // so it's time to trigger the survey - const surveyTrigger: string = 'TCA First Module Completed' - - // If there is only one assessment in a cert (e.g. Data Analysis w/Python), - // the cert is also completed, which redirects the user to the cert page. - // So the survey needs to be delayed so that it appears on the completed - // cert page instead of the current lesson. - - // NOTE: we can't use the cert's status here bc it doesn't get set to - // completed until the UI notices the cert is complete and initiates - // the completion. And we have to use >= instead of === because it's - // possible TCA data isn't in sync w/the latest FCC curriculum. - if (progress.certificationProgressPercentage >= 100) { - setTimeout(async () => { - surveyTriggerForUser(surveyTrigger, profile?.userId) - }, 1000) - } else { - surveyTriggerForUser(surveyTrigger, profile?.userId) - } + + // NOTE: We have to add a delay, otherwise the survey closes when the user + // is automatically redirected to the next lesson. + setTimeout(() => { + surveyTriggerForUser('TCA First Module Completed', profile?.userId) + }, 1000) } /** From 3e915c3425b8e34f41d6d99754fa29442dcb6cb7 Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 14 Dec 2022 11:51:56 -0800 Subject: [PATCH 16/18] TCA-832 temporarily deploy release branch to dev --- .circleci/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 288a51234..cf539516f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -227,7 +227,9 @@ workflows: filters: branches: only: - - dev + # - dev + # temp only deploy this branch to dev + - TCA-790_assessments - deployProd: context : org-global From 37867d674d13b5a15cc998bdf896d10f6b089089 Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 14 Dec 2022 11:52:48 -0800 Subject: [PATCH 17/18] TCA-832 Fix branch to deploy to dev --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cf539516f..0059ee051 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -228,8 +228,8 @@ workflows: branches: only: # - dev - # temp only deploy this branch to dev - - TCA-790_assessments + # temp only deploy the release branch to dev + - TCA-832_release - deployProd: context : org-global From a3251b9af79c4a40a63e43d74ba926ce995ae17d Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 14 Dec 2022 14:47:40 -0800 Subject: [PATCH 18/18] TCA-852 Revert dev deploy of feature branch --- .circleci/config.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0059ee051..288a51234 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -227,9 +227,7 @@ workflows: filters: branches: only: - # - dev - # temp only deploy the release branch to dev - - TCA-832_release + - dev - deployProd: context : org-global