diff --git a/src-ts/.eslintrc.js b/src-ts/.eslintrc.js index 8fa8cf12d..d80fc63f5 100644 --- a/src-ts/.eslintrc.js +++ b/src-ts/.eslintrc.js @@ -83,12 +83,24 @@ module.exports = { 'jsx-a11y/tabindex-no-positive': [ 'warn' ], + 'newline-per-chained-call': [ + 'error', + { + ignoreChainWithDepth: 1, + } + ], 'max-len': [ 'error', 120, ], 'no-extra-boolean-cast': 'off', 'no-null/no-null': 'error', + 'no-param-reassign': [ + 'error', + { + props: false + } + ], 'no-plusplus': [ 'error', { diff --git a/src-ts/lib/contact-support-form/ContactSupportForm.tsx b/src-ts/lib/contact-support-form/ContactSupportForm.tsx index 6a4c92470..57af39fb9 100644 --- a/src-ts/lib/contact-support-form/ContactSupportForm.tsx +++ b/src-ts/lib/contact-support-form/ContactSupportForm.tsx @@ -1,4 +1,4 @@ -import { Dispatch, FC, SetStateAction, useContext, useEffect, useState } from 'react' +import { Dispatch, FC, SetStateAction, useCallback, useContext, useEffect, useState } from 'react' import { Form, FormDefinition, formGetInputModel, FormInputModel } from '../form' import { LoadingSpinner } from '../loading-spinner' @@ -19,20 +19,28 @@ const ContactSupportForm: FC = (props: ContactSupportFo const { profile }: ProfileContextData = useContext(profileContext) - const [loading, setLoading]: [boolean, Dispatch>] = useState(false) - const [saveOnSuccess, setSaveOnSuccess]: [boolean, Dispatch>] = useState(false) + const [loading, setLoading]: [boolean, Dispatch>] + = useState(false) + const [saveOnSuccess, setSaveOnSuccess]: [boolean, Dispatch>] + = useState(false) useEffect(() => { if (!loading && saveOnSuccess) { props.onSave() } - }, [loading, saveOnSuccess]) + }, [loading, saveOnSuccess, props.onSave]) - function generateRequest(inputs: ReadonlyArray): ContactSupportRequest { - const firstName: string = formGetInputModel(inputs, ContactSupportFormField.first).value as string - const lastName: string = formGetInputModel(inputs, ContactSupportFormField.last).value as string - const email: string = formGetInputModel(inputs, ContactSupportFormField.email).value as string - const question: string = formGetInputModel(inputs, ContactSupportFormField.question).value as string + const generateRequest = useCallback(( + inputs: ReadonlyArray, + ): ContactSupportRequest => { + const firstName: string + = formGetInputModel(inputs, ContactSupportFormField.first).value as string + const lastName: string + = formGetInputModel(inputs, ContactSupportFormField.last).value as string + const email: string + = formGetInputModel(inputs, ContactSupportFormField.email).value as string + const question: string + = formGetInputModel(inputs, ContactSupportFormField.question).value as string return { challengeId: props.workId, email, @@ -41,15 +49,16 @@ const ContactSupportForm: FC = (props: ContactSupportFo lastName, question, } - } + }, [props.workId]) - async function saveAsync(request: ContactSupportRequest): Promise { + const saveAsync = useCallback(async (request: ContactSupportRequest): Promise => { setLoading(true) return contactSupportSubmitRequestAsync(request) .then(() => { setSaveOnSuccess(true) - }).finally(() => setLoading(false)) - } + }) + .finally(() => setLoading(false)) + }, []) const emailElement: JSX.Element | undefined = !!profile?.email ? ( @@ -69,10 +78,10 @@ const ContactSupportForm: FC = (props: ContactSupportFo Hi {' '} {profile?.firstName || 'there'} - , we're here to help. + , we're here to help.

- Please describe what you'd like to discuss, and a + Please describe what you'd like to discuss, and a Topcoder Solutions Expert will email you back {emailElement}  within one business day. diff --git a/src-ts/lib/form/form-groups/form-card-set/FormCardSet.tsx b/src-ts/lib/form/form-groups/form-card-set/FormCardSet.tsx index 59c247986..4f87d118b 100644 --- a/src-ts/lib/form/form-groups/form-card-set/FormCardSet.tsx +++ b/src-ts/lib/form/form-groups/form-card-set/FormCardSet.tsx @@ -27,7 +27,10 @@ const FormCardSet: React.FC = (props: FormCardSetProps) => { return <> } - const iconName: string = `${icon.split('-').map((chunk: string) => chunk.charAt(0).toUpperCase() + chunk.slice(1)).join('')}Icon` + const iconName: string = `${icon.split('-') + .map((chunk: string) => chunk.charAt(0) + .toUpperCase() + chunk.slice(1)) + .join('')}Icon` const IconComponent: React.FC> = IconOutline[iconName as keyof typeof IconOutline] return } diff --git a/src-ts/lib/modals/base-modal/use-fetch-modal-content.tsx b/src-ts/lib/modals/base-modal/use-fetch-modal-content.tsx index 035904cb0..d0c4d5e8a 100644 --- a/src-ts/lib/modals/base-modal/use-fetch-modal-content.tsx +++ b/src-ts/lib/modals/base-modal/use-fetch-modal-content.tsx @@ -1,4 +1,4 @@ -import {Dispatch, SetStateAction, useEffect, useState} from 'react' +import { Dispatch, SetStateAction, useEffect, useState } from 'react' import { xhrGetAsync } from '../../functions' @@ -15,7 +15,8 @@ export function useFetchModalContent(contentUrl?: string, enabled?: boolean): Mo } if (!content) { - xhrGetAsync(contentUrl).then(setContent) + xhrGetAsync(contentUrl) + .then(setContent) } }, [contentUrl, content, enabled]) diff --git a/src-ts/lib/page-footer/PageFooter.tsx b/src-ts/lib/page-footer/PageFooter.tsx index 78e270145..845593322 100644 --- a/src-ts/lib/page-footer/PageFooter.tsx +++ b/src-ts/lib/page-footer/PageFooter.tsx @@ -48,7 +48,8 @@ const PageFooter: FC<{}> = () => {

© - {(new Date()).getFullYear()} + {(new Date()) + .getFullYear()} {' '} Topcoder diff --git a/src-ts/lib/route-provider/router.utils.ts b/src-ts/lib/route-provider/router.utils.ts index 1c2ee3ef9..a5d0bef9b 100644 --- a/src-ts/lib/route-provider/router.utils.ts +++ b/src-ts/lib/route-provider/router.utils.ts @@ -14,5 +14,6 @@ export type LazyLoadType = ( * (while react's `lazy` method only allows to import default exports) */ export const lazyLoad: LazyLoadType = (moduleImport: () => Promise, namedExport: string = 'default') => ( - lazy(() => moduleImport().then(m => ({ default: get(m, namedExport) }))) + lazy(() => moduleImport() + .then(m => ({ default: get(m, namedExport) }))) ) diff --git a/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/markdownRenderer/renderer.tsx b/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/markdownRenderer/renderer.tsx index d69a69afe..aa85ee22e 100644 --- a/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/markdownRenderer/renderer.tsx +++ b/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/markdownRenderer/renderer.tsx @@ -80,17 +80,18 @@ export class Renderer implements MarkdownRenderer { const children: ReturnType = this.groupBy( nodes, options, - ).map(node => { - if (Array.isArray(node)) { - return ( - - {React.Children.map(node, child => child)} - - ) - } + ) + .map(node => { + if (Array.isArray(node)) { + return ( + + {React.Children.map(node, child => child)} + + ) + } - return node - }) + return node + }) return (
@@ -287,7 +288,8 @@ export class Renderer implements MarkdownRenderer { const h: string = marked.parser([token], parserOptions) const level: number = token.depth const title: string = removeLineBreak(stripTag(h, `h${level}`)) - const headingId: string = extractId(h, `h${level}`, index).trim() + const headingId: string = extractId(h, `h${level}`, index) + .trim() options.toc.push({ headingId, @@ -351,12 +353,14 @@ export class Renderer implements MarkdownRenderer { const tag: string = extractTag(html) if (tag) { const isParagraphTag: boolean = tag === MarkdownParagraphTag.p - const isHeaderTag: boolean = Object.values(MarkdownHeaderTag).indexOf(tag as MarkdownHeaderTag) !== -1 + const isHeaderTag: boolean = Object.values(MarkdownHeaderTag) + .indexOf(tag as MarkdownHeaderTag) !== -1 if (isParagraphTag || isHeaderTag) { let id: string | undefined if (isHeaderTag) { token = token as marked.Tokens.Heading - id = extractId(html, `h${token.depth}`, index).trim() + id = extractId(html, `h${token.depth}`, index) + .trim() } return React.createElement(tag, { diff --git a/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/markdownRenderer/util.ts b/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/markdownRenderer/util.ts index 46de0a097..5481c8a3e 100644 --- a/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/markdownRenderer/util.ts +++ b/src-ts/tools/dev-center/dev-center-lib/MarkdownDoc/markdownRenderer/util.ts @@ -30,8 +30,11 @@ export function renderMarkdown( const matchStr: string = matches ? matches[0] : '' return matchStr ? { - s: fromStr.replace(matchStr, '').trimStart(), - title: matchStr.replace(/^#/, '').replace(/`/g, '').trim(), + s: fromStr.replace(matchStr, '') + .trimStart(), + title: matchStr.replace(/^#/, '') + .replace(/`/g, '') + .trim(), } : { title, s } } diff --git a/src-ts/tools/dev-center/dev-center-pages/community-app/landing-page/dev-center-articles-section/CardSection/CardSection.tsx b/src-ts/tools/dev-center/dev-center-pages/community-app/landing-page/dev-center-articles-section/CardSection/CardSection.tsx index 5dc47a7d2..46d76f405 100644 --- a/src-ts/tools/dev-center/dev-center-pages/community-app/landing-page/dev-center-articles-section/CardSection/CardSection.tsx +++ b/src-ts/tools/dev-center/dev-center-pages/community-app/landing-page/dev-center-articles-section/CardSection/CardSection.tsx @@ -33,7 +33,8 @@ const CardSection: FC = () => { return blog } }), - ).then(arr => setArticles(arr)) + ) + .then(arr => setArticles(arr)) }, []) const articleStyles: Array = [ diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-awardedAt-renderer/MemberAwaredAtRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-awardedAt-renderer/MemberAwaredAtRenderer.tsx index 952ba3263..7d80d3cf8 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-awardedAt-renderer/MemberAwaredAtRenderer.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-awardedAt-renderer/MemberAwaredAtRenderer.tsx @@ -12,7 +12,10 @@ const MemberAwaredAtRenderer = (memberAward: MemberBadgeAward): JSX.Element => { } return ( -
{new Date(memberAward.awarded_at).toLocaleString(undefined, dateFormat)}
+
+ {new Date(memberAward.awarded_at) + .toLocaleString(undefined, dateFormat)} +
) } diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/badge-details.functions.ts b/src-ts/tools/gamification-admin/pages/badge-detail/badge-details.functions.ts index d86f98b8f..e979ad0f3 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/badge-details.functions.ts +++ b/src-ts/tools/gamification-admin/pages/badge-detail/badge-details.functions.ts @@ -13,7 +13,8 @@ export async function submitRequestAsync(request: UpdateBadgeRequest): Promise>): string { input.unshift(GamificationConfig.CSV_HEADER) - return input.map(row => row.join(',')).join('\n') + return input.map(row => row.join(',')) + .join('\n') } export async function manualAssignRequestAsync(csv: string): Promise { diff --git a/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx b/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx index 5258b0155..9e6e1d428 100644 --- a/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx +++ b/src-ts/tools/learn/course-certificate/certificate-view/CertificateView.tsx @@ -46,7 +46,8 @@ const CertificateView: FC = (props: CertificateViewProps) const certificateWrapRef: MutableRefObject = useRef() const userName: string = useMemo(() => ( - [props.profile.firstName, props.profile.lastName].filter(Boolean).join(' ') + [props.profile.firstName, props.profile.lastName].filter(Boolean) + .join(' ') || props.profile.handle ), [props.profile.firstName, props.profile.handle, props.profile.lastName]) diff --git a/src-ts/tools/learn/course-certificate/certificate-view/certificate/course-card/CourseCard.tsx b/src-ts/tools/learn/course-certificate/certificate-view/certificate/course-card/CourseCard.tsx index 75b93db0e..aa669788c 100644 --- a/src-ts/tools/learn/course-certificate/certificate-view/certificate/course-card/CourseCard.tsx +++ b/src-ts/tools/learn/course-certificate/certificate-view/certificate/course-card/CourseCard.tsx @@ -26,7 +26,13 @@ const CourseCard: FC = (props: CourseCardProps) => ( Completed - {props.completedDate && textFormatDateLocaleShortString(new Date(props.completedDate))} + + { + props.completedDate && ( + textFormatDateLocaleShortString(new Date(props.completedDate)) + ) + } +
diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx index 93f293b66..0e507be63 100644 --- a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -157,7 +157,9 @@ const FreeCodeCamp: FC<{}> = () => { function handleFccLessonReady(lessonPath: string): void { - const [nLessonPath, modulePath, coursePath]: Array = lessonPath.replace(/\/$/, '').split('/').reverse() + const [nLessonPath, modulePath, coursePath]: Array = lessonPath.replace(/\/$/, '') + .split('/') + .reverse() updatePath(nLessonPath, modulePath, coursePath) const currentLesson: { [key: string]: string } = { @@ -206,7 +208,8 @@ const FreeCodeCamp: FC<{}> = () => { certificateProgress.id, UserCertificationUpdateProgressActions.completeLesson, currentLesson, - ).then(setCertificateProgress) + ) + .then(setCertificateProgress) } } diff --git a/src-ts/tools/learn/learn-lib/course-outline/collapsible-item/CollapsibleItem.tsx b/src-ts/tools/learn/learn-lib/course-outline/collapsible-item/CollapsibleItem.tsx index 66a1dde65..f252a12b7 100644 --- a/src-ts/tools/learn/learn-lib/course-outline/collapsible-item/CollapsibleItem.tsx +++ b/src-ts/tools/learn/learn-lib/course-outline/collapsible-item/CollapsibleItem.tsx @@ -18,7 +18,7 @@ interface CollapsibleItemProps { active?: string duration: LearnModule['meta']['estimatedCompletionTime'] isAssessment: boolean - itemId?: (item: any) => string + itemId?: (item: CollapsibleListItem) => string items: Array lessonsCount: number moduleKey: string @@ -30,52 +30,67 @@ interface CollapsibleItemProps { } const CollapsibleItem: FC = (props: CollapsibleItemProps) => { - const [isOpen, setIsOpen]: [boolean, Dispatch>] = useState(false) + const [isOpen, setIsOpen]: [ + boolean, + Dispatch> + ] = useState(false) const toggle: () => void = useCallback(() => { setIsOpen(open => !open) }, []) - const progress: LearnModuleProgress | undefined = useMemo(() => props.progress?.find(m => m.module === props.moduleKey), [props.progress, props.moduleKey]) + const progress: LearnModuleProgress | undefined = useMemo(() => ( + props.progress?.find(m => m.module === props.moduleKey) + ), [props.progress, props.moduleKey]) - const isCompleted: boolean = useMemo(() => !!progress && progress.lessonCount === progress?.completedLessons.length, [progress]) + const isCompleted: boolean = useMemo(() => ( + !!progress && progress.lessonCount === progress?.completedLessons.length + ), [progress]) - const isPartial: boolean = useMemo(() => !!progress && !!progress.completedLessons.length, [progress]) + const isPartial: boolean = useMemo(() => ( + !!progress && !!progress.completedLessons.length + ), [progress]) const isItemCompleted: (key: string) => boolean = (key: string) => ( !!progress?.completedLessons.find(l => l.dashedName === key) ) - const stepLabel: (item: any, isActive: boolean, stepCount: string, label?: string) => ReactNode - = (item: any, isActive: boolean, stepCount: string, label?: string) => ( - - ) - - const renderListItem: (item: any) => ReactNode = (item: any) => { - const isActive: boolean = props.itemId?.(item) === props.active - const stepCount: string = item.dashedName.match(/^step-(\d+)$/i)?.[1] - const label: ReactNode = stepLabel(item, isActive, stepCount, !stepCount && item.title) - const key: string = props.itemId?.(item) ?? item.title - - return ( -
  • props.onItemClick(item)} - > - {props.path ? ( - - {label} - - ) : label} -
  • + const stepLabel: ( + item: CollapsibleListItem, + isActive: boolean, + stepCount?: string, + label?: string + ) => ReactNode + = (item: CollapsibleListItem, isActive: boolean, stepCount?: string, label?: string) => ( + ) - } + + const renderListItem: (item: CollapsibleListItem) => ReactNode + = (item: CollapsibleListItem) => { + const isActive: boolean = props.itemId?.(item) === props.active + const stepCount: string | undefined = item.dashedName.match(/^step-(\d+)$/i)?.[1] + const label: ReactNode = stepLabel(item, isActive, stepCount, !stepCount && item.title) + const key: string = props.itemId?.(item) ?? item.title + + return ( +
  • props.onItemClick(item)} + > + {props.path ? ( + + {label} + + ) : label} +
  • + ) + } return (
    diff --git a/src-ts/tools/learn/learn-lib/course-outline/status-icon/StatusIcon.tsx b/src-ts/tools/learn/learn-lib/course-outline/status-icon/StatusIcon.tsx index d1c2fee91..bc4dc7ef3 100755 --- a/src-ts/tools/learn/learn-lib/course-outline/status-icon/StatusIcon.tsx +++ b/src-ts/tools/learn/learn-lib/course-outline/status-icon/StatusIcon.tsx @@ -18,13 +18,17 @@ const StatusIcon: FC = (props: StatusIconProps) => { props.partial && 'partial', ) - const icon: ReactNode = useMemo(() => ( - props.completed - ? - : props.partial - ? - : - ), [props.completed, props.partial]) + const icon: ReactNode = useMemo(() => { + if (props.completed) { + return + } + + if (props.partial) { + return + } + + return + }, [props.completed, props.partial]) return (
    diff --git a/src-ts/tools/learn/learn-lib/course-outline/step-icon/StepIcon.tsx b/src-ts/tools/learn/learn-lib/course-outline/step-icon/StepIcon.tsx index 1a861c0a2..74c0551f8 100755 --- a/src-ts/tools/learn/learn-lib/course-outline/step-icon/StepIcon.tsx +++ b/src-ts/tools/learn/learn-lib/course-outline/step-icon/StepIcon.tsx @@ -8,7 +8,7 @@ import styles from './StepIcon.module.scss' interface StepIconProps { active?: boolean completed?: boolean - index: string + index?: string label?: string } diff --git a/src-ts/tools/learn/learn-lib/data-providers/all-certifications-provider/all-certifications.provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/all-certifications-provider/all-certifications.provider.tsx index 7eb1f8ea2..69644786d 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/all-certifications-provider/all-certifications.provider.tsx +++ b/src-ts/tools/learn/learn-lib/data-providers/all-certifications-provider/all-certifications.provider.tsx @@ -1,3 +1,4 @@ +/* eslint-disable default-param-last */ import useSWR, { SWRConfiguration, SWRResponse } from 'swr' import { learnUrlGet } from '../../functions' @@ -11,16 +12,16 @@ interface CertificationsAllProviderOptions { export function useGetAllCertifications( providerName: string = 'freeCodeCamp', - options?: CertificationsAllProviderOptions + options?: CertificationsAllProviderOptions, ): AllCertificationsProviderData { const url: string = learnUrlGet( 'certifications', - `?providerName=${providerName}` + `?providerName=${providerName}`, ) const swrCacheConfig: SWRConfiguration = useSwrCache(url) - const {data, error}: SWRResponse = useSWR(url, { + const { data, error }: SWRResponse = useSWR(url, { ...swrCacheConfig, isPaused: () => options?.enabled === false, }) @@ -36,16 +37,16 @@ export function useGetAllCertifications( export function useGetCertification( providerName: string = 'freeCodeCamp', certificationId: string, - options?: CertificationsAllProviderOptions + options?: CertificationsAllProviderOptions, ): AllCertificationsProviderData { const url: string = learnUrlGet( 'certifications', certificationId, - `?providerName=${providerName}` + `?providerName=${providerName}`, ) - const {data, error}: SWRResponse = useSWR(url, { + const { data, error }: SWRResponse = useSWR(url, { isPaused: () => options?.enabled === false, }) return { diff --git a/src-ts/tools/learn/learn-lib/data-providers/courses-provider/courses.provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/courses-provider/courses.provider.tsx index 304b53e96..af4a5e52d 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/courses-provider/courses.provider.tsx +++ b/src-ts/tools/learn/learn-lib/data-providers/courses-provider/courses.provider.tsx @@ -9,7 +9,7 @@ import { LearnCourse } from './learn-course.model' export function useGetCourses( provider: string, - certification?: string + certification?: string, ): CoursesProviderData { const params: string = [ @@ -22,7 +22,7 @@ export function useGetCourses( const url: string = learnUrlGet('courses', `?${params}`) const swrCacheConfig: SWRConfiguration = useSwrCache(url) - const {data, error}: SWRResponse> = useSWR(url, swrCacheConfig) + const { data, error }: SWRResponse> = useSWR(url, swrCacheConfig) return { course: get(data, [0]), diff --git a/src-ts/tools/learn/learn-lib/data-providers/lesson-provider/lesson.provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/lesson-provider/lesson.provider.tsx index ed1f00879..ee1b20128 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/lesson-provider/lesson.provider.tsx +++ b/src-ts/tools/learn/learn-lib/data-providers/lesson-provider/lesson.provider.tsx @@ -21,7 +21,9 @@ export function useGetLesson( courseData?.key ?? course, module, lesson, - ].filter(Boolean).join('/') + ] + .filter(Boolean) + .join('/') return { lesson: !lessonData ? undefined : { diff --git a/src-ts/tools/learn/learn-lib/data-providers/resource-provider-provider/resource-provider.provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/resource-provider-provider/resource-provider.provider.tsx index a100e0ffc..e3de332bc 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/resource-provider-provider/resource-provider.provider.tsx +++ b/src-ts/tools/learn/learn-lib/data-providers/resource-provider-provider/resource-provider.provider.tsx @@ -12,11 +12,11 @@ export function useGetResourceProvider(providerName?: string): ResourceProviderD const url: string = learnUrlGet('providers') const swrCacheConfig: SWRConfiguration = useSwrCache(url) - const {data, error}: SWRResponse> = useSWR(url, swrCacheConfig) + const { data, error }: SWRResponse> = useSWR(url, swrCacheConfig) return { loading: !data && !error, - provider: find(data, {name: providerName}), + provider: find(data, { name: providerName }), ready: !!data || !!error, } } 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 949505428..7bffd5039 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 @@ -9,7 +9,7 @@ import { LearnUserCertificationProgress } from './user-certifications-functions' export function useGetUserCertificationProgress( userId?: number, provider?: string, - certification?: string + certification?: string, ): UserCertificationProgressProviderData { @@ -28,10 +28,10 @@ export function useGetUserCertificationProgress( }) return { - certificationProgress: find(data, {certification}), + certificationProgress: find(data, { certification }), loading: !!userId && !data && !error, ready: !userId || data || error, refetch: () => mutate(), - setCertificateProgress: (progress) => mutate([progress]), + setCertificateProgress: progress => mutate([progress]), } } diff --git a/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certifications-functions/user-certification-progress.store.ts b/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certifications-functions/user-certification-progress.store.ts index 64da7feeb..29ecd99d1 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certifications-functions/user-certification-progress.store.ts +++ b/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certifications-functions/user-certification-progress.store.ts @@ -7,6 +7,8 @@ import { UserCertificationUpdateProgressActions } from './user-certification-upd const certProgressPath: string = 'certification-progresses' +type GenericDataObject = { [key: string]: string | GenericDataObject } + export function completeCourse( certificationProgressId: string, certification: string, @@ -15,8 +17,9 @@ export function completeCourse( ): Promise { // construct the certificate params - const certificateAlternateParams: { [key: string]: string } = LearnConfig.CERT_ALT_PARAMS - const certificateElement: string = `[${LearnConfig.CERT_ELEMENT_SELECTOR.attribute}=${LearnConfig.CERT_ELEMENT_SELECTOR.value}]` + const certificateAlternateParams: GenericDataObject = LearnConfig.CERT_ALT_PARAMS + const certificateElement: string + = `[${LearnConfig.CERT_ELEMENT_SELECTOR.attribute}=${LearnConfig.CERT_ELEMENT_SELECTOR.value}]` const certificateUrl: string = getUserCertificateUrl(provider, certification, handle) return updateAsync( @@ -30,7 +33,12 @@ export function completeCourse( ) } -export function startAsync(userId: number, certificationId: string, courseId: string, data: any): Promise { +export function startAsync( + userId: number, + certificationId: string, + courseId: string, + data: any, +): Promise { const url: string = learnUrlGet(certProgressPath, `${userId}`, certificationId, courseId) return learnXhrPostAsync<{}, LearnUserCertificationProgress>(url, {}, { params: data }) @@ -39,7 +47,7 @@ export function startAsync(userId: number, certificationId: string, courseId: st export function updateAsync( certificationProgressId: string, action: UserCertificationUpdateProgressActions, - data: any, + data: GenericDataObject, ): Promise { const url: string = learnUrlGet(certProgressPath, certificationProgressId, action) diff --git a/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certifications.provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certifications.provider.tsx index 529f22aa6..f71451d03 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certifications.provider.tsx +++ b/src-ts/tools/learn/learn-lib/data-providers/user-certifications-provider/user-certifications.provider.tsx @@ -29,17 +29,25 @@ export function useGetUserCertifications( }) const loading: boolean = !data && !error - const completed: ReadonlyArray = useMemo(() => data - ?.filter(c => c.status === UserCertificationProgressStatus.completed) - .map(c => c as UserCertificationCompleted) - .sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) ?? [] - , [data]) - - const inProgress: ReadonlyArray = useMemo(() => data - ?.filter(c => c.status === UserCertificationProgressStatus.inProgress) - .map(c => c as UserCertificationInProgress) - .sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) ?? [] - , [data]) + const completed: ReadonlyArray = useMemo( + () => data + ?.filter(c => c.status === UserCertificationProgressStatus.completed) + .map(c => c as UserCertificationCompleted) + .sort((a, b) => new Date(b.updatedAt) + .getTime() - new Date(a.updatedAt) + .getTime()) ?? [], + [data], + ) + + const inProgress: ReadonlyArray = useMemo( + () => data + ?.filter(c => c.status === UserCertificationProgressStatus.inProgress) + .map(c => c as UserCertificationInProgress) + .sort((a, b) => new Date(b.updatedAt) + .getTime() - new Date(a.updatedAt) + .getTime()) ?? [], + [data], + ) if (error) { errorHandle(error, 'There was an error getting your course progress.') diff --git a/src-ts/tools/learn/learn-lib/data-providers/user-completed-certifications-provider/user-completed-certifications.provider.tsx b/src-ts/tools/learn/learn-lib/data-providers/user-completed-certifications-provider/user-completed-certifications.provider.tsx index 7a44f8ddb..5e56ea7cf 100644 --- a/src-ts/tools/learn/learn-lib/data-providers/user-completed-certifications-provider/user-completed-certifications.provider.tsx +++ b/src-ts/tools/learn/learn-lib/data-providers/user-completed-certifications-provider/user-completed-certifications.provider.tsx @@ -8,20 +8,19 @@ import { UserCompletedCertificationsProviderData } from './user-completed-certif export function useGetUserCompletedCertifications( userId?: number, provider?: string, - certification?: string + certification?: string, ): UserCompletedCertificationsProviderData { const url: string = learnUrlGet('completed-certifications', `${userId}`) - const {data, error}: SWRResponse> = useSWR(url) + const { data, error }: SWRResponse> = useSWR(url) let certifications: ReadonlyArray = data ?? [] if (provider || certification) { - certifications = certifications.filter((c) => { - return (!provider || c.provider === provider) && - (!certification || c.certification === certification) - }) + certifications = certifications + .filter(c => (!provider || c.provider === provider) + && (!certification || c.certification === certification)) } return { diff --git a/src-ts/tools/learn/learn-lib/functions/learn-xhr.functions.ts b/src-ts/tools/learn/learn-lib/functions/learn-xhr.functions.ts index e9ab61dc7..e77a3ebbe 100644 --- a/src-ts/tools/learn/learn-lib/functions/learn-xhr.functions.ts +++ b/src-ts/tools/learn/learn-lib/functions/learn-xhr.functions.ts @@ -2,7 +2,7 @@ import { AxiosInstance, AxiosRequestConfig } from 'axios' import { xhrCreateInstance, xhrGetAsync, xhrPostAsync, xhrPutAsync } from '../../../../lib' -import { create as learnCreate } from './learn.factory' +import { create as learnCreate, LearnResponseModel } from './learn.factory' const learnXhrInstance: AxiosInstance = xhrCreateInstance() @@ -10,12 +10,12 @@ const learnXhrInstance: AxiosInstance = xhrCreateInstance() learnXhrInstance.interceptors.response .use(response => { - if (response.data?.hasOwnProperty('createdAt')) { + if (Object.prototype.hasOwnProperty.call(response.data, 'createdAt')) { response.data = learnCreate(response.data) } else if (response.data?.constructor?.name === 'Array') { response.data = response.data - .map((item: any) => learnCreate(item)) + .map((item: T) => learnCreate(item)) } return response @@ -25,10 +25,18 @@ export async function getAsync(url: string): Promise { return xhrGetAsync(url, learnXhrInstance) } -export async function postAsync(url: string, data: T, config?: AxiosRequestConfig): Promise { +export async function postAsync( + url: string, + data: T, + config?: AxiosRequestConfig, +): Promise { return xhrPostAsync(url, data, config, learnXhrInstance) } -export async function putAsync(url: string, data: T, config?: AxiosRequestConfig): Promise { +export async function putAsync( + url: string, + data: T, + config?: AxiosRequestConfig, +): Promise { return xhrPutAsync(url, data, config, learnXhrInstance) } diff --git a/src-ts/tools/learn/learn-lib/functions/learn.factory.ts b/src-ts/tools/learn/learn-lib/functions/learn.factory.ts index e7122f84b..33e433774 100644 --- a/src-ts/tools/learn/learn-lib/functions/learn.factory.ts +++ b/src-ts/tools/learn/learn-lib/functions/learn.factory.ts @@ -1,4 +1,4 @@ -interface LearnResponseModel { +export interface LearnResponseModel { createdAt?: string | Date publishedAt?: string | Date updatedAt?: string | Date diff --git a/src-ts/tools/learn/learn-lib/learn-swr/LearnSwr.tsx b/src-ts/tools/learn/learn-lib/learn-swr/LearnSwr.tsx index 532fdd52a..847de317b 100644 --- a/src-ts/tools/learn/learn-lib/learn-swr/LearnSwr.tsx +++ b/src-ts/tools/learn/learn-lib/learn-swr/LearnSwr.tsx @@ -7,20 +7,17 @@ interface LearnSwrProps { children: ReactNode } -const LearnSwr: FC = (props: LearnSwrProps) => { - - return ( - learnXhrGetAsync(resource), - refreshInterval: 0, - revalidateOnFocus: false, - revalidateOnMount: true, - }} - > - {props.children} - - ) -} +const LearnSwr: FC = (props: LearnSwrProps) => ( + learnXhrGetAsync(resource), + refreshInterval: 0, + revalidateOnFocus: false, + revalidateOnMount: true, + }} + > + {props.children} + +) export default LearnSwr diff --git a/src-ts/tools/learn/learn-lib/learn-swr/use-swr-cache.tsx b/src-ts/tools/learn/learn-lib/learn-swr/use-swr-cache.tsx index 2e13c599e..67701fb1a 100644 --- a/src-ts/tools/learn/learn-lib/learn-swr/use-swr-cache.tsx +++ b/src-ts/tools/learn/learn-lib/learn-swr/use-swr-cache.tsx @@ -10,9 +10,10 @@ if (typeof window !== 'undefined') { // parse the loaded data, and load it into swr's in-memory cache if (cacheMap) { - Object.entries(cacheMap).forEach(([key, data]) => { - mutate(key, data, {revalidate: false}) - }) + Object.entries(cacheMap) + .forEach(([key, data]) => { + mutate(key, data, { revalidate: false }) + }) } } diff --git a/src-ts/tools/learn/learn-lib/my-course-card/completed/Completed.tsx b/src-ts/tools/learn/learn-lib/my-course-card/completed/Completed.tsx index 6bdccd3b1..6813bc99d 100644 --- a/src-ts/tools/learn/learn-lib/my-course-card/completed/Completed.tsx +++ b/src-ts/tools/learn/learn-lib/my-course-card/completed/Completed.tsx @@ -8,7 +8,7 @@ import { getCertificatePath, getCoursePath } from '../../../learn.routes' import styles from './Completed.module.scss' interface CompletedProps { - certification: LearnCertification + certification?: LearnCertification completed: string } @@ -38,13 +38,23 @@ const Completed: FC = (props: CompletedProps) => { size='xs' buttonStyle='secondary' label='View Course' - route={getCoursePath(props.certification.providerName, props.certification.certification)} + route={ + getCoursePath( + props.certification.providerName, + props.certification.certification, + ) + } />
    diff --git a/src-ts/tools/learn/learn-lib/wave-hero/WaveHero.tsx b/src-ts/tools/learn/learn-lib/wave-hero/WaveHero.tsx index 1ba945333..51b6ca8af 100755 --- a/src-ts/tools/learn/learn-lib/wave-hero/WaveHero.tsx +++ b/src-ts/tools/learn/learn-lib/wave-hero/WaveHero.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames' import styles from './WaveHero.module.scss' interface WaveHeroProps { - children?: ReactNode + children?: JSX.Element|Array text: string theme?: 'light' title: ReactNode diff --git a/src-ts/tools/learn/learn.routes.tsx b/src-ts/tools/learn/learn.routes.tsx index 03d379b7e..e0627a75e 100644 --- a/src-ts/tools/learn/learn.routes.tsx +++ b/src-ts/tools/learn/learn.routes.tsx @@ -22,6 +22,9 @@ export enum LEARN_PATHS { startCourseRouteFlag = 'start-course', } +export const rootRoute: string = LEARN_PATHS.root +export const absoluteRootRoute: string = `${window.location.origin}${LEARN_PATHS.root}` + export function getAuthenticateAndStartCourseRoute(): string { return `${authUrlLogin()}${encodeURIComponent(`?${LEARN_PATHS.startCourseRouteFlag}`)}` } @@ -58,11 +61,20 @@ export function getLessonPathFromModule( return `${getCoursePath(provider, certification)}/${module}/${lesson}` } -export function getUserCertificateSsr(provider: string, certification: string, handle: string, title: string): string { +export function getUserCertificateSsr( + provider: string, + certification: string, + handle: string, + title: string, +): string { return `${LearnConfig.CERT_DOMAIN}/${handle}/${provider}/${certification}/${encodeURI(title)}` } -export function getUserCertificateUrl(provider: string, certification: string, handle: string): string { +export function getUserCertificateUrl( + provider: string, + certification: string, + handle: string, +): string { return `${window.location.origin}${getCoursePath(provider, certification)}/${handle}${LEARN_PATHS.certificate}` } @@ -70,9 +82,6 @@ export function getViewStyleParamKey(): string { return Object.keys(LearnConfig.CERT_ALT_PARAMS)[0] } -export const rootRoute: string = LEARN_PATHS.root -export const absoluteRootRoute: string = `${window.location.origin}${LEARN_PATHS.root}` - export const learnRoutes: Array = [ { children: [ diff --git a/src-ts/tools/learn/my-learning/MyLearning.tsx b/src-ts/tools/learn/my-learning/MyLearning.tsx index 9639b4db3..132961678 100755 --- a/src-ts/tools/learn/my-learning/MyLearning.tsx +++ b/src-ts/tools/learn/my-learning/MyLearning.tsx @@ -42,7 +42,6 @@ const MyLearning: FC<{}> = () => { const certificatesById: CertificatesByIdType = useMemo(() => ( certifications.reduce((certifs, certificate) => { - // eslint-disable-next-line no-param-reassign certifs[certificate.id] = certificate return certifs }, {} as unknown as CertificatesByIdType) diff --git a/src-ts/tools/learn/my-learning/my-tabs-navbar/MyTabsNavbar.tsx b/src-ts/tools/learn/my-learning/my-tabs-navbar/MyTabsNavbar.tsx index 7e0d138e3..684190deb 100644 --- a/src-ts/tools/learn/my-learning/my-tabs-navbar/MyTabsNavbar.tsx +++ b/src-ts/tools/learn/my-learning/my-tabs-navbar/MyTabsNavbar.tsx @@ -12,9 +12,8 @@ interface MyTabsNavbarProps { } const MyTabsNavbar: FC = (props: MyTabsNavbarProps) => { - const [activeTab, setActiveTab]: [MyTabsViews, Dispatch>] = useState( - MyTabsViews.inProgress, - ) + const [activeTab, setActiveTab]: [MyTabsViews, Dispatch>] + = useState(MyTabsViews.inProgress) const tabs: ReadonlyArray = useMemo(() => getMyTabsNavbarTabs( props.completed, diff --git a/src-ts/tools/learn/my-learning/tab-content-layout/TabContentLayout.tsx b/src-ts/tools/learn/my-learning/tab-content-layout/TabContentLayout.tsx index 1ce9bc74d..7ef58b15c 100644 --- a/src-ts/tools/learn/my-learning/tab-content-layout/TabContentLayout.tsx +++ b/src-ts/tools/learn/my-learning/tab-content-layout/TabContentLayout.tsx @@ -37,10 +37,12 @@ const TabContentLayout: FC = (props: TabContentLayoutProp const certsByCategory: Dictionary> = groupBy(props.certifications, 'category') return [ { label: 'All Categories', value: '' }, - ...Object.keys(certsByCategory).sort().map(c => ({ - label: c, - value: c, - })), + ...Object.keys(certsByCategory) + .sort() + .map(c => ({ + label: c, + value: c, + })), ] }, [props.certifications]) diff --git a/src-ts/tools/learn/welcome/available-courses-list/AvailableCoursesList.tsx b/src-ts/tools/learn/welcome/available-courses-list/AvailableCoursesList.tsx index 590e0b8b9..0880424e3 100644 --- a/src-ts/tools/learn/welcome/available-courses-list/AvailableCoursesList.tsx +++ b/src-ts/tools/learn/welcome/available-courses-list/AvailableCoursesList.tsx @@ -1,5 +1,5 @@ import { Dictionary, groupBy, identity, orderBy } from 'lodash' -import { Dispatch, FC, Fragment, SetStateAction, useMemo } from 'react' +import { Dispatch, FC, Fragment, ReactNode, SetStateAction, useMemo } from 'react' import classNames from 'classnames' import { InputSelect, useLocalStorage } from '../../../../lib' @@ -34,20 +34,48 @@ const AvailableCoursesList: FC = (props: AvailableCou label: string, value: string, }> = useMemo(() => [ - { label: 'All Categories', value: '', orderIndex: -1 }, - ...Object.keys(certsByCategory).sort().map(c => ({ - label: c, - value: c, - })), + { label: 'All Categories', orderIndex: -1, value: '' }, + ...Object.keys(certsByCategory) + .sort() + .map(c => ({ + label: c, + value: c, + })), ], [certsByCategory]) // create and sort the certificates groups - const certificationsGroups: Array = useMemo(() => orderBy(Object.keys(certsByCategory), [ - c => (PRIORITY_CATEGORIES.includes(c) ? -1 : 1), - identity, - ], ['asc', 'asc']), [certsByCategory]) + const certificationsGroups: Array = useMemo(() => orderBy( + Object.keys(certsByCategory), + [ + c => (PRIORITY_CATEGORIES.includes(c) ? -1 : 1), + identity, + ], + ['asc', 'asc'], + ), [certsByCategory]) - const certificationsCount: number = (certsByCategory[selectedCategory] ?? props.certifications).length + const certificationsCount: number = ( + (certsByCategory[selectedCategory] ?? props.certifications).length + ) + + const renderCertificationGroup = (category: string): ReactNode => ( + +

    + {category} +

    + +
    + {certsByCategory[category] + .map(certification => ( + + ))} +
    +
    + ) return (
    @@ -70,24 +98,9 @@ const AvailableCoursesList: FC = (props: AvailableCou
    - {certificationsGroups.map(category => (!selectedCategory || selectedCategory === category) && ( - -

    - {category} -

    - -
    - {certsByCategory[category] - .map(certification => ( - - ))} -
    -
    + {certificationsGroups.map(category => ( + (!selectedCategory || selectedCategory === category) + && renderCertificationGroup(category) ))} ) diff --git a/src-ts/tools/learn/welcome/courses-card/CoursesCard.tsx b/src-ts/tools/learn/welcome/courses-card/CoursesCard.tsx index 8d18eb744..0f1364e81 100644 --- a/src-ts/tools/learn/welcome/courses-card/CoursesCard.tsx +++ b/src-ts/tools/learn/welcome/courses-card/CoursesCard.tsx @@ -52,7 +52,8 @@ const CoursesCard: FC = (props: CoursesCardProps) => { )) } else if (!inProgress) { - // if there is no in-progress lesson for the course, Get Started by going to the course details + // if there is no in-progress lesson for the course, + // Get Started by going to the course details setButtonLabel('Get Started') setLink(getCoursePath( props.certification.providerName, @@ -60,7 +61,8 @@ const CoursesCard: FC = (props: CoursesCardProps) => { )) } else { - // otherwise this course is in-progress, so Resume the course at the next lesson + // otherwise this course is in-progress, + // so Resume the course at the next lesson setButtonStyle('secondary') setButtonLabel('Resume') setLink(getLessonPathFromCurrentLesson( diff --git a/src-ts/tools/learn/welcome/progress-block/ProgressBlock.tsx b/src-ts/tools/learn/welcome/progress-block/ProgressBlock.tsx index 5d996b15b..c4ab318b1 100644 --- a/src-ts/tools/learn/welcome/progress-block/ProgressBlock.tsx +++ b/src-ts/tools/learn/welcome/progress-block/ProgressBlock.tsx @@ -23,7 +23,9 @@ const ProgressBlock: FC = (props: ProgressBlockProps) => { return <> } - const isStarted: boolean = !!props.userInProgressCertifications.length || !!props.userCompletedCertifications.length + const isStarted: boolean = ( + !!props.userInProgressCertifications.length || !!props.userCompletedCertifications.length + ) return (
    diff --git a/src-ts/tools/learn/welcome/progress-block/cards-slider/CardsSlider.tsx b/src-ts/tools/learn/welcome/progress-block/cards-slider/CardsSlider.tsx index f60a0fa09..7b4c9a55b 100644 --- a/src-ts/tools/learn/welcome/progress-block/cards-slider/CardsSlider.tsx +++ b/src-ts/tools/learn/welcome/progress-block/cards-slider/CardsSlider.tsx @@ -11,34 +11,39 @@ interface CardsSliderProps { const CardsSlider: FC = (props: CardsSliderProps) => { const [activeSlide, setActiveSlide]: [number, Dispatch>] = useState(0) - const wrapSlides: (children: Array) => Array = (children: Array) => Children.map(children, (child, index) => ( -
    index && 'is-prev', - activeSlide < index && 'is-next', - ) - } - > - {child} -
    - )) as Array + const renderSlides: (children: Array) => Array + = (children: Array) => ( + Children.map(children, (child, index) => ( +
    index && 'is-prev', + activeSlide < index && 'is-next', + ) + } + > + {child} +
    + )) as Array + ) return (
    - {wrapSlides(props.children)} + {renderSlides(props.children)}
    - {fill(Array(props.children.length), '').map((_, i) => ( - setActiveSlide(i)} - /> - ))} + {fill(Array(props.children.length), '') + .map((_, i) => ( + setActiveSlide(i)} + /> + ))}
    ) diff --git a/src-ts/tools/learn/welcome/progress-block/progress-action/ProgressAction.tsx b/src-ts/tools/learn/welcome/progress-block/progress-action/ProgressAction.tsx index b38a247dc..159bb7180 100644 --- a/src-ts/tools/learn/welcome/progress-block/progress-action/ProgressAction.tsx +++ b/src-ts/tools/learn/welcome/progress-block/progress-action/ProgressAction.tsx @@ -30,12 +30,6 @@ const USER_PROGRESS_MAX_SLIDES_COUNT: number = 8 const ProgressAction: FC = (props: ProgressActionProps) => { - const { - allCertifications, - userCompletedCertifications: myCompletedCertifications, - userInProgressCertifications: myInProgressCertifications, - }: ProgressActionProps = props - const allMyLearningsLink: ReactNode = (