1 |
- {"version":3,"file":"static/chunks/22042-838dfd6fdd3687bc.js","mappings":"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","sources":["webpack://_N_E/./src/components/Course/CompletedTick/index.tsx","webpack://_N_E/./src/components/Course/ContentContainer/index.tsx","webpack://_N_E/./src/components/Course/CourseFeedback/index.tsx","webpack://_N_E/./src/components/Course/CourseFeedback/CourseFeedbackForm/index.tsx","webpack://_N_E/./src/components/Course/CourseFeedback/CourseFeedbackModal/index.tsx","webpack://_N_E/./src/components/Course/utils/mutations.ts","webpack://_N_E/./src/components/DataFetcher/index.tsx","webpack://_N_E/./public/icons/retry.svg","webpack://_N_E/./src/components/Error/index.tsx","webpack://_N_E/./src/components/FormBuilder/buildFormBuilderFormField.ts","webpack://_N_E/./src/components/FormBuilder/buildTranslatedErrorMessageByErrorId.ts","webpack://_N_E/./src/components/MarkdownEditor/index.tsx","webpack://_N_E/./src/components/NextSeoWrapper.tsx","webpack://_N_E/./src/components/PageContainer/index.tsx","webpack://_N_E/./src/components/dls/ContentModal/ContentModal.tsx","webpack://_N_E/./src/hooks/useMutateMultipleKeys.ts","webpack://_N_E/./src/hooks/useMutateWithoutRevalidation.ts","webpack://_N_E/./src/utils/string.ts","webpack://_N_E/./types/ErrorMessageId.ts","webpack://_N_E/./src/components/Course/ContentContainer/ContentContainer.module.scss","webpack://_N_E/./src/components/Course/CourseFeedback/CourseFeedback.module.scss","webpack://_N_E/./src/components/Course/CourseFeedback/CourseFeedbackForm/CourseFeedbackForm.module.scss","webpack://_N_E/./src/components/Course/CourseFeedback/CourseFeedbackModal/CourseFeedbackModal.module.scss","webpack://_N_E/./src/components/Error/Error.module.scss","webpack://_N_E/./src/components/MarkdownEditor/MarkdownEditor.module.scss","webpack://_N_E/./src/components/PageContainer/PageContainer.module.scss","webpack://_N_E/./src/components/dls/ContentModal/ContentModal.module.scss","webpack://_N_E/./src/pages/index.module.scss"],"sourcesContent":["import React from 'react';\n\nconst CompletedTick = () => {\n return <span>{` ✔`}</span>;\n};\n\nexport default CompletedTick;\n","import React from 'react';\n\nimport styles from './ContentContainer.module.scss';\n\ntype Props = {\n children: React.ReactNode;\n};\n\nconst ContentContainer: React.FC<Props> = ({ children }) => {\n return <div className={styles.container}>{children}</div>;\n};\n\nexport default ContentContainer;\n","import React, { useEffect, useState } from 'react';\n\nimport useTranslation from 'next-translate/useTranslation';\n\nimport styles from './CourseFeedback.module.scss';\nimport CourseFeedbackModal from './CourseFeedbackModal';\n\nimport Button, { ButtonSize, ButtonType } from '@/dls/Button/Button';\nimport { Course } from '@/types/auth/Course';\nimport { logButtonClick } from '@/utils/eventLogger';\n\ntype Props = {\n course: Course;\n source: FeedbackSource;\n shouldOpenModal?: boolean;\n};\n\nexport enum FeedbackSource {\n CoursePage = 'course_page',\n LessonPage = 'lesson_page',\n}\n\nconst CourseFeedback: React.FC<Props> = ({ source, course, shouldOpenModal = false }) => {\n const { t } = useTranslation('learn');\n const [isModalOpen, setIsModalOpen] = useState(false);\n\n /**\n * listen to changes from the parent component. This will happen when the user\n * completes last lesson of the course.\n */\n useEffect(() => {\n if (shouldOpenModal) {\n setIsModalOpen(true);\n }\n }, [shouldOpenModal]);\n\n const onAddFeedbackClicked = () => {\n logButtonClick('add_course_feedback', {\n source,\n });\n setIsModalOpen(true);\n };\n\n return (\n <div className={styles.container}>\n <Button size={ButtonSize.Small} type={ButtonType.Primary} onClick={onAddFeedbackClicked}>\n {t('feedback.add-feedback')}\n </Button>\n <CourseFeedbackModal\n course={course}\n isOpen={isModalOpen}\n onClose={() => setIsModalOpen(false)}\n />\n </div>\n );\n};\n\nexport default CourseFeedback;\n","import React, { useState } from 'react';\n\nimport useTranslation from 'next-translate/useTranslation';\n\nimport styles from './CourseFeedbackForm.module.scss';\n\nimport {\n mutateCachedCourseAfterFeedback,\n mutateCachedLessonsAfterFeedback,\n} from '@/components/Course/utils/mutations';\nimport buildFormBuilderFormField from '@/components/FormBuilder/buildFormBuilderFormField';\nimport buildTranslatedErrorMessageByErrorId from '@/components/FormBuilder/buildTranslatedErrorMessageByErrorId';\nimport FormBuilder from '@/components/FormBuilder/FormBuilder';\nimport Button from '@/dls/Button/Button';\nimport { ToastStatus, useToast } from '@/dls/Toast/Toast';\nimport useMutateMultipleKeys from '@/hooks/useMutateMultipleKeys';\nimport useMutateWithoutRevalidation from '@/hooks/useMutateWithoutRevalidation';\nimport { Course } from '@/types/auth/Course';\nimport ErrorMessageId from '@/types/ErrorMessageId';\nimport { RuleType } from '@/types/FieldRule';\nimport { FormFieldType } from '@/types/FormField';\nimport { postCourseFeedback } from '@/utils/auth/api';\nimport { logFormSubmission } from '@/utils/eventLogger';\n\ntype Props = {\n course: Course;\n onSuccess: () => void;\n};\n\ntype CourseFeedbackFormData = {\n rating: number;\n body?: string;\n};\n\nconst BODY_MAX_VALIDATION_PARAMS = {\n value: 10000,\n};\n\nconst CourseFeedbackForm: React.FC<Props> = ({ course, onSuccess }) => {\n const { t } = useTranslation('learn');\n const [isLoading, setIsLoading] = useState(false);\n const toast = useToast();\n const mutateWithoutRevalidation = useMutateWithoutRevalidation();\n const mutateMultipleKeys = useMutateMultipleKeys();\n\n const submitFeedback = async (formData: CourseFeedbackFormData) => {\n setIsLoading(true);\n postCourseFeedback({\n courseId: course.id,\n ...formData,\n })\n .then(() => {\n toast(t('feedback.feedback-success'), {\n status: ToastStatus.Success,\n });\n // update local cache to set userHasFeedback to true\n mutateCachedCourseAfterFeedback(mutateWithoutRevalidation, course.slug);\n mutateCachedLessonsAfterFeedback(mutateMultipleKeys, course.slug);\n onSuccess();\n })\n .catch(() => {\n toast(t('common:error.general'), {\n status: ToastStatus.Error,\n });\n })\n .finally(() => {\n setIsLoading(false);\n });\n };\n\n const onSubmit = async (formData: CourseFeedbackFormData) => {\n logFormSubmission('course_feedback', formData);\n submitFeedback(formData);\n };\n\n return (\n <FormBuilder\n formFields={[\n {\n field: 'rating',\n type: FormFieldType.StarRating,\n // user must pick a rating\n defaultValue: null,\n containerClassName: styles.ratingContainer,\n rules: [\n {\n type: RuleType.Required,\n value: true,\n errorId: ErrorMessageId.RequiredField,\n errorMessage: buildTranslatedErrorMessageByErrorId(\n ErrorMessageId.RequiredField,\n 'rating',\n t,\n ),\n },\n ],\n },\n {\n field: 'body',\n placeholder: t('feedback.feedback-placeholder'),\n rules: [\n {\n ...BODY_MAX_VALIDATION_PARAMS,\n type: RuleType.MaximumLength,\n errorId: ErrorMessageId.MaximumLength,\n errorExtraParams: {\n ...BODY_MAX_VALIDATION_PARAMS,\n },\n errorMessage: buildTranslatedErrorMessageByErrorId(\n ErrorMessageId.MaximumLength,\n 'body',\n t,\n {\n ...BODY_MAX_VALIDATION_PARAMS,\n },\n ),\n },\n ],\n type: FormFieldType.TextArea,\n containerClassName: styles.bodyInput,\n fieldSetLegend: t('feedback.your-feedback'),\n },\n ].map((field) => buildFormBuilderFormField(field, t))}\n onSubmit={onSubmit}\n isSubmitting={isLoading}\n renderAction={({ isLoading: isSubmitting }) => {\n return (\n <div className={styles.submitButton}>\n <Button htmlType=\"submit\" isLoading={isSubmitting} isDisabled={isSubmitting}>\n {t('common:submit')}\n </Button>\n </div>\n );\n }}\n />\n );\n};\n\nexport default CourseFeedbackForm;\n","import { useRef } from 'react';\n\nimport Trans from 'next-translate/Trans';\nimport useTranslation from 'next-translate/useTranslation';\n\nimport CourseFeedbackForm from '../CourseFeedbackForm';\n\nimport styles from './CourseFeedbackModal.module.scss';\n\nimport ContentModal, { ContentModalSize } from '@/dls/ContentModal/ContentModal';\nimport ContentModalHandles from '@/dls/ContentModal/types/ContentModalHandles';\nimport { Course } from '@/types/auth/Course';\nimport { Note } from '@/types/auth/Note';\n\ninterface NoteModalProps {\n isOpen: boolean;\n onClose: () => void;\n course: Course;\n onNoteUpdated?: (data: Note) => void;\n onNoteDeleted?: () => void;\n}\n\nconst CourseFeedbackModal: React.FC<NoteModalProps> = ({ onClose, isOpen, course }) => {\n const { t } = useTranslation('learn');\n const contentModalRef = useRef<ContentModalHandles>();\n\n const { title } = course;\n\n return (\n <ContentModal\n innerRef={contentModalRef}\n isOpen={isOpen}\n header={<div className={styles.headerContainer}>{t('feedback.add-feedback')}</div>}\n hasCloseButton\n onClose={onClose}\n onEscapeKeyDown={onClose}\n size={ContentModalSize.MEDIUM}\n >\n <div className={styles.desc}>\n <Trans\n components={{ br: <br /> }}\n i18nKey=\"learn:feedback.desc\"\n values={{\n courseName: title,\n }}\n />\n </div>\n <CourseFeedbackForm onSuccess={onClose} course={course} />\n </ContentModal>\n );\n};\n\nexport default CourseFeedbackModal;\n","import { Course, Lesson } from '@/types/auth/Course';\nimport { makeGetCourseUrl, makeGetLessonUrlPrefix } from '@/utils/auth/apiPaths';\n\n/**\n * Given an ordered list of lessons and a list of completed lessons:\n *\n * – If all of them are completed, return the first\n * - If none of them are completed, return the first\n * - If only some of them are completed, return the 1st uncompleted lesson.\n *\n * @param {Lesson[]} lessons\n *\n * @returns {string}\n */\nexport const getContinueFromLesson = (lessons: Lesson[]): string => {\n if (!lessons) {\n return null;\n }\n const completedLessonIds = lessons\n .filter((lesson) => lesson.isCompleted)\n .map((lesson) => lesson.id);\n const numberOfCompletedLessons = completedLessonIds.length;\n // if no lessons were completed, return the first lesson\n if (numberOfCompletedLessons === 0) {\n return lessons[0].slug;\n }\n // if all lessons were completed, return the first lesson\n if (numberOfCompletedLessons === lessons.length) {\n return lessons[0].slug;\n }\n // 1. make sure the lessons are sorted by day\n const sortedLessons = lessons.sort((a, b) => a.day - b.day);\n // 2. pick first uncompleted lesson\n for (let index = 0; index < sortedLessons.length; index += 1) {\n // if the lessons has not been completed, return in\n if (!completedLessonIds.includes(sortedLessons[index].id)) {\n return sortedLessons[index].slug;\n }\n }\n return null;\n};\n\n/**\n * Given a lessons array and a lesson id, it returns a new lessons array\n * after setting the lesson with the given id set as completed.\n *\n * @param {Lesson[]} lessons\n * @param {string} lessonId\n * @returns {Lesson[]}\n */\nexport const mutateLessonAsCompleted = (lessons: Lesson[], lessonId: string): Lesson[] => {\n const newLessons = [...lessons];\n const lessonIndex = newLessons.findIndex((loopLesson) => loopLesson.id === lessonId);\n // safety check: if the lesson was found in the lessons array, set it as completed\n if (lessonIndex !== -1) {\n newLessons[lessonIndex].isCompleted = true;\n }\n return newLessons;\n};\n\n/**\n * This function receives the cached lesson data and the id of the lesson that was just completed\n * and expects to return the updated lesson data with the lesson marked as completed\n * which will be used to update the local cache without having to call the API again.\n *\n * @param {Lesson} cachedLessonData\n * @param {string} completedLessonId\n * @returns {Lesson}\n */\nexport const getUpdatedLessonDataAfterCompletion = (\n cachedLessonData: Lesson,\n completedLessonId: string,\n): Lesson => {\n if (cachedLessonData) {\n const updatedLessonData = { ...cachedLessonData };\n // only set the completed lesson data to completed\n if (updatedLessonData.id === completedLessonId) {\n updatedLessonData.isCompleted = true;\n }\n // if the lesson has a course, we should update the lessons array of the course\n if (cachedLessonData?.course?.lessons) {\n updatedLessonData.course.lessons = mutateLessonAsCompleted(\n updatedLessonData.course.lessons,\n completedLessonId,\n );\n }\n return updatedLessonData;\n }\n return cachedLessonData;\n};\n\n/**\n * This function receives the cached course data and the id of the lesson that was just completed\n * and expects to return the updated course data with the lesson marked as completed\n * which will be used to update the local cache without having to call the API again.\n *\n * @param {Course} cachedCourseData\n * @param {string} completedLessonId\n * @returns {Course}\n */\nexport const getUpdatedCourseDataAfterCompletion = (\n cachedCourseData: Course,\n completedLessonId: string,\n): Course => {\n if (cachedCourseData) {\n const updatedCourseData = { ...cachedCourseData };\n // if the course has lessons, we should update the lessons array\n if (updatedCourseData?.lessons) {\n const completedLessons = updatedCourseData.lessons.filter(\n (loopLesson) => loopLesson.isCompleted,\n );\n // if we are marking the last un-completed lesson in the course, we should mark the course itself as completed\n if (completedLessons.length + 1 === updatedCourseData.lessons.length) {\n updatedCourseData.isCompleted = true;\n }\n updatedCourseData.lessons = mutateLessonAsCompleted(\n updatedCourseData.lessons,\n completedLessonId,\n );\n updatedCourseData.continueFromLesson = getContinueFromLesson(updatedCourseData.lessons);\n }\n return updatedCourseData;\n }\n return cachedCourseData;\n};\n\n/**\n * we need to update all the cached lessons of the course to set the current lesson as completed\n *\n * @param {any} mutatorFunction\n * @param {string} courseSlug\n * @param {string} completedLessonId\n *\n * @returns {void}\n */\nexport const mutateCachedLessonsAfterCompletion = (\n mutatorFunction: any,\n courseSlug: string,\n completedLessonId: string,\n): void => {\n const courseLessonsUrlRegex = `^${makeGetLessonUrlPrefix(courseSlug)}/.+`;\n mutatorFunction(courseLessonsUrlRegex, (cachedLessonData: Lesson) =>\n getUpdatedLessonDataAfterCompletion(cachedLessonData, completedLessonId),\n );\n};\n\n/**\n * update local cache of the course to set the current lesson as completed in the lessons array\n *\n * @param {any} mutatorFunction\n * @param {string} courseSlug\n * @param {string} completedLessonId\n *\n * @returns {void}\n */\nexport const mutateCachedCourseAfterCompletion = (\n mutatorFunction: any,\n courseSlug: string,\n completedLessonId: string,\n): void => {\n mutatorFunction(makeGetCourseUrl(courseSlug), (cachedCourseData: Course) =>\n getUpdatedCourseDataAfterCompletion(cachedCourseData, completedLessonId),\n );\n};\n\n/**\n * we need to update all the cached lessons of the course to set the current lesson as completed\n *\n * @param {any} mutatorFunction\n * @param {string} courseSlug\n *\n * @returns {void}\n */\nexport const mutateCachedLessonsAfterFeedback = (\n mutatorFunction: any,\n courseSlug: string,\n): void => {\n const courseLessonsUrlRegex = `^${makeGetLessonUrlPrefix(courseSlug)}/.+`;\n mutatorFunction(courseLessonsUrlRegex, (cachedLessonData: Lesson) =>\n getUpdatedLessonDataAfterFeedback(cachedLessonData),\n );\n};\n\n/**\n * update local cache of the course to set the current lesson as completed in the lessons array\n *\n * @param {any} mutatorFunction\n * @param {string} courseSlug\n *\n * @returns {void}\n */\nexport const mutateCachedCourseAfterFeedback = (mutatorFunction: any, courseSlug: string): void => {\n mutatorFunction(makeGetCourseUrl(courseSlug), (cachedCourseData: Course) =>\n getUpdatedCourseDataAfterFeedback(cachedCourseData),\n );\n};\n\n/**\n * This function receives the cached course data and the id of the lesson that was just completed\n * and expects to return the updated course data with the lesson marked as completed\n * which will be used to update the local cache without having to call the API again.\n *\n * @param {Course} cachedCourseData\n * @returns {Course}\n */\nexport const getUpdatedCourseDataAfterFeedback = (cachedCourseData: Course): Course => {\n if (cachedCourseData) {\n const updatedCourseData = { ...cachedCourseData };\n updatedCourseData.userHasFeedback = true;\n return updatedCourseData;\n }\n return cachedCourseData;\n};\n\n/**\n * This function receives the cached lesson data and the id of the lesson that was just completed\n * and expects to return the updated lesson data with the lesson marked as completed\n * which will be used to update the local cache without having to call the API again.\n *\n * @param {Lesson} cachedLessonData\n * @returns {Lesson}\n */\nexport const getUpdatedLessonDataAfterFeedback = (cachedLessonData: Lesson): Lesson => {\n if (cachedLessonData) {\n const updatedLessonData = { ...cachedLessonData };\n // if the lesson has a course, we should update it to userHasFeedback = true\n if (cachedLessonData?.course) {\n updatedLessonData.course = {\n ...updatedLessonData.course,\n userHasFeedback: true,\n };\n }\n return updatedLessonData;\n }\n return cachedLessonData;\n};\n","import React, { memo } from 'react';\n\nimport useSWRImmutable from 'swr/immutable';\n\nimport Error from '@/components/Error';\nimport Spinner from '@/dls/Spinner/Spinner';\nimport { fetcher } from 'src/api';\nimport { BaseResponse } from 'types/ApiResponses';\n\ninterface Props {\n queryKey: string;\n render: (data: BaseResponse) => JSX.Element;\n renderError?: (error: any) => JSX.Element | undefined;\n initialData?: BaseResponse;\n loading?: () => JSX.Element;\n fetcher?: (queryKey: string) => Promise<BaseResponse>;\n showSpinnerOnRevalidate?: boolean;\n onFetchSuccess?: (data: BaseResponse) => void;\n}\n\n/**\n * Data fetcher is a dynamic component that serves as a container for a component\n * that depends on data from a remote API to render. This component handles:\n * 1. Calling the API.\n * 2. Caching the response (due to using useSwr).\n * 3. Handling errors if any by showing an error message.\n * 4. Handling when the user is offline while trying to fetch the API response.\n * 5. Dynamically passing the response data through render-props to the parent.\n *\n * @param {Props} props\n * @returns {JSX.Element}\n */\nconst DataFetcher: React.FC<Props> = ({\n queryKey,\n render,\n renderError,\n initialData,\n loading = () => <Spinner />,\n fetcher: dataFetcher = fetcher,\n showSpinnerOnRevalidate = true,\n onFetchSuccess,\n}: Props): JSX.Element => {\n const { data, error, isValidating, mutate } = useSWRImmutable(\n queryKey,\n () =>\n dataFetcher(queryKey)\n .then((res) => {\n onFetchSuccess?.(res);\n return Promise.resolve(res);\n })\n .catch((err) => Promise.reject(err)),\n {\n fallbackData: initialData,\n },\n );\n\n // if showSpinnerOnRevalidate is true, we should show the spinner if we are revalidating the data.\n // otherwise, we should only show the spinner on initial loads.\n if (showSpinnerOnRevalidate ? isValidating : isValidating && !data) {\n return loading();\n }\n\n const onRetryClicked = () => {\n mutate();\n };\n\n /**\n * if we haven't fetched the data yet and the device is not online (because we don't want to show an offline message if the data already exists).\n * or if we had an error when calling the API.\n */\n if (error) {\n // if there is a custom error renderer, use it.\n if (renderError) {\n const errorComponent = renderError(error);\n // if the custom error renderer returns false, it means that it doesn't want to render anything special.\n if (typeof errorComponent !== 'undefined') {\n return errorComponent;\n }\n }\n return <Error onRetryClicked={onRetryClicked} error={error} />;\n }\n\n return render(data);\n};\n\nexport default memo(DataFetcher);\n","var _path;\nfunction _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }\nimport * as React from \"react\";\nvar SvgRetry = function SvgRetry(props) {\n return /*#__PURE__*/React.createElement(\"svg\", _extends({\n width: 15,\n height: 15,\n viewBox: \"0 0 15 15\",\n fill: \"none\",\n xmlns: \"http://www.w3.org/2000/svg\"\n }, props), _path || (_path = /*#__PURE__*/React.createElement(\"path\", {\n d: \"M1.85 7.5c0-2.835 2.21-5.65 5.65-5.65 2.778 0 4.152 2.056 4.737 3.15H10.5a.5.5 0 0 0 0 1h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-1 0v1.813C12.296 3.071 10.666.85 7.5.85 3.437.85.85 4.185.85 7.5c0 3.315 2.587 6.65 6.65 6.65 1.944 0 3.562-.77 4.714-1.942a6.77 6.77 0 0 0 1.428-2.167.5.5 0 1 0-.925-.38 5.77 5.77 0 0 1-1.216 1.846c-.971.99-2.336 1.643-4.001 1.643-3.44 0-5.65-2.815-5.65-5.65Z\",\n fill: \"currentColor\",\n fillRule: \"evenodd\",\n clipRule: \"evenodd\"\n })));\n};\nexport default SvgRetry;","import React from 'react';\n\nimport useTranslation from 'next-translate/useTranslation';\n\nimport styles from './Error.module.scss';\n\nimport Button, { ButtonSize, ButtonType } from '@/dls/Button/Button';\nimport RetryIcon from '@/icons/retry.svg';\nimport { OFFLINE_ERROR } from 'src/api';\n\ninterface Props {\n onRetryClicked: () => void;\n error: Error;\n}\n\nconst Error: React.FC<Props> = ({ onRetryClicked, error }) => {\n const { t } = useTranslation('common');\n return (\n <div className={styles.container}>\n <p className={styles.text}>\n {error.message !== OFFLINE_ERROR ? t('error.general') : t('error.offline')}\n </p>\n <Button\n prefix={<RetryIcon />}\n size={ButtonSize.Small}\n type={ButtonType.Secondary}\n onClick={onRetryClicked}\n >\n {t('retry')}\n </Button>\n </div>\n );\n};\n\nexport default Error;\n","import capitalize from 'lodash/capitalize';\nimport { Translate } from 'next-translate';\n\nimport { FormBuilderFormField } from './FormBuilderTypes';\n\nimport FormField, { FormFieldType } from 'types/FormField';\n\n/**\n * Transform FormField to be FormBuilderFormField\n *\n * FormField and FormBuilderFormField are the same except, FormBuilderFormField is not tied to errorId and translationId\n * - Previously FormBuilder was tied to common.json, next-translate.\n * - and it's also tied to ErrorMessageId\n * - and the `label` is also less flexible because it's tied to `field` value\n *\n * This function help to transform FormField to FormBuilderFormField for common use case.\n * But when we need a more flexible use case, we can use FormBuilderFormField directly. Without using this helper function\n *\n * check ./FormBuilderTypes.ts for more info\n *\n * Note that this function expect the `t` translate function to be used with `common.json`. And expect `form.$field` and `validation.$errorId` to exist.\n *\n * @param {FormField} formField\n * @returns {FormBuilderFormField} formBuilderFormField\n */\nconst buildFormBuilderFormField = (formField: FormField, t: Translate): FormBuilderFormField => {\n return {\n ...formField,\n ...(formField.rules && {\n rules: formField.rules.map((rule) => ({\n type: rule.type,\n value: rule.value,\n errorMessage: t(`common:validation.${rule.errorId}`, {\n field: capitalize(formField.field),\n ...rule.errorExtraParams,\n }),\n })),\n }),\n ...(formField.label && {\n label:\n formField.type === FormFieldType.Checkbox ? formField.label : t(`form.${formField.label}`),\n }),\n ...(formField.defaultValue && { defaultValue: formField.defaultValue }),\n ...(formField.placeholder && { placeholder: formField.placeholder }),\n };\n};\n\nexport default buildFormBuilderFormField;\n","import capitalize from 'lodash/capitalize';\nimport { Translate } from 'next-translate';\n\nimport ErrorMessageId from 'types/ErrorMessageId';\n\nconst DEFAULT_ERROR_ID = ErrorMessageId.InvalidField;\n\nconst buildTranslatedErrorMessageByErrorId = (\n errorId: ErrorMessageId,\n fieldName: string,\n t: Translate,\n extraParams?: Record<string, unknown>,\n) => {\n if (Object.values(ErrorMessageId).includes(errorId)) {\n return t(`common:validation.${errorId}`, { field: capitalize(fieldName), ...extraParams });\n }\n return t(`common:validation.${DEFAULT_ERROR_ID}`, { field: capitalize(fieldName) });\n};\n\nexport default buildTranslatedErrorMessageByErrorId;\n","import React, { useEffect } from 'react';\n\nimport { defaultValueCtx, Editor, rootCtx, editorViewOptionsCtx } from '@milkdown/core';\nimport { commonmark } from '@milkdown/preset-commonmark';\nimport { Milkdown, useEditor } from '@milkdown/react';\nimport { replaceAll } from '@milkdown/utils';\n\nimport styles from '@/components/MarkdownEditor/MarkdownEditor.module.scss';\n\ntype Props = {\n isEditable?: boolean;\n defaultValue?: string;\n};\n\nconst MarkdownEditor: React.FC<Props> = ({ isEditable = true, defaultValue }) => {\n const { get } = useEditor((root) => {\n return Editor.make()\n .config((ctx) => {\n ctx.set(rootCtx, root);\n if (defaultValue) {\n ctx.set(defaultValueCtx, defaultValue);\n }\n // Add attributes to the editor container\n ctx.update(editorViewOptionsCtx, (prev) => ({\n ...prev,\n editable: () => isEditable,\n attributes: { class: styles.editor, spellcheck: 'false' },\n }));\n })\n .use(commonmark);\n }, []);\n\n useEffect(() => {\n if (defaultValue) {\n get()?.action(replaceAll(defaultValue));\n }\n }, [defaultValue, get]);\n\n return (\n <div className={styles.content}>\n <Milkdown />\n </div>\n );\n};\n\nexport default MarkdownEditor;\n","import React from 'react';\n\nimport { NextSeo } from 'next-seo';\n\nimport { SEOProps } from '@/utils/seo';\nimport { truncateString } from '@/utils/string';\n\ninterface Props extends SEOProps {\n url?: string;\n image?: string;\n imageAlt?: string;\n imageWidth?: number;\n imageHeight?: number;\n}\n\nconst NextSeoWrapper: React.FC<Props> = (props) => {\n const { url, image, imageAlt, imageHeight, imageWidth, openGraph, description, ...rest } = props;\n const openGraphParams = {\n ...(openGraph && { openGraph }),\n ...(url && { url }),\n ...(image && {\n images: [{ url: image, width: imageWidth, height: imageHeight, alt: imageAlt }],\n }),\n };\n const params = {\n ...rest,\n ...(description && { description: truncateString(description, 150) }),\n };\n return <NextSeo {...params} openGraph={openGraphParams} />;\n};\n\nexport default NextSeoWrapper;\n","import { ReactNode, FC } from 'react';\n\nimport styles from './PageContainer.module.scss';\n\ntype Props = {\n children: ReactNode | ReactNode[];\n};\n\nconst PageContainer: FC<Props> = ({ children }) => {\n return <div className={styles.container}>{children}</div>;\n};\n\nexport default PageContainer;\n","import { useRef, useImperativeHandle, ForwardedRef } from 'react';\n\nimport * as Dialog from '@radix-ui/react-dialog';\nimport classNames from 'classnames';\nimport { useRouter } from 'next/router';\n\nimport Button, { ButtonShape, ButtonVariant } from '../Button/Button';\n\nimport styles from './ContentModal.module.scss';\n\nimport ContentModalHandles from '@/dls/ContentModal/types/ContentModalHandles';\nimport CloseIcon from '@/icons/close.svg';\nimport { isRTLLocale } from '@/utils/locale';\n\nexport enum ContentModalSize {\n SMALL = 'small',\n MEDIUM = 'medium',\n}\n\ntype ContentModalProps = {\n isOpen?: boolean;\n onClose?: () => void;\n onEscapeKeyDown?: () => void;\n children: React.ReactNode;\n hasCloseButton?: boolean;\n hasHeader?: boolean;\n header?: React.ReactNode;\n innerRef?: ForwardedRef<ContentModalHandles>;\n // using innerRef instead of using function forwardRef so we can dynamically load this component https://github.com/vercel/next.js/issues/4957#issuecomment-413841689\n contentClassName?: string;\n size?: ContentModalSize;\n isFixedHeight?: boolean;\n};\n\nconst SCROLLBAR_WIDTH = 15;\n\nconst ContentModal = ({\n isOpen,\n onClose,\n onEscapeKeyDown,\n hasCloseButton,\n children,\n header,\n innerRef,\n contentClassName,\n size = ContentModalSize.MEDIUM,\n isFixedHeight,\n hasHeader = true,\n}: ContentModalProps) => {\n const overlayRef = useRef<HTMLDivElement>();\n const { locale } = useRouter();\n\n useImperativeHandle(innerRef, () => ({\n scrollToTop: () => {\n if (overlayRef.current) overlayRef.current.scrollTop = 0;\n },\n }));\n\n /**\n * We need to manually check what the user is targeting. If it lies at the\n * area where the scroll bar is (assuming the scrollbar width is equivalent\n * to SCROLLBAR_WIDTH), then we don't close the Modal, otherwise we do.\n * We also need to check if the current locale is RTL or LTR because the side\n * where the scrollbar is will be different and therefor the value of\n * {e.detail.originalEvent.offsetX} will be different.\n *\n * inspired by {@see https://github.com/radix-ui/primitives/issues/1280#issuecomment-1198248523}\n *\n * @param {any} e\n */\n const onPointerDownOutside = (e: any) => {\n const currentTarget = e.currentTarget as HTMLElement;\n\n const shouldPreventOnClose = isRTLLocale(locale)\n ? e.detail.originalEvent.offsetX < SCROLLBAR_WIDTH // left side of the screen clicked\n : e.detail.originalEvent.offsetX > currentTarget.clientWidth - SCROLLBAR_WIDTH; // right side of the screen clicked\n\n if (shouldPreventOnClose) {\n e.preventDefault();\n return;\n }\n if (onClose) {\n onClose();\n }\n };\n\n return (\n <Dialog.Root open={isOpen}>\n <Dialog.Portal>\n <Dialog.Overlay className={styles.overlay} ref={overlayRef}>\n <Dialog.Content\n className={classNames(styles.contentWrapper, {\n [contentClassName]: contentClassName,\n [styles.small]: size === ContentModalSize.SMALL,\n [styles.medium]: size === ContentModalSize.MEDIUM,\n [styles.autoHeight]: !isFixedHeight,\n })}\n onEscapeKeyDown={onEscapeKeyDown}\n onPointerDownOutside={onPointerDownOutside}\n >\n {hasHeader && (\n <div className={styles.header}>\n {hasCloseButton && (\n <Dialog.Close className={styles.closeIcon}>\n <Button\n variant={ButtonVariant.Ghost}\n shape={ButtonShape.Circle}\n onClick={onClose}\n >\n <CloseIcon />\n </Button>\n </Dialog.Close>\n )}\n {header}\n </div>\n )}\n\n <div className={styles.content}>{children}</div>\n </Dialog.Content>\n </Dialog.Overlay>\n </Dialog.Portal>\n </Dialog.Root>\n );\n};\nexport default ContentModal;\n","import { useCallback } from 'react';\n\nimport { useSWRConfig, MutatorCallback } from 'swr';\n\nimport { NO_REVALIDATION_MUTATOR_OPTIONS } from './useMutateWithoutRevalidation';\n\n/**\n * a hook on top of useSWRConfig.mutate to mutate multiple keys in the cache by matching a regex expression against\n * each of the keys in the cache.\n *\n * Inspired by {@see https://github.com/vercel/swr/discussions/488#discussioncomment-743074}\n *\n * @returns {(url: string, callback: MutatorCallback, options: MutatorOptions) => void} mutateMultipleKeys\n */\nconst useMutateMultipleKeys = (): ((url: string, callback: MutatorCallback) => void) => {\n const { cache, mutate } = useSWRConfig();\n const mutateMultipleKeys = useCallback(\n (regexExpression: string, callback: MutatorCallback) => {\n // @ts-ignore\n const cacheKeys = Array.from(cache.keys());\n const pattern = new RegExp(regexExpression);\n cacheKeys.forEach((key: string) => {\n const keyMatches = pattern.test(key);\n if (keyMatches) {\n mutate(key, callback, NO_REVALIDATION_MUTATOR_OPTIONS);\n }\n });\n },\n\n [cache, mutate],\n );\n return mutateMultipleKeys;\n};\n\nexport default useMutateMultipleKeys;\n","import { useCallback } from 'react';\n\nimport { useSWRConfig, MutatorCallback, MutatorOptions, Key } from 'swr';\n\nexport const NO_REVALIDATION_MUTATOR_OPTIONS: MutatorOptions = { revalidate: false };\n\n/**\n * a hook on top of useSWRConfig.mutate to mutate without revalidation\n *\n * @returns {(url: string, callback: MutatorCallback) => void} mutateWithoutRevalidation\n */\nconst useMutateWithoutRevalidation = (): ((url: Key, callback: MutatorCallback) => void) => {\n const { mutate } = useSWRConfig();\n const mutateWithoutRevalidation = useCallback(\n (url: Key, callback: MutatorCallback) => {\n mutate(url, callback, NO_REVALIDATION_MUTATOR_OPTIONS);\n },\n [mutate],\n );\n return mutateWithoutRevalidation;\n};\n\nexport default useMutateWithoutRevalidation;\n","/**\n * Shorten a text by setting the maximum number of characters\n * by the value of the parameter and adding \"...\" at the end.\n *\n * @param {string} rawString\n * @param {number} length\n * @param {string} suffix\n * @returns {string}\n */\nexport const truncateString = (rawString: string, length: number, suffix = '...'): string => {\n const characters = rawString.split('', length);\n let shortenedText = '';\n for (let index = 0; index < characters.length; index += 1) {\n const character = characters[index];\n if (shortenedText.length === length - 1) {\n shortenedText = `${shortenedText}${character}${suffix}`;\n break;\n }\n shortenedText = `${shortenedText}${character}`;\n }\n return shortenedText;\n};\n\n/**\n * Strip HTML tags from a string.\n *\n * @param {string} rawString\n * @returns {string}\n */\nexport const stripHTMLTags = (rawString: string): string => rawString.replace(/(<([^>]+)>)/gi, '');\n\n/**\n * Convert a slugified collection id to collection id only after\n * removing the slug.\n *\n * @param {string} slugifiedCollectionId\n * @returns {string}\n */\nexport const slugifiedCollectionIdToCollectionId = (slugifiedCollectionId: string): string => {\n if (!slugifiedCollectionId) {\n return '';\n }\n const splits = slugifiedCollectionId.split('-');\n // if there is no slug in the url (collections with a name that cannot be slugified e.g. emoticons)\n if (splits.length === 1) {\n return splits[0];\n }\n return splits[splits.length - 1];\n};\n","enum ErrorMessageId {\n InvalidEmail = 'invalid-email',\n RequiredField = 'required-field',\n InvalidField = 'invalid-field',\n MaximumLength = 'maximum-length',\n MinimumLength = 'minimum-length',\n}\n\nexport default ErrorMessageId;\n","// extracted by mini-css-extract-plugin\nmodule.exports = {\"container\":\"ContentContainer_container__s7dX2\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"container\":\"CourseFeedback_container__iBDGv\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"bodyInput\":\"CourseFeedbackForm_bodyInput__0TtN_\",\"submitButton\":\"CourseFeedbackForm_submitButton__vLdJc\",\"ratingContainer\":\"CourseFeedbackForm_ratingContainer__AF_0R\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"headerContainer\":\"CourseFeedbackModal_headerContainer__pubww\",\"desc\":\"CourseFeedbackModal_desc__UebUq\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"container\":\"Error_container__1m9XV\",\"text\":\"Error_text__yg4kD\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"editor\":\"MarkdownEditor_editor__yKRsX\",\"content\":\"MarkdownEditor_content__4M3H4\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"container\":\"PageContainer_container__1TUET\",\"fullWidth\":\"PageContainer_fullWidth__RU5GM\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"modalContainer\":\"ContentModal_modalContainer__i7bo0\",\"contentContainer\":\"ContentModal_contentContainer___ciX5\",\"overlay\":\"ContentModal_overlay__qZfQY\",\"contentWrapper\":\"ContentModal_contentWrapper__VaiRB\",\"autoHeight\":\"ContentModal_autoHeight__A3IW7\",\"medium\":\"ContentModal_medium__EKB5h\",\"small\":\"ContentModal_small__YBKtM\",\"fadeIn\":\"ContentModal_fadeIn__JGh_A\",\"fadeOut\":\"ContentModal_fadeOut__36m_B\",\"contentIn\":\"ContentModal_contentIn__EAwQw\",\"contentOut\":\"ContentModal_contentOut__2x8WN\",\"closeIcon\":\"ContentModal_closeIcon__xppin\",\"header\":\"ContentModal_header__384F2\",\"content\":\"ContentModal_content__9M2Iy\"};","// extracted by mini-css-extract-plugin\nmodule.exports = {\"pageContainer\":\"index_pageContainer__Pxtn3\",\"loadingContainer\":\"index_loadingContainer__WEZFc\",\"flow\":\"index_flow__rCTR5\",\"flowItem\":\"index_flowItem__GnXWz\",\"additionalVerticalGap\":\"index_additionalVerticalGap__nzYz6\",\"fullWidth\":\"index_fullWidth__1n4ux\"};"],"names":["span","children","div","className","styles","BODY_MAX_VALIDATION_PARAMS","value","course","onSuccess","useTranslation","t","useState","isLoading","setIsLoading","toast","useToast","mutateWithoutRevalidation","useMutateWithoutRevalidation","mutateMultipleKeys","useMutateMultipleKeys","submitFeedback","formData","postCourseFeedback","courseId","id","then","status","ToastStatus","mutateCachedCourseAfterFeedback","slug","mutateCachedLessonsAfterFeedback","catch","finally","onSubmit","logFormSubmission","FormBuilder","formFields","field","type","FormFieldType","defaultValue","containerClassName","rules","RuleType","errorId","ErrorMessageId","errorMessage","buildTranslatedErrorMessageByErrorId","placeholder","errorExtraParams","fieldSetLegend","map","buildFormBuilderFormField","isSubmitting","renderAction","Button","htmlType","isDisabled","onClose","isOpen","contentModalRef","useRef","title","ContentModal","innerRef","header","hasCloseButton","onEscapeKeyDown","size","ContentModalSize","Trans","components","br","i18nKey","values","courseName","CourseFeedbackForm","FeedbackSource","source","shouldOpenModal","isModalOpen","setIsModalOpen","useEffect","ButtonSize","ButtonType","onClick","logButtonClick","CourseFeedbackModal","mutateLessonAsCompleted","lessons","lessonId","newLessons","lessonIndex","findIndex","loopLesson","isCompleted","mutateCachedLessonsAfterCompletion","mutatorFunction","courseSlug","completedLessonId","makeGetLessonUrlPrefix","cachedLessonData","updatedLessonData","getUpdatedLessonDataAfterCompletion","mutateCachedCourseAfterCompletion","makeGetCourseUrl","cachedCourseData","updatedCourseData","filter","length","continueFromLesson","completedLessonIds","lesson","numberOfCompletedLessons","sortedLessons","sort","a","b","day","index","includes","getContinueFromLesson","getUpdatedCourseDataAfterCompletion","getUpdatedLessonDataAfterFeedback","getUpdatedCourseDataAfterFeedback","userHasFeedback","DataFetcher","queryKey","render","renderError","initialData","loading","Spinner","dataFetcher","fetcher","showSpinnerOnRevalidate","onFetchSuccess","useSWRImmutable","res","Promise","resolve","err","reject","fallbackData","data","error","isValidating","mutate","errorComponent","Error","onRetryClicked","memo","_path","_extends","Object","assign","bind","n","e","arguments","r","hasOwnProperty","call","apply","props","width","height","viewBox","fill","xmlns","d","fillRule","clipRule","p","message","OFFLINE_ERROR","prefix","RetryIcon","formField","rule","capitalize","label","DEFAULT_ERROR_ID","fieldName","extraParams","isEditable","useEditor","root","Editor","config","ctx","set","rootCtx","defaultValueCtx","update","editorViewOptionsCtx","prev","editable","attributes","class","spellcheck","use","commonmark","get","action","replaceAll","Milkdown","url","image","imageAlt","imageHeight","imageWidth","openGraph","description","rest","openGraphParams","images","alt","params","truncateString","NextSeo","contentClassName","MEDIUM","isFixedHeight","hasHeader","overlayRef","useRouter","locale","useImperativeHandle","scrollToTop","current","scrollTop","Dialog","open","ref","classNames","SMALL","onPointerDownOutside","currentTarget","isRTLLocale","detail","originalEvent","offsetX","clientWidth","preventDefault","variant","ButtonVariant","shape","ButtonShape","CloseIcon","useSWRConfig","cache","useCallback","regexExpression","callback","cacheKeys","Array","from","keys","pattern","RegExp","forEach","key","test","NO_REVALIDATION_MUTATOR_OPTIONS","revalidate","rawString","suffix","characters","split","shortenedText","character","stripHTMLTags","replace","slugifiedCollectionIdToCollectionId","slugifiedCollectionId","splits","module","exports"],"sourceRoot":""}
|