@clickview/streamable-learning 0.48.0-rc.1 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.vite/manifest.json +605 -605
- package/dist/bundles.json +1 -1
- package/dist/en.json +1 -1
- package/dist/scripts/{CN8PeBwg.chunk.js → BIisq8ZO.chunk.js} +2 -2
- package/dist/scripts/{CN8PeBwg.chunk.js.map → BIisq8ZO.chunk.js.map} +1 -1
- package/dist/scripts/{BaMNOAYj2.chunk.js → BWU6_pPN2.chunk.js} +2 -2
- package/dist/scripts/{BaMNOAYj2.chunk.js.map → BWU6_pPN2.chunk.js.map} +1 -1
- package/dist/scripts/{BvJXPFoz2.chunk.js → BcZFo9Vw2.chunk.js} +2 -2
- package/dist/scripts/{BvJXPFoz2.chunk.js.map → BcZFo9Vw2.chunk.js.map} +1 -1
- package/dist/scripts/Bd2bbHru.chunk.js +1 -0
- package/dist/scripts/{CkYqp83j.chunk.js → BfNy0Hvk.chunk.js} +2 -2
- package/dist/scripts/{CkYqp83j.chunk.js.map → BfNy0Hvk.chunk.js.map} +1 -1
- package/dist/scripts/{D0SYGnyF.chunk.js → BivP7X20.chunk.js} +2 -2
- package/dist/scripts/{D0SYGnyF.chunk.js.map → BivP7X20.chunk.js.map} +1 -1
- package/dist/scripts/{BihZ4r0z2.chunk.js → BjbY4Fbp2.chunk.js} +3 -3
- package/dist/scripts/{BihZ4r0z2.chunk.js.map → BjbY4Fbp2.chunk.js.map} +1 -1
- package/dist/scripts/{DO8_mR5i2.chunk.js → BmxcE73n2.chunk.js} +2 -2
- package/dist/scripts/{DO8_mR5i2.chunk.js.map → BmxcE73n2.chunk.js.map} +1 -1
- package/dist/scripts/{bycmewy72.chunk.js → BnEMhkEE2.chunk.js} +2 -2
- package/dist/scripts/{bycmewy72.chunk.js.map → BnEMhkEE2.chunk.js.map} +1 -1
- package/dist/scripts/{jWpq99N3.chunk.js → Buc8GegC.chunk.js} +2 -2
- package/dist/scripts/{jWpq99N3.chunk.js.map → Buc8GegC.chunk.js.map} +1 -1
- package/dist/scripts/{CrCAJmt6.chunk.js → Byczy1lS.chunk.js} +2 -2
- package/dist/scripts/{CrCAJmt6.chunk.js.map → Byczy1lS.chunk.js.map} +1 -1
- package/dist/scripts/{BZOcEcTA2.chunk.js → C2itEpvc2.chunk.js} +2 -2
- package/dist/scripts/{BZOcEcTA2.chunk.js.map → C2itEpvc2.chunk.js.map} +1 -1
- package/dist/scripts/{smdLElLq.chunk.js → CEFKXxac.chunk.js} +2 -2
- package/dist/scripts/{smdLElLq.chunk.js.map → CEFKXxac.chunk.js.map} +1 -1
- package/dist/scripts/{B-qOny0I2.chunk.js → CEYjJAp52.chunk.js} +2 -2
- package/dist/scripts/{B-qOny0I2.chunk.js.map → CEYjJAp52.chunk.js.map} +1 -1
- package/dist/scripts/{CNJrD44-2.chunk.js → CJSc4YDq2.chunk.js} +2 -2
- package/dist/scripts/{CNJrD44-2.chunk.js.map → CJSc4YDq2.chunk.js.map} +1 -1
- package/dist/scripts/{Br0Uc4GG.chunk.js → CKUA5J3R.chunk.js} +2 -2
- package/dist/scripts/{Br0Uc4GG.chunk.js.map → CKUA5J3R.chunk.js.map} +1 -1
- package/dist/scripts/{CWFInhB82.chunk.js → CYrzupmS2.chunk.js} +2 -2
- package/dist/scripts/{CWFInhB82.chunk.js.map → CYrzupmS2.chunk.js.map} +1 -1
- package/dist/scripts/{Llxar-VU.chunk.js → CcGYZb9f.chunk.js} +2 -2
- package/dist/scripts/{Llxar-VU.chunk.js.map → CcGYZb9f.chunk.js.map} +1 -1
- package/dist/scripts/{BTYwcYPL2.chunk.js → CeQGaFi-2.chunk.js} +2 -2
- package/dist/scripts/{BTYwcYPL2.chunk.js.map → CeQGaFi-2.chunk.js.map} +1 -1
- package/dist/scripts/{D7tastET2.chunk.js → Cr3Blj6H2.chunk.js} +2 -2
- package/dist/scripts/{D7tastET2.chunk.js.map → Cr3Blj6H2.chunk.js.map} +1 -1
- package/dist/scripts/{Dr1flAez.chunk.js → CxCkwLio.chunk.js} +2 -2
- package/dist/scripts/{Dr1flAez.chunk.js.map → CxCkwLio.chunk.js.map} +1 -1
- package/dist/scripts/{DyT1OGvP2.chunk.js → Cxj75Dqe2.chunk.js} +2 -2
- package/dist/scripts/{DyT1OGvP2.chunk.js.map → Cxj75Dqe2.chunk.js.map} +1 -1
- package/dist/scripts/{CsC3VVvE2.chunk.js → D-VNmhoM2.chunk.js} +2 -2
- package/dist/scripts/{CsC3VVvE2.chunk.js.map → D-VNmhoM2.chunk.js.map} +1 -1
- package/dist/scripts/{CKdklY2o2.chunk.js → D2FqnK9m2.chunk.js} +2 -2
- package/dist/scripts/{CKdklY2o2.chunk.js.map → D2FqnK9m2.chunk.js.map} +1 -1
- package/dist/scripts/{qcrBN1zR2.chunk.js → D3sdyN2Q2.chunk.js} +2 -2
- package/dist/scripts/{qcrBN1zR2.chunk.js.map → D3sdyN2Q2.chunk.js.map} +1 -1
- package/dist/scripts/{Ce1TZZdV2.chunk.js → D6IzS-bj2.chunk.js} +2 -2
- package/dist/scripts/{Ce1TZZdV2.chunk.js.map → D6IzS-bj2.chunk.js.map} +1 -1
- package/dist/scripts/{B703cBe72.chunk.js → D8g6nOG92.chunk.js} +2 -2
- package/dist/scripts/{B703cBe72.chunk.js.map → D8g6nOG92.chunk.js.map} +1 -1
- package/dist/scripts/{CCoZQmgX.chunk.js → DCKKwz9L.chunk.js} +2 -2
- package/dist/scripts/{CCoZQmgX.chunk.js.map → DCKKwz9L.chunk.js.map} +1 -1
- package/dist/scripts/{DIavEegC.chunk.js → DL4UFxRK.chunk.js} +2 -2
- package/dist/scripts/{DIavEegC.chunk.js.map → DL4UFxRK.chunk.js.map} +1 -1
- package/dist/scripts/{C5i1HsPp2.chunk.js → DLofRa642.chunk.js} +2 -2
- package/dist/scripts/{C5i1HsPp2.chunk.js.map → DLofRa642.chunk.js.map} +1 -1
- package/dist/scripts/{B5jBIPaP.chunk.js → DMZ--ok1.chunk.js} +2 -2
- package/dist/scripts/{B5jBIPaP.chunk.js.map → DMZ--ok1.chunk.js.map} +1 -1
- package/dist/scripts/{CUUUI6pl.chunk.js → DQFcbMMk.chunk.js} +2 -2
- package/dist/scripts/{CUUUI6pl.chunk.js.map → DQFcbMMk.chunk.js.map} +1 -1
- package/dist/scripts/{Dj4AeYQQ2.chunk.js → DVeqPzBe2.chunk.js} +2 -2
- package/dist/scripts/{Dj4AeYQQ2.chunk.js.map → DVeqPzBe2.chunk.js.map} +1 -1
- package/dist/scripts/{CGxa1Jzq.chunk.js → DWerltCT.chunk.js} +2 -2
- package/dist/scripts/{CGxa1Jzq.chunk.js.map → DWerltCT.chunk.js.map} +1 -1
- package/dist/scripts/{CbLL7dIz2.chunk.js → DatscYpA2.chunk.js} +2 -2
- package/dist/scripts/{CbLL7dIz2.chunk.js.map → DatscYpA2.chunk.js.map} +1 -1
- package/dist/scripts/{DwzBzBlI2.chunk.js → DkaGC5IU2.chunk.js} +2 -2
- package/dist/scripts/{DwzBzBlI2.chunk.js.map → DkaGC5IU2.chunk.js.map} +1 -1
- package/dist/scripts/{BLrjbrp8.chunk.js → DqZWSPDJ.chunk.js} +2 -2
- package/dist/scripts/{BLrjbrp8.chunk.js.map → DqZWSPDJ.chunk.js.map} +1 -1
- package/dist/scripts/{BKnxYKDu2.chunk.js → Dql-1E6g2.chunk.js} +2 -2
- package/dist/scripts/{BKnxYKDu2.chunk.js.map → Dql-1E6g2.chunk.js.map} +1 -1
- package/dist/scripts/{B7iwtSij.chunk.js → DuBHin02.chunk.js} +2 -2
- package/dist/scripts/{B7iwtSij.chunk.js.map → DuBHin02.chunk.js.map} +1 -1
- package/dist/scripts/{BpgHKWR52.chunk.js → QMuFwiiF2.chunk.js} +2 -2
- package/dist/scripts/{BpgHKWR52.chunk.js.map → QMuFwiiF2.chunk.js.map} +1 -1
- package/dist/scripts/{Ces-KTwe.chunk.js → U_sIlzAD.chunk.js} +2 -2
- package/dist/scripts/{Ces-KTwe.chunk.js.map → U_sIlzAD.chunk.js.map} +1 -1
- package/dist/scripts/{ACTQklJQ.chunk.js → WLyOm9Lj.chunk.js} +2 -2
- package/dist/scripts/{ACTQklJQ.chunk.js.map → WLyOm9Lj.chunk.js.map} +1 -1
- package/dist/scripts/{DR80oZtZ.chunk.js → Ymq7JLkU.chunk.js} +2 -2
- package/dist/scripts/{DR80oZtZ.chunk.js.map → Ymq7JLkU.chunk.js.map} +1 -1
- package/dist/scripts/{app-BIigh9wv.js → app-gjHxcZG3.js} +4 -4
- package/dist/scripts/app-gjHxcZG3.js.map +1 -0
- package/dist/scripts/{CNmmq34f.chunk.js → djRnI462.chunk.js} +2 -2
- package/dist/scripts/{CNmmq34f.chunk.js.map → djRnI462.chunk.js.map} +1 -1
- package/dist/scripts/{oTYyWWB-.chunk.js → e2K2YU7z.chunk.js} +2 -2
- package/dist/scripts/{oTYyWWB-.chunk.js.map → e2K2YU7z.chunk.js.map} +1 -1
- package/dist/scripts/{BxypZGPK.chunk.js → fnfhCa1P.chunk.js} +2 -2
- package/dist/scripts/{BxypZGPK.chunk.js.map → fnfhCa1P.chunk.js.map} +1 -1
- package/dist/scripts/{BsAo7Lri2.chunk.js → iyIL3kim2.chunk.js} +2 -2
- package/dist/scripts/{BsAo7Lri2.chunk.js.map → iyIL3kim2.chunk.js.map} +1 -1
- package/dist/scripts/{DK3xia1t.chunk.js → kfFYr9dc.chunk.js} +2 -2
- package/dist/scripts/{DK3xia1t.chunk.js.map → kfFYr9dc.chunk.js.map} +1 -1
- package/dist/scripts/{BXJetawx2.chunk.js → kts5xiiM2.chunk.js} +2 -2
- package/dist/scripts/{BXJetawx2.chunk.js.map → kts5xiiM2.chunk.js.map} +1 -1
- package/dist/scripts/{tYi-sUb22.chunk.js → lLAYbgAy2.chunk.js} +2 -2
- package/dist/scripts/{tYi-sUb22.chunk.js.map → lLAYbgAy2.chunk.js.map} +1 -1
- package/dist/scripts/{BCBfXCYM2.chunk.js → p9ukva5a2.chunk.js} +2 -2
- package/dist/scripts/{BCBfXCYM2.chunk.js.map → p9ukva5a2.chunk.js.map} +1 -1
- package/dist/scripts/{DKnZ8BaN.chunk.js → wOeN2ls0.chunk.js} +2 -2
- package/dist/scripts/{DKnZ8BaN.chunk.js.map → wOeN2ls0.chunk.js.map} +1 -1
- package/dist/scripts/{DU1SE31v2.chunk.js → zp2BHOp82.chunk.js} +2 -2
- package/dist/scripts/{DU1SE31v2.chunk.js.map → zp2BHOp82.chunk.js.map} +1 -1
- package/dist/scripts/{DnSy_Myx.chunk.js → zyVwH8JF.chunk.js} +2 -2
- package/dist/scripts/{DnSy_Myx.chunk.js.map → zyVwH8JF.chunk.js.map} +1 -1
- package/package.json +1 -1
- package/dist/scripts/C4MLxDS-.chunk.js +0 -1
- package/dist/scripts/app-BIigh9wv.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qcrBN1zR2.chunk.js","names":[],"sources":["../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-header-details/ClassificationHeaderDetails.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/empty-state/CuratedClassificationEmptyState.tsx","../../../../libs/shared/src/components/table-of-contents-list/table-of-contents-list.module.scss","../../../../libs/shared/src/components/table-of-contents-list/TableOfContentsList.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/table-of-contents/table-of-contents.module.scss","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/table-of-contents/TableOfContents.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/teacher-only/TeacherOnlyEmptyState.tsx","../../../../libs/shared/src/apps/subjects/hooks/useGetTopicsWidgets.ts","../../../../libs/shared/src/hooks/useTableOfContentsActiveHeading.tsx","../../../../libs/shared/src/hooks/usePrevious.ts","../../../../libs/shared/src/hooks/useTableOfContentsScroll.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-coming-soon/ClassificationComingSoon.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/audiences/ClassificationDashboardAudiences.tsx","../../../../libs/shared/src/images/svg/widgets/WidgetSeriesSvg.tsx","../../../../libs/shared/src/apps/subjects/hooks/useDirectoryTabProductTipSwitcher.ts","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-tabs/classification-tabs.module.scss","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-tabs/ClassificationTabs.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-dashboard-nav/ClassificationDashboardNav.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/ClassificationDashboard.tsx","../../src/apps/subjects/errors/TopicNotFoundError.ts","../../src/apps/subjects/views/classification/partial-loading/PartialClassification.tsx","../../src/apps/subjects/views/classification/StreamableClassificationViewUtils.ts","../../src/apps/subjects/views/classification/StreamableClassificationView.tsx"],"sourcesContent":["import React from 'react';\n\nimport { Text } from 'libs/shared/components/text/Text';\nimport { Classification } from 'libs/shared/interfaces';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nconst namespace = 'subject.classificationHeaderDetails';\n\nconst Separator = ({ className }: { className: string }) =>\n <span className={className}>•</span>;\n\ninterface ClassificationHeaderDetailsProps {\n classification: Classification;\n}\n\nexport function ClassificationHeaderDetails(props: ClassificationHeaderDetailsProps): React.ReactElement {\n const {\n dashboardVideoCount,\n childDashboardVideoCount,\n dashboardResourceCount,\n childDashboardResourceCount,\n childClassificationCount\n } = TopicsHelper.getCounts(props.classification);\n\n const videoCount = dashboardVideoCount + childDashboardVideoCount;\n const resourceCount = dashboardResourceCount + childDashboardResourceCount;\n\n return (\n <p className='mb-n1 font-size-normal fw-normal mt-1'>\n {!!childClassificationCount && (\n <Text\n namespace={namespace}\n phrase='topics'\n options={{ count: childClassificationCount.toLocaleString(), smartCount: childClassificationCount }}\n />\n )}\n\n {!!videoCount && (\n <>\n {childClassificationCount > 0 && <Separator className='mx-2' />}\n <Text\n namespace={namespace}\n phrase='videos'\n options={{ count: videoCount.toLocaleString(), smartCount: videoCount }}\n />\n </>\n )}\n {!!resourceCount && (\n <>\n <Separator className='mx-2' />\n <Text\n namespace={namespace}\n phrase='resources'\n options={{ count: resourceCount.toLocaleString(), smartCount: resourceCount }}\n />\n </>\n )}\n </p>\n );\n}\n","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\n\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\nimport { Tooltip } from 'libs/shared/components/tooltip/Tooltip';\nimport { PlusSvg } from 'libs/shared/images/svg/actions/PlusSvg';\nimport { CuratedDashboard, DashboardStatus } from 'libs/shared/interfaces';\n\nconst namespace = 'subjects.curatedClassificationEmptyState';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface CuratedClassificationEmptyStateProps {\n dashboard: CuratedDashboard;\n imageUrl: string;\n isReadonly: boolean;\n addWidgetApplink?: () => Core.AppLink;\n}\n\nexport function CuratedClassificationEmptyState(props: CuratedClassificationEmptyStateProps): JSX.Element {\n const isArchived = props.dashboard?.status === DashboardStatus.Archived;\n\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState>\n <EmptyState.Image src={props.imageUrl} altText={getPhrase('headingForNP')} />\n {!props.isReadonly ? (\n <EmptyState.Heading>\n <Text phrase='headingForNP' />\n </EmptyState.Heading>\n ) : (\n <>\n <EmptyState.Heading>\n <Text namespace={namespace} phrase='headingForCurator' />\n </EmptyState.Heading>\n <EmptyState.Info>\n <Text namespace={namespace} phrase='info' />\n </EmptyState.Info>\n <Tooltip title={isArchived ? LanguageService.getPhrase(namespace, 'archivedCtaTooltip') : ''} spanHack>\n <EmptyState.Cta\n text={LanguageService.getPhrase(namespace, 'add')}\n appLink={props.addWidgetApplink?.()}\n className='btn btn-dark'\n icon={PlusSvg}\n disabled={isArchived}\n />\n </Tooltip>\n </>\n )}\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n",":local{\n $dot-size: 0.75rem;\n $track-offset: -1rem;\n\n @mixin dot {\n &::before {\n position: absolute;\n left: -1.06rem;\n top: calc(50% - $dot-size/2);\n display: block;\n content: '';\n height: $dot-size;\n width: $dot-size;\n border-radius: 50%;\n background-color: $black;\n }\n }\n\n @mixin tocIndent($depth) {\n margin-left: map-get($spacers, 3) * $depth;\n }\n \n .itemsWrapper {\n border-left: 2px solid $black;\n padding-left: 0.625rem;\n }\n\n .anchorWrapper {\n padding: 0.625rem;\n text-decoration: none;\n position: relative;\n display: block;\n }\n .anchorWrapper:hover {\n background-color: $light-blue;\n text-decoration: none;\n cursor: pointer;\n }\n\n .anchorWrapper:first-child {\n &::after {\n display: block;\n content: '';\n background-color: $white;\n height: calc(50% - $dot-size/2 + 0.05rem);\n width: 0.625rem;\n top: -0.05rem;\n position: absolute;\n left: $track-offset;\n }\n }\n .anchorWrapper:last-child {\n &::after {\n display: block;\n content: '';\n background-color: $white;\n height: calc(50% - $dot-size/2);\n width: 0.625rem;\n position: absolute;\n bottom: 0;\n left: $track-offset;\n }\n }\n\n .default {\n @include dot\n }\n\n .selectedItem {\n background-color: $gray-100;\n font-weight: 500;\n @include dot\n }\n \n .disabled:hover {\n cursor: default;\n background-color: $white;\n }\n .disabled{\n pointer-events:none\n }\n\n .floatIcon {\n position: absolute;\n right: 0;\n width: fit-content;\n padding: 0;\n .arrowIcon {\n display: none;\n }\n .listIcon {\n display: block;\n }\n &:hover {\n .listIcon {\n display: none;\n }\n .arrowIcon {\n display: block;\n }\n }\n }\n\n .tocIndent1 {\n @include tocIndent(1);\n }\n\n .tocIndent2 {\n @include tocIndent(2);\n }\n}","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { ScrollHelper } from 'libs/common/backbone/utils/ScrollHelper';\n\nimport { EntityType, HashObject, LocationContext, UserAction } from 'libs/analytics/interfaces';\n\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { DivButton } from 'libs/shared/components/div-button/DivButton';\n\nimport styles from './table-of-contents-list.module.scss';\n\nexport interface TableOfContentsItem<T=string> {\n name: string;\n id: T;\n tocIndentation?: number;\n}\n\ninterface TableOfContentsProps<T> {\n items: TableOfContentsItem<T>[];\n activeId: string;\n appLink?: Core.AppLink;\n analyticsData?: HashObject;\n setControlledId: (arg: string) => void;\n // set to true if the TOC is controlled by a local state rather than query params\n localState?: boolean;\n getAppLink?: (args: TableOfContentsItem<T>) => Core.AppLink;\n onItemClick?: (args: TableOfContentsItem<T>) => void;\n}\n\nexport function TableOfContentsList<T extends string>(props: TableOfContentsProps<T>): JSX.Element {\n const analyticsOptions = {\n actionType: UserAction.Click,\n entity: EntityType.Widget,\n location: LocationContext.TableOfContents\n };\n\n function onItemSelect(item: TableOfContentsItem<T>) {\n ScrollHelper.preventScrollTop();\n props.setControlledId(item.id);\n \n props.onItemClick?.(item);\n \n setTimeout(() => document.getElementById(item.id)?.focus());\n }\n\n function getTocIndentClass(item: TableOfContentsItem<T>): string {\n if (item.tocIndentation === 1)\n return styles.tocIndent1;\n \n if (item.tocIndentation === 2)\n return styles.tocIndent2;\n\n return '';\n }\n\n return (\n <div className={`${styles.itemsWrapper}`}>\n {props.items.map((item, idx) => {\n if (props.localState) {\n return (\n <DivButton\n key={item.id}\n className={`${styles.anchorWrapper} ${props.activeId === item.id ? styles.selectedItem : ''}`}\n onClick={() => {\n onItemSelect(item);\n }}\n >\n <div className={`${!props.activeId && idx === 0 ? styles.default : ''} `}>\n {item.name}\n </div>\n </DivButton>\n );\n }\n\n return (\n <AppLink\n key={item.id}\n appLink={props.getAppLink(item)}\n appLinkOptions={{ replace: true }}\n className={`${styles.anchorWrapper} ${props.activeId === item.id ? styles.selectedItem : ''}`}\n onClick={() => {\n onItemSelect(item);\n }}\n analyticsData={{\n ...props.analyticsData,\n id: item.id,\n name: item.name\n }}\n analyticsOptions={analyticsOptions}\n >\n <div className={`${!props.activeId && idx === 0 ? styles.default : ''} ${getTocIndentClass(item)}`}>\n {item.name}\n </div>\n </AppLink>\n );\n })}\n </div>\n );\n}\n","$top-nav-height: 4.1875rem;\n$cv-banner-height: calc(100vw * 22 / 120);\n$filters-area: 7.87rem;\n\n.container {\n position: sticky;\n top: 6.25rem;\n z-index: 80;\n}\n\n.mobile {\n position: fixed;\n top: calc($top-nav-height + $cv-banner-height + $filters-area);\n z-index: 80;\n right: 0;\n}","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { EntityType, HashObject, LocationContext, UserAction } from 'libs/analytics/interfaces';\n\nimport { IconButton } from 'libs/shared/components/icon-button/IconButton';\nimport { TableOfContentsList } from 'libs/shared/components/table-of-contents-list/TableOfContentsList';\nimport { TableOfContentsSvg } from 'libs/shared/images/svg/objects/TableOfContentsSvg';\nimport { CuratedWidget } from 'libs/shared/interfaces';\nimport { ContextService } from 'libs/shared/services/ContextService';\n\nimport styles from './table-of-contents.module.scss';\n\ninterface TableOfContentsContainerProps {\n widgets: CuratedWidget[];\n title: string;\n activeId: string;\n appLink?: Core.AppLink;\n clickable?: boolean;\n analyticsData?: HashObject;\n setControlledId: (arg: string) => void;\n isSmallScreen?: boolean;\n}\ninterface TableOfContentsProps extends TableOfContentsContainerProps {\n getAppLink: (widget: CuratedWidget) => Core.AppLink;\n}\n\nfunction TableOfContentsMobile(props: TableOfContentsProps) {\n const [ isExpanded, setIsExpanded ] = React.useState(false);\n\n function logUserAction() {\n const analyticsOptions = {\n actionType: !isExpanded ? UserAction.Open : UserAction.Hide,\n entity: EntityType.TableOfContents,\n location: LocationContext.Dashboard\n };\n\n AnalyticsHelper.logUserAction(props.analyticsData, analyticsOptions);\n }\n\n function onClickIcon() {\n setIsExpanded(!isExpanded);\n logUserAction();\n }\n\n return (\n <div className={`${styles.mobile} d-inline-flex gap-1`}>\n \n {isExpanded && (\n <div className='bg-white px-3 pt-3 pb-2 border border-dark rounded-1 ps-3'>\n <h2 className='h5'>{props.title}</h2>\n <TableOfContentsList\n items={props.widgets.map(widget => (\n { name: widget.name, id: widget.id, tocIndentation: widget.metadata.tocIndentation }\n ))}\n activeId={props.activeId}\n appLink={props.appLink}\n analyticsData={props.analyticsData}\n setControlledId={props.setControlledId}\n getAppLink={props.getAppLink}\n onItemClick={() => setIsExpanded(false)}\n />\n </div>\n )}\n <div className={styles.container}>\n <IconButton\n className='btn btn-outline-dark'\n svg={TableOfContentsSvg}\n onClick={onClickIcon}\n />\n </div>\n </div>\n );\n}\n\nfunction TableOfContents(props: TableOfContentsProps): JSX.Element {\n return (\n <aside className='col-3 order-1'>\n <div className={`${styles.container} ps-3`}>\n <h2 className='h5'>{props.title}</h2>\n \n <TableOfContentsList\n items={props.widgets.map(widget => (\n { name: widget.name, id: widget.id, tocIndentation: widget.metadata.tocIndentation }\n ))}\n activeId={props.activeId}\n appLink={props.appLink}\n analyticsData={props.analyticsData}\n setControlledId={props.setControlledId}\n getAppLink={props.getAppLink}\n />\n </div>\n </aside>\n );\n}\n\nexport function TableOfContentsContainer(props: TableOfContentsContainerProps): JSX.Element {\n function getAppLink(widget: CuratedWidget): Core.AppLink {\n const currentAppLink = ContextService.getCurrentRoute().appLink;\n \n const params: HashObject = currentAppLink.params ?\n { ...(currentAppLink.params as HashObject) } :\n {};\n\n params.tocId = widget.id;\n\n return {\n ...currentAppLink,\n params\n };\n }\n\n return (\n <>\n {!props.isSmallScreen ?\n <TableOfContents {...props} getAppLink={getAppLink} /> :\n <TableOfContentsMobile {...props} getAppLink={getAppLink} />\n }\n </>\n );\n}\n","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\n\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\n\nconst namespace = 'subjects.teacherOnlyEmptyState';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface TeacherOnlyEmptyStateProps {\n imageUrl: string;\n ctaAppLink?: () => Core.AppLink;\n}\n\nexport function TeacherOnlyEmptyState(props: TeacherOnlyEmptyStateProps): JSX.Element {\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState>\n <EmptyState.Image src={props.imageUrl} altText={getPhrase('heading')} />\n <EmptyState.Heading>\n <Text phrase='heading' />\n </EmptyState.Heading>\n <EmptyState.Info>\n <Text phrase='info' />\n </EmptyState.Info>\n\n <EmptyState.Cta\n text={getPhrase('cta')}\n appLink={props.ctaAppLink?.()}\n className='btn btn-dark'\n />\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n","import React from 'react';\n\nimport { Flight } from 'libs/common/react/index';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { WidgetTemplate } from 'libs/shared/enums/WidgetTemplate';\nimport { WidgetTypeId } from 'libs/shared/enums/WidgetTypeId';\nimport { DashboardRequests } from 'libs/shared/flight-requests/DashboardRequests';\nimport { CuratedDashboard, CuratedMediaWidget, CuratedWidget, PresentationAudience, Video } from 'libs/shared/interfaces';\nimport { CuratedDashboardHelper } from 'libs/shared/utils/DashboardHelper';\n\nexport interface Response {\n widgets: CuratedWidget[];\n\n videoList?: Video[];\n videoListWidgetId?: string;\n}\n\n/**\n * This hook helps us with custom logic for to display system generated dashboards in a slightly\n * different way.\n */\nexport function useGetTopicsWidgets(dashboard: CuratedDashboard, activeAudiences: PresentationAudience[]): Response {\n const {\n isSystemGeneratedDashboard,\n systemGeneratedVideoWidget\n } = React.useMemo(() => {\n if (!dashboard) {\n return {\n isSystemGeneratedDashboard: false,\n systemGeneratedVideoWidget: null\n };\n }\n\n const isSystemGeneratedDashboard = CuratedDashboardHelper.isSystemGeneratedDashboard(dashboard.widgets);\n\n return {\n isSystemGeneratedDashboard,\n systemGeneratedVideoWidget: dashboard.widgets.find(widget => {\n return (\n widget.widgetId === WidgetTypeId.ClassificationPinnedVideos &&\n widget.templateId !== WidgetTemplate.ThumbnailVerticalList\n );\n })\n };\n }, [dashboard?.id]);\n\n const systemGeneratedVideoContent = Flight.useBasicFetch<CuratedMediaWidget<Video[]>>(\n !!systemGeneratedVideoWidget &&\n DashboardRequests.dashboardWidgetContent(\n systemGeneratedVideoWidget?.id,\n CuratedDashboardHelper.getWidgetParams(\n systemGeneratedVideoWidget.widgetId,\n systemGeneratedVideoWidget.templateId,\n CuratedDashboardHelper.getDashboardTargetType(dashboard),\n activeAudiences?.map(a => a.masterId)\n ),\n systemGeneratedVideoWidget?.templateId\n )\n );\n\n // Non system generated dashboards are returned as per usual\n if (!isSystemGeneratedDashboard)\n return { widgets: ArrayHelper.sortBy(dashboard?.widgets, 'index') };\n\n // System generated dashboard have the video widget removed and returned as a separate video list\n return {\n widgets: dashboard?.widgets?.filter(widget => {\n if (widget.widgetId !== WidgetTypeId.ClassificationPinnedVideos)\n return true;\n\n if (widget.templateId === WidgetTemplate.ThumbnailVerticalList)\n return true;\n\n return false;\n }) ?? [],\n videoList: systemGeneratedVideoContent.data?.content ?? [],\n videoListWidgetId: systemGeneratedVideoWidget?.id\n };\n}\n","import React from 'react';\n\ntype TableOfContentsActiveOption = {\n setActiveId: (id: string) => void,\n headingElements: Element[],\n controlledId?: string,\n setControlledId?: (arg: string) => void\n};\n\nlet timer: number;\n\nexport const useTableOfContentsActiveHeading = (\n { setActiveId, headingElements, controlledId, setControlledId }: TableOfContentsActiveOption\n) => {\n const scrollPositionRef = React.useRef(0);\n\n React.useEffect(() => {\n const callback = (headings: IntersectionObserverEntry[]) => {\n headings.forEach(heading => {\n if (controlledId) {\n setActiveId(controlledId);\n // can use scrollEnd event when the new event type is supported\n timer = window.setTimeout(() => {\n setControlledId('');\n }, 800);\n return;\n }\n if (heading.isIntersecting) {\n setActiveId(heading.target.id);\n scrollPositionRef.current = window.scrollY;\n } else {\n const scrollDistance = scrollPositionRef.current - window.scrollY;\n const isScrollingUp = scrollDistance > 0;\n const curIndex = headingElements.findIndex(h => h.id === heading.target.id);\n const prevHeading = headingElements[curIndex - 1];\n if (isScrollingUp && prevHeading?.id) {\n setActiveId(prevHeading?.id);\n }\n }\n });\n };\n\n const observer = new IntersectionObserver(callback, {\n // rootMargin top: same as the cv-nav-height\n rootMargin: '-67px 0px -80% 0px'\n });\n\n headingElements.forEach(element => observer.observe(element));\n\n return () => {\n timer && window.clearTimeout(timer);\n observer.disconnect();\n };\n }, [ setActiveId, headingElements.length, controlledId ]);\n};\n\n","import React from 'react';\n\n// https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state\nexport function usePrevious<T>(value: T): T {\n const ref = React.useRef<T>(null);\n React.useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n}\n","import React from 'react';\n\nimport { usePrevious } from './usePrevious';\n\nconst HEADER_OFFSET = 80; // Size of header + some extra spacing\n\nexport const useTableOfContentsScroll = (elements: Element[], activeId: string) => {\n const [ hasDoneInitialScroll, setHasDoneInitialScroll ] = React.useState(false);\n\n const previousId = usePrevious(activeId);\n const currentId = activeId;\n\n React.useLayoutEffect(() => {\n if (!hasDoneInitialScroll || previousId !== currentId) {\n const target = elements.find(heading => heading && (heading?.id === currentId));\n\n if (target) {\n const rec = target.getBoundingClientRect();\n\n window.scrollBy({\n top: rec.top - HEADER_OFFSET,\n behavior: 'smooth'\n });\n \n if (!hasDoneInitialScroll)\n setHasDoneInitialScroll(true);\n }\n }\n }, [ elements, previousId, currentId, hasDoneInitialScroll ]);\n};\n","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { EntityType, LocationContext, SignUpDescriptors, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { ActionButton } from 'libs/shared/components/actions/ActionButton';\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\nimport { BellFilledSvg } from 'libs/shared/images/svg/objects/BellFilledSvg';\nimport { BellSvg } from 'libs/shared/images/svg/objects/BellSvg';\nimport { Classification } from 'libs/shared/interfaces';\n\nconst namespace = 'subjects.classificationComingSoon';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface ComingSoonProps {\n data: Classification;\n onToggleFollow?: () => void;\n canFollowSubjects: boolean;\n imageUrl: string;\n showFollowButtonSpinner: boolean;\n showSignUp: boolean;\n signUpAppLink: Core.AppLink;\n}\n\nexport function ClassificationComingSoon(props: ComingSoonProps): JSX.Element {\n const isFollowing = !!props.data.followers?.data?.length;\n function onClick(): void {\n props.onToggleFollow?.();\n }\n\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState className='pt-0'>\n <EmptyState.Image src={props.imageUrl} altText={getPhrase('comingSoon')} />\n\n <EmptyState.Heading>\n <Text phrase='comingSoon' />\n </EmptyState.Heading>\n\n <EmptyState.Info>\n <Text phrase={props.showSignUp ? 'infoAnon' : 'info'} />\n </EmptyState.Info>\n\n {props.canFollowSubjects && (\n <ActionButton\n svg={isFollowing ? BellFilledSvg : BellSvg}\n onClick={onClick}\n showSpinner={props.showFollowButtonSpinner}\n className={`btn follow-btn me-2 ${isFollowing ? 'btn-outline-dark' : 'btn-dark'}`}\n >\n <Text phrase={isFollowing ? 'following' : 'follow'} />\n </ActionButton>\n )}\n\n {props.showSignUp && !props.canFollowSubjects && (\n <AppLink\n appLink={props.signUpAppLink}\n className='btn btn-dark d-none d-lg-inline-block'\n analyticsOptions={{\n actionType: UserAction.Click,\n location: LocationContext.ClassificationComingSoon,\n entity: EntityType.AppLink,\n workflowPhase: WorkflowPhase.Start,\n descriptor: SignUpDescriptors.SignUp\n }}\n analyticsData={{}}\n tag='button'\n >\n {getPhrase('signUp')}\n </AppLink>\n )}\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n","import React from 'react';\n\nimport { Core } from 'libs/common/core';\n\nimport { AudienceFilter } from 'libs/shared/apps/subjects/components/audience-filter/AudienceFilter';\nimport { PresentationAudience } from 'libs/shared/interfaces';\n\ninterface ClassificationDashboardAudiencesProps {\n audiences: PresentationAudience[];\n activeAudiences: PresentationAudience[];\n appLink: Core.AppLink;\n disabled: boolean;\n disablePersist: boolean;\n tooltip: string;\n}\n\nexport function ClassificationDashboardAudiences(props: ClassificationDashboardAudiencesProps): JSX.Element {\n return (\n <AudienceFilter\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n disabled={props.disabled}\n appLink={props.appLink}\n disablePersist={props.disablePersist}\n tooltip={props.tooltip}\n />\n );\n}\n","import React from 'react';\n\nexport function WidgetSeriesSvg(props: React.SVGProps<SVGSVGElement>) {\n return (\n <svg {...props}>\n <path\n d='M4.5 4a.5.5 0 0 0 0 1h16a.5.5 0 0 1 .5.5v12a.5.5 0 0 0 1 0v-12A1.5 1.5 0 0 0 20.5 4zM9 10.26a.256.256 0 0 1 .39-.218l4.482 2.74a.256.256 0 0 1 0 .437L9.39 15.958A.256.256 0 0 1 9 15.739zM18.5 6A1.5 1.5 0 0 1 20 7.5v11a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 2 18.5v-11A1.5 1.5 0 0 1 3.5 6zm-15 1a.5.5 0 0 0-.5.5v11a.5.5 0 0 0 .5.5h15a.5.5 0 0 0 .5-.5v-11a.5.5 0 0 0-.5-.5z'\n fill='currentColor'\n />\n </svg>\n );\n}\n","import React from 'react';\n\nimport { useViewModel } from 'libs/common/react/hooks/UseViewModel';\n\nimport { ClassificationTab } from '../components/classification-dashboard/classification-tabs/ClassificationTabs';\n\ninterface ViewModel {\n tab: ClassificationTab;\n on: boolean;\n}\n\nexport function useDirectoryTabProductTipSwitcher(initialTab?: ClassificationTab) {\n const initialState: ViewModel = {\n on: false,\n tab: initialTab || 'new-releases'\n };\n\n const [ viewModel, setViewModel ] = useViewModel<ViewModel>('directory:product:tip:switcher', initialState);\n\n React.useEffect(() => {\n if (!initialTab)\n return;\n\n setViewModel('tab', initialTab);\n }, [initialTab]);\n\n React.useEffect(() => {\n let interval: number = null;\n\n if (viewModel.on) {\n interval = window.setInterval(() => {\n if (viewModel.tab === 'new-releases' || viewModel.tab === 'all-topics')\n setViewModel('tab', viewModel.tab === 'new-releases' ? 'all-topics' : 'new-releases');\n else\n setViewModel('tab', viewModel.tab === 'curated-topic' ? 'video-list' : 'curated-topic');\n }, 2000);\n }\n\n return () => {\n window.clearInterval(interval);\n };\n }, [ viewModel.on, viewModel.tab ]);\n\n return {\n tab: viewModel.tab,\n isHighlighting: viewModel.on,\n start: () => setViewModel('on', true),\n stop: () => {\n setViewModel({\n on: false,\n tab: initialTab || viewModel.tab\n });\n }\n };\n}\n",":local {\n .curatedTopicTab {\n min-width: 6rem !important;\n }\n \n .tabTransition {\n transition: background-color .5s ease-in-out;\n }\n}","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { EntityType, LocationContext, UserAction } from 'libs/analytics/interfaces';\n\nimport { PillTab, PillTabSelector } from 'libs/shared/components/pill-tab-selector/PillTabSelector';\nimport { Breakpoints, useBreakpoints } from 'libs/shared/hooks/useBreakpoints';\nimport { GridSvg } from 'libs/shared/images/svg/objects/GridSvg';\nimport { RectanglesSvg } from 'libs/shared/images/svg/objects/RectanglesSvg';\nimport { SparkleSvg } from 'libs/shared/images/svg/objects/SparkleSvg';\nimport { WidgetSeriesSvg } from 'libs/shared/images/svg/widgets/WidgetSeriesSvg';\nimport { Classification, Presentation } from 'libs/shared/interfaces';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nimport { useDirectoryTabProductTipSwitcher } from '../../../hooks/useDirectoryTabProductTipSwitcher';\n\nimport styles from './classification-tabs.module.scss';\n\nconst namespace = 'shared.classificationDashboard';\n\nexport type ClassificationTab = 'new-releases' | 'all-topics' | 'curated-topic' | 'curriculum';\n\nfunction getTabs(\n props: ClassificationTabsProps,\n breakpoints: Breakpoints,\n activeTab: ClassificationTab,\n isHighlighting: boolean\n): PillTab[] {\n const showText = breakpoints.lg || breakpoints.xl || breakpoints.xxl || breakpoints.xs;\n\n function getTopicTabClassName(): string {\n let className = isHighlighting ? styles.tabTransition : '';\n\n if (breakpoints.xs)\n return className + ' w-100';\n\n if (showText)\n return className = ` ${styles.curatedTopicTab}`;\n\n return className;\n }\n\n if (TopicsHelper.isTopLevelTopic(props.classification)) {\n return [{\n name: showText ? LanguageService.getPhrase(namespace, 'newReleases') : '',\n appLink: props.appLinks?.classification?.(props.classification),\n active: activeTab === 'new-releases',\n svg: SparkleSvg,\n analyticsData: {\n id: 'new-releases',\n classificationId: props.classification.id,\n classificationName: props.classification.name,\n presentationId: props.presentation.id,\n presentationDescription: props.presentation.description,\n name: LanguageService.getPhrase(namespace, 'newReleases'),\n url: Core.AppLinkHelper.getHref(props.appLinks?.classification?.(props.classification))\n },\n analyticsOptions: {\n actionType: UserAction.Click,\n entity: EntityType.Url,\n location: LocationContext.MagicTabs\n },\n className: `${breakpoints.xs ? 'w-100' : ''} ${isHighlighting ? styles.tabTransition : ''}`\n }, {\n name: showText ? LanguageService.getPhrase(namespace, 'allTopics') : '',\n appLink: props.appLinks?.classificationDirectory?.(props.classification),\n active: activeTab === 'all-topics',\n svg: GridSvg,\n analyticsData: {\n id: 'all-topics',\n classificationId: props.classification.id,\n classificationName: props.classification.name,\n presentationId: props.presentation.id,\n presentationDescription: props.presentation.description,\n name: LanguageService.getPhrase(namespace, 'allTopics'),\n url: Core.AppLinkHelper.getHref(props.appLinks?.classificationDirectory?.(props.classification))\n },\n analyticsOptions: {\n actionType: UserAction.Click,\n entity: EntityType.Url,\n location: LocationContext.MagicTabs\n },\n className: `${breakpoints.xs ? 'w-100' : ''} ${isHighlighting ? styles.tabTransition : ''}`\n }];\n }\n\n return [{\n name: showText ? LanguageService.getPhrase(namespace, 'topic') : '',\n appLink: props.appLinks?.classification?.(props.classification),\n active: activeTab === 'curated-topic',\n svg: RectanglesSvg,\n analyticsData: {\n id: 'curated-topic',\n classificationId: props.classification.id,\n classificationName: props.classification.name,\n presentationId: props.presentation.id,\n presentationDescription: props.presentation.description,\n name: LanguageService.getPhrase(namespace, 'topic'),\n url: Core.AppLinkHelper.getHref(props.appLinks?.classification?.(props.classification))\n },\n analyticsOptions: {\n actionType: UserAction.Click,\n entity: EntityType.Url,\n location: LocationContext.MagicTabs\n },\n className: getTopicTabClassName()\n }, {\n name: showText ? LanguageService.getPhrase(namespace, 'curriculum') : '',\n appLink: props.appLinks?.classificationCurriculum?.(props.classification),\n active: activeTab === 'curriculum',\n svg: WidgetSeriesSvg,\n analyticsData: {\n id: 'curriculum',\n classificationId: props.classification.id,\n classificationName: props.classification.name,\n presentationId: props.presentation.id,\n presentationDescription: props.presentation.description,\n name: LanguageService.getPhrase(namespace, 'curriculum'),\n url: Core.AppLinkHelper.getHref(props.appLinks?.classificationCurriculum?.(props.classification))\n },\n analyticsOptions: {\n actionType: UserAction.Click,\n entity: EntityType.Url,\n location: LocationContext.MagicTabs\n },\n className: `${breakpoints.xs ? 'w-100' : ''} ${isHighlighting ? styles.tabTransition : ''}`\n }];\n}\n\ninterface ClassificationTabsProps {\n classification: Classification;\n presentation: Presentation;\n appLinks: {\n classification: (classification: Classification | null) => Core.AppLink,\n classificationDirectory: (classification: Classification) => Core.AppLink,\n classificationCurriculum: (classification: Classification) => Core.AppLink\n };\n activeTab: ClassificationTab;\n}\n\nexport function ClassificationTabs(props: ClassificationTabsProps): JSX.Element {\n const breakpoints = useBreakpoints();\n const { tab, isHighlighting } = useDirectoryTabProductTipSwitcher(props.activeTab);\n\n return (\n <PillTabSelector\n borderRadius='sm'\n className={breakpoints.xs ? 'w-100' : ''}\n listClassName='d-flex flex-nowrap'\n tabs={getTabs(props, breakpoints, tab, isHighlighting)}\n />\n );\n}\n","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\n\nimport { Breadcrumb, Breadcrumbs } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { useBreakpoints } from 'libs/shared/hooks/useBreakpoints';\nimport { Classification, CuratedDashboard, Presentation, PresentationAudience } from 'libs/shared/interfaces';\nimport { AudienceHelper } from 'libs/shared/utils/audience-helper/AudienceHelper';\nimport { CuratedDashboardHelper } from 'libs/shared/utils/DashboardHelper';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nimport { ClassificationDashboardAudiences } from '../audiences/ClassificationDashboardAudiences';\nimport { ClassificationTab, ClassificationTabs } from '../classification-tabs/ClassificationTabs';\n\nfunction shouldHideAudiences(\n audiences: PresentationAudience[],\n activeAudiences: PresentationAudience[],\n activeTab: ClassificationTab,\n isEmpty: boolean,\n isComingSoon: boolean\n): boolean {\n if (isComingSoon)\n return true;\n\n if (isEmpty && !activeAudiences?.length)\n return true;\n\n if (!AudienceHelper.shouldShowAudiences(audiences))\n return true;\n\n if (activeTab === 'curriculum')\n return true;\n\n return false;\n}\n\ninterface ClassificationDashboardNavProps {\n dashboard: CuratedDashboard;\n classification: Classification;\n presentation: Presentation;\n appLinks: {\n audience: () => Core.AppLink,\n classification: (classification: Classification | null) => Core.AppLink,\n classificationDirectory: (classification: Classification) => Core.AppLink,\n classificationCurriculum: (classification: Classification) => Core.AppLink\n };\n activeTab: ClassificationTab;\n audiences: PresentationAudience[];\n activeAudiences: PresentationAudience[];\n getBreadcrumbs: () => Breadcrumb[];\n\n hasTopicDirectoryDashboard: boolean;\n hasTopicCurriculumDashboard: boolean;\n isComingSoon: boolean;\n isEmpty: boolean;\n isViewingCurrentPresentation: boolean;\n disableAudiences: boolean;\n audienceTooltip: string;\n}\n\nexport function ClassificationDashboardNav(props: ClassificationDashboardNavProps): JSX.Element {\n const breakpoints = useBreakpoints();\n\n const hideAudiences = shouldHideAudiences(\n props.audiences,\n props.activeAudiences,\n props.activeTab,\n props.isEmpty,\n props.isComingSoon\n );\n\n function canShowTabs(): boolean {\n if (!props.classification || !props.dashboard)\n return false;\n\n if (CuratedDashboardHelper.isSystemGeneratedDashboard(props.dashboard.widgets))\n return false;\n\n /**\n * For our top-level topics, we can show the topic tab if the topic has a directory dashboard.\n */\n if (TopicsHelper.isTopLevelTopic(props.classification))\n return props.hasTopicDirectoryDashboard;\n\n /**\n * For our curated topics, we can show the curriculum tab if the topic has one, which it should\n */\n if (props.classification.externalMetadata?.isCurated && props.hasTopicCurriculumDashboard)\n return true;\n\n return false;\n }\n\n function getContainerClass(): string {\n let className = 'd-flex flex-column py-3 mb-3';\n\n if (!props.isComingSoon)\n className += ' border-bottom';\n\n if ((canShowTabs() || hideAudiences) && !breakpoints.xs)\n return className;\n\n return className + ' row-gap-3';\n }\n\n function getTopRowClass(): string {\n if (hideAudiences) {\n if (breakpoints.xs)\n return 'd-flex flex-column justify-content-between row-gap-3';\n\n return 'd-flex align-items-center justify-content-between';\n }\n\n let className = '';\n\n className += 'd-flex align-items-center justify-content-between mb-1';\n\n if (breakpoints.xs)\n className += ' row-gap-3 mb-0';\n\n return className;\n }\n\n function getBottomRowClass(): string {\n let className = 'd-flex align-items-end justify-content-between';\n\n if (breakpoints.xs)\n className += ' row-gap-3 flex-wrap';\n\n return className;\n }\n\n return (\n <div className={getContainerClass()}>\n <div className={getTopRowClass()}>\n <Breadcrumbs breadcrumbs={props.getBreadcrumbs?.()} />\n\n {canShowTabs() && hideAudiences && (\n <ClassificationTabs\n classification={props.classification}\n activeTab={props.activeTab}\n appLinks={props.appLinks}\n presentation={props.presentation}\n />\n )}\n </div>\n\n <div className={getBottomRowClass()}>\n {!hideAudiences && (\n <ClassificationDashboardAudiences\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n appLink={props.appLinks.audience?.()}\n disabled={props.disableAudiences}\n tooltip={props.audienceTooltip}\n disablePersist={!props.isViewingCurrentPresentation}\n />\n )}\n\n {canShowTabs() && !hideAudiences && (\n <ClassificationTabs\n classification={props.classification}\n activeTab={props.activeTab}\n appLinks={props.appLinks}\n presentation={props.presentation}\n />\n )}\n </div>\n </div>\n );\n}\n","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\n\nimport { AnalyticsOptions, HashObject, LocationContext } from 'libs/analytics/interfaces';\n\nimport { ClassificationHeaderDetails } from 'libs/shared/apps/subjects/components/classification-dashboard/classification-header-details/ClassificationHeaderDetails';\nimport { CuratedClassificationEmptyState } from 'libs/shared/apps/subjects/components/classification-dashboard/empty-state/CuratedClassificationEmptyState';\nimport { TableOfContentsContainer } from 'libs/shared/apps/subjects/components/classification-dashboard/table-of-contents/TableOfContents';\nimport { TeacherOnlyEmptyState } from 'libs/shared/apps/subjects/components/classification-dashboard/teacher-only/TeacherOnlyEmptyState';\nimport { useGetTopicsWidgets } from 'libs/shared/apps/subjects/hooks/useGetTopicsWidgets';\nimport { ActionOptions } from 'libs/shared/components/actions/Actions';\nimport { BannerHeader } from 'libs/shared/components/banner-header/BannerHeader';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { DashboardFeedbackData } from 'libs/shared/components/feedback-form/FeedbackForm';\nimport { VideoList } from 'libs/shared/components/video-list/VideoList';\nimport { WidgetHeader } from 'libs/shared/components/widgets/curated-widgets/components/header/WidgetHeader';\nimport { WidgetContainerView } from 'libs/shared/components/widgets/curated-widgets/WidgetContainerView';\nimport { AllClassificationWidgetTemplates } from 'libs/shared/components/widgets/curated-widgets/WidgetProps';\nimport { ClassificationType } from 'libs/shared/enums/ClassificationType';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { LocalPermissionName } from 'libs/shared/enums/PermissionName';\nimport { WidgetTemplate } from 'libs/shared/enums/WidgetTemplate';\nimport { WidgetTypeId } from 'libs/shared/enums/WidgetTypeId';\nimport { useMediaQuery } from 'libs/shared/hooks/UseMediaQuery';\nimport { HasLocalPermissionsFunc, HasPermissionsFunc } from 'libs/shared/hooks/usePermissions';\nimport { useTableOfContentsActiveHeading } from 'libs/shared/hooks/useTableOfContentsActiveHeading';\nimport { useTableOfContentsScroll } from 'libs/shared/hooks/useTableOfContentsScroll';\nimport { CalendarEvent, CalendarEventContentType, Classification, CuratedDashboard, CuratedWidget, CuratedWidgetQueryParams, CurriculumData, DashboardStatus, DashboardTargetType, InteractiveMetadata, Presentation, PresentationAudience } from 'libs/shared/interfaces';\nimport { CommonVideoProps } from 'libs/shared/interfaces/CommonVideoProps';\nimport { CuratedDashboardHelper } from 'libs/shared/utils/DashboardHelper';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nimport { ClassificationComingSoon } from './classification-coming-soon/ClassificationComingSoon';\nimport { ClassificationDashboardNav } from './classification-dashboard-nav/ClassificationDashboardNav';\nimport { ClassificationTab } from './classification-tabs/ClassificationTabs';\n\nconst namespace = 'shared.classificationDashboard';\n\nfunction isHeadingWidget(widget: CuratedWidget) {\n return widget.widgetId === WidgetTypeId.Blurb && widget.templateId === WidgetTemplate.Heading;\n}\n\nfunction isTopicWidget(widget: CuratedWidget) {\n return widget.widgetId === WidgetTypeId.CuratedClassifications || widget.widgetId === WidgetTypeId.Classifications;\n}\n\nexport interface ClassificationDashboardProps {\n dashboard: CuratedDashboard;\n classification: Classification;\n presentation: Presentation;\n hasPermissions: HasPermissionsFunc;\n hasLocalPermissions: HasLocalPermissionsFunc;\n resourceThumbnailFallbackImageUrl: string;\n hasTopicDirectoryDashboard: boolean;\n hasTopicCurriculumDashboard: boolean;\n isTertiaryCustomerWithoutExchange: boolean;\n tab: ClassificationTab;\n specialEvent?: CalendarEvent;\n curriculums: CurriculumData;\n\n audiences: PresentationAudience[];\n activeAudiences?: PresentationAudience[];\n\n getWidgetContentRequest: (\n id: string,\n params: CuratedWidgetQueryParams,\n widgetTemplate: WidgetTemplate\n ) => Flight.Request;\n\n getBannerActions?: () => ActionOptions[];\n getBreadcrumbs?: () => Breadcrumb[];\n onToggleFollow?: (classification: Classification, locationContext: LocationContext) => void;\n canFollowSubjects: boolean;\n onSubmitFeedback?: (feedback: DashboardFeedbackData) => Promise<void>;\n\n appLinks?: AllClassificationWidgetTemplates['appLinks'] & {\n signUp: () => Core.AppLink,\n widgetWizard: () => Core.AppLink,\n previewQuestions: (interactive: InteractiveMetadata) => Core.AppLink,\n classificationCurriculum: (classification: Classification) => Core.AppLink,\n audience: () => Core.AppLink\n };\n\n imageCdnUrl: string;\n emptyImageUrl: string;\n comingSoonImageUrl?: string;\n\n analyticsOptions?: AnalyticsOptions;\n analyticsData?: HashObject;\n\n scrollToWidgetId?: string;\n tableOfContentsId?: string;\n\n // Means the dashboard contains no linked or working filters\n isReadonly?: boolean;\n\n // Means the dashboard is being previewed by ClickView staff either in product or in curator\n isPreviewing?: boolean;\n\n // Means the parent topic for the dashboard has a status of \"Coming Soon\"\n isComingSoon?: boolean;\n\n showFollowButtonSpinner?: boolean;\n \n isViewCurrentPresentation?: boolean;\n\n // By default widgets will always be lazyloaded. We override this behaviour only in extenuating \n // circumstances, such as dynamic rendering for SEO.\n lazyLoad?: boolean;\n\n moviesAndTv?: boolean;\n\n isTeacherOnly?: boolean;\n \n contentType?: CalendarEventContentType;\n\n isBot?: boolean;\n\n settings?: AllClassificationWidgetTemplates['settings'];\n\n commonVideoProps: CommonVideoProps;\n}\n\nClassificationDashboard.defaultProps = {\n appLinks: {}\n};\n\nexport function ClassificationDashboard(props: ClassificationDashboardProps): JSX.Element {\n const { widgets, videoList, videoListWidgetId } = useGetTopicsWidgets(props.dashboard, props.activeAudiences);\n\n const isSmallScreen = useMediaQuery(MediaQueryStrings.LGDown);\n const headingRef = React.useRef<Set<Element>>(new Set());\n\n const initialEmptyWidgets = React.useMemo(() => {\n return widgets.reduce((acc: HashObject<boolean>, widget) => {\n acc[widget.id] = false;\n return acc;\n }, {});\n }, [widgets?.length]);\n\n const [ emptyWidgets, setEmptyWidgets ] = React.useState(initialEmptyWidgets);\n\n const [ controlledId, setControlledId ] = React.useState(props.tableOfContentsId);\n\n const [ tableOfContentActiveId, setTableOfContentActiveId ] = React.useState<string>('');\n\n const headingElements = Array.from(headingRef.current);\n useTableOfContentsScroll(headingElements, controlledId);\n useTableOfContentsActiveHeading({\n setActiveId: setTableOfContentActiveId,\n headingElements,\n controlledId,\n setControlledId\n });\n\n const isHubDashboard = props.classification.type === ClassificationType.Hub;\n\n function shouldShowEmptyState(): boolean {\n if (props.isComingSoon)\n return false;\n\n if (props.isTeacherOnly)\n return false;\n\n if (!props.dashboard)\n return true;\n\n if (props.dashboard.status === DashboardStatus.Archived && !props.isReadonly)\n return true;\n\n if (props.dashboard.status === DashboardStatus.Draft && !props.isPreviewing)\n return true;\n\n if (!widgets?.length)\n return true;\n\n if (videoList && videoList.length)\n return false;\n\n return Object.values(emptyWidgets).every(state => !!state);\n }\n\n function getWidgetContentRequest(id: string, widgetTypeId: WidgetTypeId, template: WidgetTemplate): Flight.Request {\n const params = CuratedDashboardHelper.getWidgetParams(\n widgetTypeId,\n template,\n CuratedDashboardHelper.getDashboardTargetType(props.dashboard),\n props.activeAudiences?.map(a => a.masterId),\n props.curriculums.preferredCurriculum?.id\n );\n\n return props.getWidgetContentRequest(id, params, template);\n }\n\n const showEmptyState = shouldShowEmptyState();\n\n React.useEffect(() => {\n /**\n * When we add the first widget of the dashboard, the showEmptyState is `true`, the WidgetContainer is not going to be rendered to lazyload the `content`\n * so we set the emptyWidget to initial make sure the widget container is rendered to lazyload `widget.content`\n * and let the WidgetContainer to re-set the empty state based on the actual `widget.content` from backend\n */\n if (showEmptyState) {\n setEmptyWidgets(initialEmptyWidgets);\n }\n }, [widgets?.length]);\n\n const onSetIsEmpty = React.useCallback((widgetId: string, isEmpty: boolean) => {\n if (emptyWidgets[widgetId] === isEmpty)\n return;\n\n const newEmptyState = {\n ...emptyWidgets,\n [widgetId]: isEmpty\n };\n\n // The logic beneath this if-block doesn't apply to classification directories. This is because\n // classification directories don't support audience filtering, so widgets should never be empty,\n // meaning headings should never be hidden.\n if (CuratedDashboardHelper.isType(props.dashboard, DashboardTargetType.ClassificationDirectory)) {\n setEmptyWidgets(newEmptyState);\n return;\n }\n\n let index = 0;\n\n /**\n * Every time a widget is identified as empty, we check each heading blurb widget\n * to see if it should be hidden. This will be the case when all widgets beneath a heading\n * (up until the next heading) are empty.\n */\n while (index < widgets.length) {\n const currentWidget = widgets[index];\n\n if (!isHeadingWidget(currentWidget)) {\n index++;\n continue;\n }\n\n let isHeadingEmpty = true;\n let subWidgetIndex = index + 1;\n\n while (isHeadingEmpty && subWidgetIndex < widgets.length) {\n const headingSubWidget = widgets[subWidgetIndex];\n\n if (isHeadingWidget(headingSubWidget))\n break;\n\n if (!newEmptyState[headingSubWidget.id] && !isTopicWidget(headingSubWidget))\n isHeadingEmpty = false;\n\n subWidgetIndex++;\n }\n\n index = subWidgetIndex;\n\n newEmptyState[currentWidget.id] = isHeadingEmpty;\n }\n\n setEmptyWidgets(newEmptyState);\n }, [ emptyWidgets, widgets ]);\n\n function hideWidget(widget: CuratedWidget): boolean {\n return isHeadingWidget(widget) && emptyWidgets[widget.id];\n }\n\n function useLargeDashboardSpacing(): boolean {\n const target = CuratedDashboardHelper.getDashboardTargetType(props.dashboard);\n\n if (props.moviesAndTv || target === DashboardTargetType.ClassificationCurriculum)\n return false;\n\n return true;\n }\n\n function getWidgetHeading(widget: CuratedWidget, index: number): string {\n if (widget.widgetId === WidgetTypeId.ClassificationDashboardExternalMedia) {\n const previousWidget = widgets[index - 1];\n\n if (emptyWidgets[previousWidget.id])\n return widget.name.replace('Other videos', 'Videos');\n\n return widget.name;\n }\n\n return widget.name;\n }\n\n const widgetsInTableOfContents = widgets.filter(w => {\n return !hideWidget(w) && !!w.metadata?.showInTableOfContents;\n });\n\n const isTopicOnlyDashboard = widgets.every(isTopicWidget);\n\n const shouldShowTableOfContents = widgetsInTableOfContents.length >= 2;\n const shouldShowSideTableOfContents = shouldShowTableOfContents && !isSmallScreen && !isHubDashboard;\n\n const shouldShowTopicCounts = (\n props.settings?.hasTopicDirectories &&\n TopicsHelper.isTopLevelTopic(props.classification) &&\n !props.isTertiaryCustomerWithoutExchange\n );\n\n /**\n * We don't put the .topic-dashboard class when we're in a movies and tv classification\n * because we don't want the extra padding between widgets.\n */\n return (\n <div className={`bg-white px-4 ${useLargeDashboardSpacing() ? 'dashboard-spacing-lg' : ''}`}>\n {isHubDashboard && (\n <>\n <h1 className='h2 mb-4'>{props.classification.name}</h1>\n <hr className='mt-2'/>\n </>\n )}\n\n {!isHubDashboard && (\n <BannerHeader\n heading={props.classification.name}\n banner={props.classification.banner}\n imageCdnUrl={props.imageCdnUrl}\n actions={props.getBannerActions?.()}\n actionsDropdownClassName='btn btn-outline-dark'\n specialEvent={props.specialEvent}\n calendarTheme={{\n background: 'bg-light-blue',\n border: 'border-light-blue'\n }}\n showComingSoon={props.isComingSoon}\n detailsComponent={shouldShowTopicCounts ?\n () => <ClassificationHeaderDetails classification={props.classification} /> :\n null\n }\n />\n )}\n\n {!isHubDashboard && (\n <ClassificationDashboardNav\n dashboard={props.dashboard}\n classification={props.classification}\n presentation={props.presentation}\n appLinks={props.appLinks}\n activeTab={props.tab}\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n getBreadcrumbs={props.getBreadcrumbs}\n hasTopicDirectoryDashboard={props.hasTopicDirectoryDashboard}\n hasTopicCurriculumDashboard={props.hasTopicCurriculumDashboard}\n isComingSoon={props.isComingSoon}\n isEmpty={showEmptyState}\n isViewingCurrentPresentation={props.isViewCurrentPresentation}\n disableAudiences={isTopicOnlyDashboard || props.isReadonly}\n audienceTooltip={isTopicOnlyDashboard ? LanguageService.getPhrase(namespace, 'audienceTooltip') : ''}\n />\n )}\n\n {props.isComingSoon && (\n <ClassificationComingSoon\n imageUrl={props.comingSoonImageUrl}\n data={props.classification}\n canFollowSubjects={props.canFollowSubjects}\n showFollowButtonSpinner={props.showFollowButtonSpinner}\n onToggleFollow={() => props.onToggleFollow(props.classification, LocationContext.ClassificationComingSoon)}\n showSignUp={!props.hasLocalPermissions(LocalPermissionName.FollowComingSoonTopics)}\n signUpAppLink={props.appLinks.signUp?.()}\n />\n )}\n\n {!props.isComingSoon && (\n <div className={`${shouldShowSideTableOfContents ? 'row no-wrap' : ''}`}>\n {shouldShowTableOfContents && (\n <TableOfContentsContainer\n widgets={widgetsInTableOfContents}\n title={props.classification.name}\n activeId={tableOfContentActiveId}\n clickable={!props.isReadonly}\n analyticsData={props.analyticsData}\n setControlledId={setControlledId}\n isSmallScreen={isSmallScreen}\n />\n )}\n\n <div className={shouldShowSideTableOfContents ? 'col-9 order-0' : ''}>\n {widgets.map((widget, idx) => {\n if (hideWidget(widget))\n return <React.Fragment key={widget.id}></React.Fragment>;\n\n return (\n <WidgetContainerView\n widgetCollection={DashboardTargetType.Classification}\n headingElementRef={headingRef}\n key={widget.id}\n id={widget.id}\n name={getWidgetHeading(widget, idx)}\n description={widget.description}\n classification={props.classification}\n templateId={widget.templateId}\n widgetTypeId={widget.widgetId}\n audiences={props.audiences}\n getContentRequest={getWidgetContentRequest}\n setIsEmpty={onSetIsEmpty}\n appLinks={props.appLinks}\n presentation={props.presentation}\n analyticsData={props.analyticsData}\n isScrollToTargetWidget={props.scrollToWidgetId === widget.id}\n imageCdnUrl={props.imageCdnUrl}\n onSubmitFeedback={props.onSubmitFeedback}\n metadata={widget.metadata}\n isBot={props.isBot}\n hasTableOfContents={shouldShowSideTableOfContents}\n lazyLoad={props.lazyLoad}\n dashboardTarget={CuratedDashboardHelper.getDashboardTargetType(props.dashboard)}\n widgetIndex={idx}\n hasPermissions={props.hasPermissions}\n hasLocalPermissions={props.hasLocalPermissions}\n isPreviewing={props.isReadonly}\n contentType={props.contentType}\n resourceThumbnailFallbackImageUrl={props.resourceThumbnailFallbackImageUrl}\n onToggleFollowClassification={props.onToggleFollow}\n settings={props.settings}\n isEditing={props.isReadonly}\n isTertiaryCustomerWithoutExchange={props.isTertiaryCustomerWithoutExchange}\n commonVideoProps={props.commonVideoProps}\n curriculums={props.curriculums}\n\n // TODO: Do we actually need this shit if it wasn't even being passed in?\n limitTotalItems={false}\n seeMoreLink={null}\n onClickRemoveItem={null}\n badgeComponent={null}\n />\n );\n })}\n </div>\n\n {!!videoList?.length && (\n <>\n <WidgetHeader name={LanguageService.getPhrase(namespace, 'videos')} />\n <VideoList\n videos={videoList}\n getVideoAppLink={(video, opts) => props.appLinks.videoType(\n video,\n { ...opts, contextId: videoListWidgetId, includeContext: opts.includeContext }\n )}\n hasPermissions={props.hasPermissions}\n presentationAudiences={props.audiences}\n getPreviewQuestionsAppLink={props.appLinks.previewQuestions}\n commonVideoProps={props.commonVideoProps}\n />\n </>\n )}\n </div>\n )}\n\n {showEmptyState && (\n <CuratedClassificationEmptyState\n dashboard={props.dashboard}\n isReadonly={props.isReadonly}\n imageUrl={props.emptyImageUrl}\n addWidgetApplink={props.appLinks.widgetWizard}\n />\n )}\n\n {props.isTeacherOnly && (\n <TeacherOnlyEmptyState\n imageUrl={props.emptyImageUrl}\n ctaAppLink={() => props.appLinks.allTopics(props.classification.presentationId)}\n />\n )}\n </div>\n );\n}\n","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { ErrorCta, ErrorPageError } from 'libs/shared/errors/primitives/ErrorPageError';\n\nimport { Actions } from 'shared/constants/StreamableActions';\nimport { AppChannels } from 'shared/constants/StreamableRadioChannels';\n\nconst namespace = 'subjects.topicNotFoundError';\n\nexport class TopicNotFoundError extends ErrorPageError {\n constructor() {\n super('Topic doesn\\'t exist');\n }\n\n // @ts-ignore\n public get name(): string {\n return 'TopicNotFoundError';\n }\n\n // @ts-ignore\n public get heading(): string {\n return LanguageService.getPhrase(namespace, 'heading');\n }\n\n // @ts-ignore\n public get description(): string {\n return LanguageService.getPhrase(namespace, 'description');\n }\n\n // @ts-ignore\n public get cta(): ErrorCta {\n return {\n text: LanguageService.getPhrase(namespace, 'cta'),\n appLink: {\n application: AppChannels.SUBJECTS,\n action: Actions.Subjects.CLASSIFICATION_ALL\n }\n };\n }\n}\n","import React from 'react';\n\nimport { PartialAudienceFilter } from 'libs/shared/apps/subjects/components/audience-filter/AudienceFilter';\nimport { PartialBannerHeader } from 'libs/shared/components/banner-header/BannerHeader';\nimport { PartialBreadcrumbs } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\n\nexport function PartialClassification(): JSX.Element {\n return (\n <div className='bg-white px-4'>\n <PartialBannerHeader />\n\n <div className='d-flex flex-column row-gap-3 py-3 mb-3 border-bottom'>\n <PartialBreadcrumbs />\n <PartialAudienceFilter />\n </div>\n </div>\n );\n}\n","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { HashObject } from 'libs/common/react/interfaces';\n\nimport { ClassificationDashboardProps } from 'libs/shared/apps/subjects/components/classification-dashboard/ClassificationDashboard';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { Classification } from 'libs/shared/interfaces';\n\nimport { Actions } from 'shared/constants/StreamableActions';\nimport { AppChannels } from 'shared/constants/StreamableRadioChannels';\nimport { StreamableAppLinks } from 'shared/utils/StreamableAppLinks';\n\nconst namespace = 'subjects.classificationView';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport function getClassificationAppLinks(\n classification: Classification,\n params: HashObject\n): ClassificationDashboardProps['appLinks'] {\n return {\n ...StreamableAppLinks,\n classification: c => StreamableAppLinks.classification(c || classification, params),\n classificationDirectory: () => StreamableAppLinks.classificationDirectory(params),\n audience: () => StreamableAppLinks.classification(classification, params),\n\n // TODO: Find a nice way around having to pass these in\n previewQuestions: () => null,\n series: () => null,\n latestReleases: () => null,\n classificationLatestReleases: () => null,\n playlist: () => null,\n signUp: () => null,\n widgetWizard: () => null,\n classificationCurriculum: () => null,\n searchSettings: () => null,\n searchHome: () => null,\n search: () => null,\n editCurriculum: () => null,\n getPreviewQuestionsAppLink: () => null\n };\n}\n\ninterface GetClassificationBreadcrumbsOptions {\n classification: Classification;\n path: Classification[];\n appLinks: ClassificationDashboardProps['appLinks'];\n}\n\nexport function getClassificationBreadcrumbs(\n options: GetClassificationBreadcrumbsOptions\n): Breadcrumb[] {\n const { classification, path, appLinks } = options;\n\n const breadcrumbs: Breadcrumb[] = [{\n name: getPhrase('discover'),\n appLink: {\n application: AppChannels.DASHBOARD,\n action: Actions.Dashboard.HOME\n }\n }, {\n name: getPhrase('exploreAllTopicsHeading'),\n appLink: {\n application: AppChannels.SUBJECTS,\n action: Actions.Subjects.CLASSIFICATION_ALL\n }\n }];\n\n path.forEach(item => {\n breadcrumbs.push({\n name: item.name,\n appLink: appLinks.classification(item),\n active: item.name === classification.name\n });\n });\n\n return breadcrumbs;\n}\n","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\nimport { ObjectHelper } from 'libs/common/react/utils/ObjectHelper';\n\nimport { ClassificationDashboard } from 'libs/shared/apps/subjects/components/classification-dashboard/ClassificationDashboard';\nimport { PreviewBanner } from 'libs/shared/apps/subjects/components/preview-banner/PreviewBanner';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { VideoActionsContext } from 'libs/shared/context/VideoActionsContext';\nimport { PresentationType } from 'libs/shared/enums/PresentationType';\nimport { AudienceRequests } from 'libs/shared/flight-requests/AudienceRequests';\nimport { ClassificationRequests } from 'libs/shared/flight-requests/ClassificationRequests';\nimport { ConfigRequests } from 'libs/shared/flight-requests/ConfigRequests';\nimport { DashboardRequests } from 'libs/shared/flight-requests/DashboardRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { useHandleObjectError } from 'libs/shared/hooks/UseHandleObjectError';\nimport { useSetPageMetadata } from 'libs/shared/hooks/useSetPageMetadata';\nimport { AudienceFilterParams, CalendarEventContentType, Classification, Config, CurrentUser, DashboardTargetType, Presentation, PresentationAudience } from 'libs/shared/interfaces';\nimport { AudienceHelper } from 'libs/shared/utils/audience-helper/AudienceHelper';\nimport { PageMetadataHelper } from 'libs/shared/utils/PageMetadataHelper';\n\nimport { ImageUrls } from 'shared/constants/ImageUrls';\nimport { StreamableConstants } from 'shared/constants/StreamableConstants';\nimport { PresentationRequests } from 'shared/flight-requests/PresentationRequests';\nimport { useCommonVideoProps } from 'shared/hooks/useCommonVideoProps';\nimport { useFetchDashboard } from 'shared/hooks/useFetchDashboard';\nimport { useStreamableVideoActions } from 'shared/hooks/useStreamableVideoActions';\nimport { SeoHelper } from 'shared/utils/StreamableSeoHelper';\n\nimport { TopicNotFoundError } from 'apps/subjects/errors/TopicNotFoundError';\nimport { useCurriculums } from 'apps/videos/hooks/useCurriculums';\n\nimport { PartialClassification } from './partial-loading/PartialClassification';\nimport { getClassificationAppLinks, getClassificationBreadcrumbs } from './StreamableClassificationViewUtils';\n\nconst namespace = 'subjects.classificationView';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport interface StreamableClassificationViewQueryParams extends AudienceFilterParams {\n dashboardId?: string;\n tocId?: string;\n}\n\nexport function sanitizeStreamableClassificationParams(\n queryParams: StreamableClassificationViewQueryParams\n): StreamableClassificationViewQueryParams {\n if (!queryParams)\n return {};\n\n return ObjectHelper.pick(queryParams, [ 'a', 'dashboardId', 'tocId' ]);\n}\n\ninterface StreamableClassificationViewProps {\n id: string;\n queryParams: StreamableClassificationViewQueryParams;\n}\n\nexport function StreamableClassificationView(props: StreamableClassificationViewProps): JSX.Element {\n const getVideoActions = useStreamableVideoActions('video-list');\n\n const { commonVideoProps } = useCommonVideoProps();\n\n const config = Flight.useBasicFetch<Config>(ConfigRequests.config());\n const currentUser = Flight.useBasicFetch<CurrentUser>(UserRequests.currentUser());\n const curriculumData = useCurriculums();\n\n const presentation = Flight.useBasicFetch<Presentation>(\n PresentationRequests.streamablePresentation()\n );\n\n const classification = Flight.useBasicFetch<Classification>(\n ClassificationRequests.classification(props.id, currentUser.data?.id)\n );\n\n const { dashboard, isPreviewing } = useFetchDashboard({\n targetType: DashboardTargetType.Classification,\n dashboardId: props.queryParams?.dashboardId,\n classificationId: props.id\n });\n\n const appLinks = getClassificationAppLinks(classification.data, props.queryParams);\n\n useSetPageMetadata(PageMetadataHelper.getClassificationMetadata({\n content: { classification: classification.data },\n phraseContext: {\n phraseHandler: getPhrase,\n titlePhrase: 'pageTitle',\n descriptionPhrase: 'pageDescription'\n },\n canonicalLink: SeoHelper.getCanonicalLink({\n customAppLink: appLinks.classification(classification.data)\n }),\n allowIndexing: true,\n product: StreamableConstants.PRODUCT_NAME\n }));\n\n useHandleObjectError(classification, {\n notFound: TopicNotFoundError\n });\n\n const audiences = Flight.useBasicFetch<PresentationAudience[]>(presentation.data &&\n AudienceRequests.presentationAudiences(PresentationType.StreamableLearning, presentation.data.id));\n\n const path = Flight.useBasicFetch<Classification[]>(\n ClassificationRequests.path(props.id, PresentationType.StreamableLearning)\n );\n\n /**\n * We use the current active audiences to re-fetch content for that specific audience set.\n */\n const activeAudiences = React.useMemo(\n () => AudienceHelper.getActiveAudiencesFromParams(audiences.data, props.queryParams),\n [ audiences.data, props.queryParams ]\n );\n const activeAudienceIds = activeAudiences?.map(a => a.masterId) ?? [];\n\n /**\n * Additional topics data to be mixed in with lower-level component analytics collection\n */\n const analyticsData = {\n presentationId: presentation.data?.id,\n presentationName: presentation.data?.name,\n currentClassificationId: classification.data?.id,\n currentClassificationName: classification.data?.name,\n followingCurrentClassification: !!classification.data?.followers?.data?.length,\n activeAudienceNames: activeAudiences?.length ? activeAudiences.map(a => a.name) : null,\n activeAudienceIds: activeAudienceIds.length ? activeAudienceIds : null\n };\n\n function getBreadcrumbs(): () => Breadcrumb[] {\n return () => getClassificationBreadcrumbs({\n appLinks: appLinks,\n classification: classification.data,\n path: path.data\n });\n }\n\n const dataLoaded = !!config.data\n && dashboard.hasCompleted\n && !!classification.data\n && !!presentation.data\n && !!path.data\n && !!audiences.data;\n\n if (!dataLoaded)\n return <PartialClassification />;\n\n return (\n <VideoActionsContext.Provider value={{ getVideoActions }}>\n <div className='position-relative'>\n {!!(isPreviewing && dashboard.data) && <PreviewBanner status={dashboard.data.status} type='topic' />}\n <ClassificationDashboard\n dashboard={dashboard.data}\n classification={classification.data}\n getWidgetContentRequest={DashboardRequests.dashboardWidgetContent}\n getBreadcrumbs={getBreadcrumbs()}\n hasPermissions={() => false}\n hasLocalPermissions={() => false}\n presentation={presentation.data}\n getBannerActions={() => []}\n audiences={audiences.data}\n activeAudiences={activeAudiences}\n analyticsData={analyticsData}\n imageCdnUrl={config.data.imageCdnUrl}\n resourceThumbnailFallbackImageUrl={ImageUrls.Fallbacks.RESOURCE_THUMBNAIL}\n emptyImageUrl={ImageUrls.EmptyStates.Topics.TOPIC}\n appLinks={appLinks}\n isPreviewing={isPreviewing}\n isViewCurrentPresentation\n canFollowSubjects={false}\n tableOfContentsId={props.queryParams.tocId}\n lazyLoad={!SeoHelper.isBot()}\n isTeacherOnly={false}\n contentType={CalendarEventContentType.Livestream}\n hasTopicDirectoryDashboard={false}\n hasTopicCurriculumDashboard={false}\n isTertiaryCustomerWithoutExchange={false}\n tab='curated-topic'\n curriculums={curriculumData}\n // just... one... more.. prop....\n commonVideoProps={commonVideoProps}\n />\n </div>\n </VideoActionsContext.Provider>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"D3sdyN2Q2.chunk.js","names":[],"sources":["../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-header-details/ClassificationHeaderDetails.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/empty-state/CuratedClassificationEmptyState.tsx","../../../../libs/shared/src/components/table-of-contents-list/table-of-contents-list.module.scss","../../../../libs/shared/src/components/table-of-contents-list/TableOfContentsList.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/table-of-contents/table-of-contents.module.scss","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/table-of-contents/TableOfContents.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/teacher-only/TeacherOnlyEmptyState.tsx","../../../../libs/shared/src/apps/subjects/hooks/useGetTopicsWidgets.ts","../../../../libs/shared/src/hooks/useTableOfContentsActiveHeading.tsx","../../../../libs/shared/src/hooks/usePrevious.ts","../../../../libs/shared/src/hooks/useTableOfContentsScroll.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-coming-soon/ClassificationComingSoon.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/audiences/ClassificationDashboardAudiences.tsx","../../../../libs/shared/src/images/svg/widgets/WidgetSeriesSvg.tsx","../../../../libs/shared/src/apps/subjects/hooks/useDirectoryTabProductTipSwitcher.ts","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-tabs/classification-tabs.module.scss","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-tabs/ClassificationTabs.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/classification-dashboard-nav/ClassificationDashboardNav.tsx","../../../../libs/shared/src/apps/subjects/components/classification-dashboard/ClassificationDashboard.tsx","../../src/apps/subjects/errors/TopicNotFoundError.ts","../../src/apps/subjects/views/classification/partial-loading/PartialClassification.tsx","../../src/apps/subjects/views/classification/StreamableClassificationViewUtils.ts","../../src/apps/subjects/views/classification/StreamableClassificationView.tsx"],"sourcesContent":["import React from 'react';\n\nimport { Text } from 'libs/shared/components/text/Text';\nimport { Classification } from 'libs/shared/interfaces';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nconst namespace = 'subject.classificationHeaderDetails';\n\nconst Separator = ({ className }: { className: string }) =>\n <span className={className}>•</span>;\n\ninterface ClassificationHeaderDetailsProps {\n classification: Classification;\n}\n\nexport function ClassificationHeaderDetails(props: ClassificationHeaderDetailsProps): React.ReactElement {\n const {\n dashboardVideoCount,\n childDashboardVideoCount,\n dashboardResourceCount,\n childDashboardResourceCount,\n childClassificationCount\n } = TopicsHelper.getCounts(props.classification);\n\n const videoCount = dashboardVideoCount + childDashboardVideoCount;\n const resourceCount = dashboardResourceCount + childDashboardResourceCount;\n\n return (\n <p className='mb-n1 font-size-normal fw-normal mt-1'>\n {!!childClassificationCount && (\n <Text\n namespace={namespace}\n phrase='topics'\n options={{ count: childClassificationCount.toLocaleString(), smartCount: childClassificationCount }}\n />\n )}\n\n {!!videoCount && (\n <>\n {childClassificationCount > 0 && <Separator className='mx-2' />}\n <Text\n namespace={namespace}\n phrase='videos'\n options={{ count: videoCount.toLocaleString(), smartCount: videoCount }}\n />\n </>\n )}\n {!!resourceCount && (\n <>\n <Separator className='mx-2' />\n <Text\n namespace={namespace}\n phrase='resources'\n options={{ count: resourceCount.toLocaleString(), smartCount: resourceCount }}\n />\n </>\n )}\n </p>\n );\n}\n","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\n\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\nimport { Tooltip } from 'libs/shared/components/tooltip/Tooltip';\nimport { PlusSvg } from 'libs/shared/images/svg/actions/PlusSvg';\nimport { CuratedDashboard, DashboardStatus } from 'libs/shared/interfaces';\n\nconst namespace = 'subjects.curatedClassificationEmptyState';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface CuratedClassificationEmptyStateProps {\n dashboard: CuratedDashboard;\n imageUrl: string;\n isReadonly: boolean;\n addWidgetApplink?: () => Core.AppLink;\n}\n\nexport function CuratedClassificationEmptyState(props: CuratedClassificationEmptyStateProps): JSX.Element {\n const isArchived = props.dashboard?.status === DashboardStatus.Archived;\n\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState>\n <EmptyState.Image src={props.imageUrl} altText={getPhrase('headingForNP')} />\n {!props.isReadonly ? (\n <EmptyState.Heading>\n <Text phrase='headingForNP' />\n </EmptyState.Heading>\n ) : (\n <>\n <EmptyState.Heading>\n <Text namespace={namespace} phrase='headingForCurator' />\n </EmptyState.Heading>\n <EmptyState.Info>\n <Text namespace={namespace} phrase='info' />\n </EmptyState.Info>\n <Tooltip title={isArchived ? LanguageService.getPhrase(namespace, 'archivedCtaTooltip') : ''} spanHack>\n <EmptyState.Cta\n text={LanguageService.getPhrase(namespace, 'add')}\n appLink={props.addWidgetApplink?.()}\n className='btn btn-dark'\n icon={PlusSvg}\n disabled={isArchived}\n />\n </Tooltip>\n </>\n )}\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n",":local{\n $dot-size: 0.75rem;\n $track-offset: -1rem;\n\n @mixin dot {\n &::before {\n position: absolute;\n left: -1.06rem;\n top: calc(50% - $dot-size/2);\n display: block;\n content: '';\n height: $dot-size;\n width: $dot-size;\n border-radius: 50%;\n background-color: $black;\n }\n }\n\n @mixin tocIndent($depth) {\n margin-left: map-get($spacers, 3) * $depth;\n }\n \n .itemsWrapper {\n border-left: 2px solid $black;\n padding-left: 0.625rem;\n }\n\n .anchorWrapper {\n padding: 0.625rem;\n text-decoration: none;\n position: relative;\n display: block;\n }\n .anchorWrapper:hover {\n background-color: $light-blue;\n text-decoration: none;\n cursor: pointer;\n }\n\n .anchorWrapper:first-child {\n &::after {\n display: block;\n content: '';\n background-color: $white;\n height: calc(50% - $dot-size/2 + 0.05rem);\n width: 0.625rem;\n top: -0.05rem;\n position: absolute;\n left: $track-offset;\n }\n }\n .anchorWrapper:last-child {\n &::after {\n display: block;\n content: '';\n background-color: $white;\n height: calc(50% - $dot-size/2);\n width: 0.625rem;\n position: absolute;\n bottom: 0;\n left: $track-offset;\n }\n }\n\n .default {\n @include dot\n }\n\n .selectedItem {\n background-color: $gray-100;\n font-weight: 500;\n @include dot\n }\n \n .disabled:hover {\n cursor: default;\n background-color: $white;\n }\n .disabled{\n pointer-events:none\n }\n\n .floatIcon {\n position: absolute;\n right: 0;\n width: fit-content;\n padding: 0;\n .arrowIcon {\n display: none;\n }\n .listIcon {\n display: block;\n }\n &:hover {\n .listIcon {\n display: none;\n }\n .arrowIcon {\n display: block;\n }\n }\n }\n\n .tocIndent1 {\n @include tocIndent(1);\n }\n\n .tocIndent2 {\n @include tocIndent(2);\n }\n}","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { ScrollHelper } from 'libs/common/backbone/utils/ScrollHelper';\n\nimport { EntityType, HashObject, LocationContext, UserAction } from 'libs/analytics/interfaces';\n\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { DivButton } from 'libs/shared/components/div-button/DivButton';\n\nimport styles from './table-of-contents-list.module.scss';\n\nexport interface TableOfContentsItem<T=string> {\n name: string;\n id: T;\n tocIndentation?: number;\n}\n\ninterface TableOfContentsProps<T> {\n items: TableOfContentsItem<T>[];\n activeId: string;\n appLink?: Core.AppLink;\n analyticsData?: HashObject;\n setControlledId: (arg: string) => void;\n // set to true if the TOC is controlled by a local state rather than query params\n localState?: boolean;\n getAppLink?: (args: TableOfContentsItem<T>) => Core.AppLink;\n onItemClick?: (args: TableOfContentsItem<T>) => void;\n}\n\nexport function TableOfContentsList<T extends string>(props: TableOfContentsProps<T>): JSX.Element {\n const analyticsOptions = {\n actionType: UserAction.Click,\n entity: EntityType.Widget,\n location: LocationContext.TableOfContents\n };\n\n function onItemSelect(item: TableOfContentsItem<T>) {\n ScrollHelper.preventScrollTop();\n props.setControlledId(item.id);\n \n props.onItemClick?.(item);\n \n setTimeout(() => document.getElementById(item.id)?.focus());\n }\n\n function getTocIndentClass(item: TableOfContentsItem<T>): string {\n if (item.tocIndentation === 1)\n return styles.tocIndent1;\n \n if (item.tocIndentation === 2)\n return styles.tocIndent2;\n\n return '';\n }\n\n return (\n <div className={`${styles.itemsWrapper}`}>\n {props.items.map((item, idx) => {\n if (props.localState) {\n return (\n <DivButton\n key={item.id}\n className={`${styles.anchorWrapper} ${props.activeId === item.id ? styles.selectedItem : ''}`}\n onClick={() => {\n onItemSelect(item);\n }}\n >\n <div className={`${!props.activeId && idx === 0 ? styles.default : ''} `}>\n {item.name}\n </div>\n </DivButton>\n );\n }\n\n return (\n <AppLink\n key={item.id}\n appLink={props.getAppLink(item)}\n appLinkOptions={{ replace: true }}\n className={`${styles.anchorWrapper} ${props.activeId === item.id ? styles.selectedItem : ''}`}\n onClick={() => {\n onItemSelect(item);\n }}\n analyticsData={{\n ...props.analyticsData,\n id: item.id,\n name: item.name\n }}\n analyticsOptions={analyticsOptions}\n >\n <div className={`${!props.activeId && idx === 0 ? styles.default : ''} ${getTocIndentClass(item)}`}>\n {item.name}\n </div>\n </AppLink>\n );\n })}\n </div>\n );\n}\n","$top-nav-height: 4.1875rem;\n$cv-banner-height: calc(100vw * 22 / 120);\n$filters-area: 7.87rem;\n\n.container {\n position: sticky;\n top: 6.25rem;\n z-index: 80;\n}\n\n.mobile {\n position: fixed;\n top: calc($top-nav-height + $cv-banner-height + $filters-area);\n z-index: 80;\n right: 0;\n}","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { EntityType, HashObject, LocationContext, UserAction } from 'libs/analytics/interfaces';\n\nimport { IconButton } from 'libs/shared/components/icon-button/IconButton';\nimport { TableOfContentsList } from 'libs/shared/components/table-of-contents-list/TableOfContentsList';\nimport { TableOfContentsSvg } from 'libs/shared/images/svg/objects/TableOfContentsSvg';\nimport { CuratedWidget } from 'libs/shared/interfaces';\nimport { ContextService } from 'libs/shared/services/ContextService';\n\nimport styles from './table-of-contents.module.scss';\n\ninterface TableOfContentsContainerProps {\n widgets: CuratedWidget[];\n title: string;\n activeId: string;\n appLink?: Core.AppLink;\n clickable?: boolean;\n analyticsData?: HashObject;\n setControlledId: (arg: string) => void;\n isSmallScreen?: boolean;\n}\ninterface TableOfContentsProps extends TableOfContentsContainerProps {\n getAppLink: (widget: CuratedWidget) => Core.AppLink;\n}\n\nfunction TableOfContentsMobile(props: TableOfContentsProps) {\n const [ isExpanded, setIsExpanded ] = React.useState(false);\n\n function logUserAction() {\n const analyticsOptions = {\n actionType: !isExpanded ? UserAction.Open : UserAction.Hide,\n entity: EntityType.TableOfContents,\n location: LocationContext.Dashboard\n };\n\n AnalyticsHelper.logUserAction(props.analyticsData, analyticsOptions);\n }\n\n function onClickIcon() {\n setIsExpanded(!isExpanded);\n logUserAction();\n }\n\n return (\n <div className={`${styles.mobile} d-inline-flex gap-1`}>\n \n {isExpanded && (\n <div className='bg-white px-3 pt-3 pb-2 border border-dark rounded-1 ps-3'>\n <h2 className='h5'>{props.title}</h2>\n <TableOfContentsList\n items={props.widgets.map(widget => (\n { name: widget.name, id: widget.id, tocIndentation: widget.metadata.tocIndentation }\n ))}\n activeId={props.activeId}\n appLink={props.appLink}\n analyticsData={props.analyticsData}\n setControlledId={props.setControlledId}\n getAppLink={props.getAppLink}\n onItemClick={() => setIsExpanded(false)}\n />\n </div>\n )}\n <div className={styles.container}>\n <IconButton\n className='btn btn-outline-dark'\n svg={TableOfContentsSvg}\n onClick={onClickIcon}\n />\n </div>\n </div>\n );\n}\n\nfunction TableOfContents(props: TableOfContentsProps): JSX.Element {\n return (\n <aside className='col-3 order-1'>\n <div className={`${styles.container} ps-3`}>\n <h2 className='h5'>{props.title}</h2>\n \n <TableOfContentsList\n items={props.widgets.map(widget => (\n { name: widget.name, id: widget.id, tocIndentation: widget.metadata.tocIndentation }\n ))}\n activeId={props.activeId}\n appLink={props.appLink}\n analyticsData={props.analyticsData}\n setControlledId={props.setControlledId}\n getAppLink={props.getAppLink}\n />\n </div>\n </aside>\n );\n}\n\nexport function TableOfContentsContainer(props: TableOfContentsContainerProps): JSX.Element {\n function getAppLink(widget: CuratedWidget): Core.AppLink {\n const currentAppLink = ContextService.getCurrentRoute().appLink;\n \n const params: HashObject = currentAppLink.params ?\n { ...(currentAppLink.params as HashObject) } :\n {};\n\n params.tocId = widget.id;\n\n return {\n ...currentAppLink,\n params\n };\n }\n\n return (\n <>\n {!props.isSmallScreen ?\n <TableOfContents {...props} getAppLink={getAppLink} /> :\n <TableOfContentsMobile {...props} getAppLink={getAppLink} />\n }\n </>\n );\n}\n","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\n\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\n\nconst namespace = 'subjects.teacherOnlyEmptyState';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface TeacherOnlyEmptyStateProps {\n imageUrl: string;\n ctaAppLink?: () => Core.AppLink;\n}\n\nexport function TeacherOnlyEmptyState(props: TeacherOnlyEmptyStateProps): JSX.Element {\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState>\n <EmptyState.Image src={props.imageUrl} altText={getPhrase('heading')} />\n <EmptyState.Heading>\n <Text phrase='heading' />\n </EmptyState.Heading>\n <EmptyState.Info>\n <Text phrase='info' />\n </EmptyState.Info>\n\n <EmptyState.Cta\n text={getPhrase('cta')}\n appLink={props.ctaAppLink?.()}\n className='btn btn-dark'\n />\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n","import React from 'react';\n\nimport { Flight } from 'libs/common/react/index';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { WidgetTemplate } from 'libs/shared/enums/WidgetTemplate';\nimport { WidgetTypeId } from 'libs/shared/enums/WidgetTypeId';\nimport { DashboardRequests } from 'libs/shared/flight-requests/DashboardRequests';\nimport { CuratedDashboard, CuratedMediaWidget, CuratedWidget, PresentationAudience, Video } from 'libs/shared/interfaces';\nimport { CuratedDashboardHelper } from 'libs/shared/utils/DashboardHelper';\n\nexport interface Response {\n widgets: CuratedWidget[];\n\n videoList?: Video[];\n videoListWidgetId?: string;\n}\n\n/**\n * This hook helps us with custom logic for to display system generated dashboards in a slightly\n * different way.\n */\nexport function useGetTopicsWidgets(dashboard: CuratedDashboard, activeAudiences: PresentationAudience[]): Response {\n const {\n isSystemGeneratedDashboard,\n systemGeneratedVideoWidget\n } = React.useMemo(() => {\n if (!dashboard) {\n return {\n isSystemGeneratedDashboard: false,\n systemGeneratedVideoWidget: null\n };\n }\n\n const isSystemGeneratedDashboard = CuratedDashboardHelper.isSystemGeneratedDashboard(dashboard.widgets);\n\n return {\n isSystemGeneratedDashboard,\n systemGeneratedVideoWidget: dashboard.widgets.find(widget => {\n return (\n widget.widgetId === WidgetTypeId.ClassificationPinnedVideos &&\n widget.templateId !== WidgetTemplate.ThumbnailVerticalList\n );\n })\n };\n }, [dashboard?.id]);\n\n const systemGeneratedVideoContent = Flight.useBasicFetch<CuratedMediaWidget<Video[]>>(\n !!systemGeneratedVideoWidget &&\n DashboardRequests.dashboardWidgetContent(\n systemGeneratedVideoWidget?.id,\n CuratedDashboardHelper.getWidgetParams(\n systemGeneratedVideoWidget.widgetId,\n systemGeneratedVideoWidget.templateId,\n CuratedDashboardHelper.getDashboardTargetType(dashboard),\n activeAudiences?.map(a => a.masterId)\n ),\n systemGeneratedVideoWidget?.templateId\n )\n );\n\n // Non system generated dashboards are returned as per usual\n if (!isSystemGeneratedDashboard)\n return { widgets: ArrayHelper.sortBy(dashboard?.widgets, 'index') };\n\n // System generated dashboard have the video widget removed and returned as a separate video list\n return {\n widgets: dashboard?.widgets?.filter(widget => {\n if (widget.widgetId !== WidgetTypeId.ClassificationPinnedVideos)\n return true;\n\n if (widget.templateId === WidgetTemplate.ThumbnailVerticalList)\n return true;\n\n return false;\n }) ?? [],\n videoList: systemGeneratedVideoContent.data?.content ?? [],\n videoListWidgetId: systemGeneratedVideoWidget?.id\n };\n}\n","import React from 'react';\n\ntype TableOfContentsActiveOption = {\n setActiveId: (id: string) => void,\n headingElements: Element[],\n controlledId?: string,\n setControlledId?: (arg: string) => void\n};\n\nlet timer: number;\n\nexport const useTableOfContentsActiveHeading = (\n { setActiveId, headingElements, controlledId, setControlledId }: TableOfContentsActiveOption\n) => {\n const scrollPositionRef = React.useRef(0);\n\n React.useEffect(() => {\n const callback = (headings: IntersectionObserverEntry[]) => {\n headings.forEach(heading => {\n if (controlledId) {\n setActiveId(controlledId);\n // can use scrollEnd event when the new event type is supported\n timer = window.setTimeout(() => {\n setControlledId('');\n }, 800);\n return;\n }\n if (heading.isIntersecting) {\n setActiveId(heading.target.id);\n scrollPositionRef.current = window.scrollY;\n } else {\n const scrollDistance = scrollPositionRef.current - window.scrollY;\n const isScrollingUp = scrollDistance > 0;\n const curIndex = headingElements.findIndex(h => h.id === heading.target.id);\n const prevHeading = headingElements[curIndex - 1];\n if (isScrollingUp && prevHeading?.id) {\n setActiveId(prevHeading?.id);\n }\n }\n });\n };\n\n const observer = new IntersectionObserver(callback, {\n // rootMargin top: same as the cv-nav-height\n rootMargin: '-67px 0px -80% 0px'\n });\n\n headingElements.forEach(element => observer.observe(element));\n\n return () => {\n timer && window.clearTimeout(timer);\n observer.disconnect();\n };\n }, [ setActiveId, headingElements.length, controlledId ]);\n};\n\n","import React from 'react';\n\n// https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state\nexport function usePrevious<T>(value: T): T {\n const ref = React.useRef<T>(null);\n React.useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n}\n","import React from 'react';\n\nimport { usePrevious } from './usePrevious';\n\nconst HEADER_OFFSET = 80; // Size of header + some extra spacing\n\nexport const useTableOfContentsScroll = (elements: Element[], activeId: string) => {\n const [ hasDoneInitialScroll, setHasDoneInitialScroll ] = React.useState(false);\n\n const previousId = usePrevious(activeId);\n const currentId = activeId;\n\n React.useLayoutEffect(() => {\n if (!hasDoneInitialScroll || previousId !== currentId) {\n const target = elements.find(heading => heading && (heading?.id === currentId));\n\n if (target) {\n const rec = target.getBoundingClientRect();\n\n window.scrollBy({\n top: rec.top - HEADER_OFFSET,\n behavior: 'smooth'\n });\n \n if (!hasDoneInitialScroll)\n setHasDoneInitialScroll(true);\n }\n }\n }, [ elements, previousId, currentId, hasDoneInitialScroll ]);\n};\n","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { EntityType, LocationContext, SignUpDescriptors, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { ActionButton } from 'libs/shared/components/actions/ActionButton';\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { EmptyState } from 'libs/shared/components/empty-states/EmptyState';\nimport { LanguageNamespaceContext, Text } from 'libs/shared/components/text/Text';\nimport { BellFilledSvg } from 'libs/shared/images/svg/objects/BellFilledSvg';\nimport { BellSvg } from 'libs/shared/images/svg/objects/BellSvg';\nimport { Classification } from 'libs/shared/interfaces';\n\nconst namespace = 'subjects.classificationComingSoon';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface ComingSoonProps {\n data: Classification;\n onToggleFollow?: () => void;\n canFollowSubjects: boolean;\n imageUrl: string;\n showFollowButtonSpinner: boolean;\n showSignUp: boolean;\n signUpAppLink: Core.AppLink;\n}\n\nexport function ClassificationComingSoon(props: ComingSoonProps): JSX.Element {\n const isFollowing = !!props.data.followers?.data?.length;\n function onClick(): void {\n props.onToggleFollow?.();\n }\n\n return (\n <LanguageNamespaceContext.Provider value={namespace}>\n <EmptyState className='pt-0'>\n <EmptyState.Image src={props.imageUrl} altText={getPhrase('comingSoon')} />\n\n <EmptyState.Heading>\n <Text phrase='comingSoon' />\n </EmptyState.Heading>\n\n <EmptyState.Info>\n <Text phrase={props.showSignUp ? 'infoAnon' : 'info'} />\n </EmptyState.Info>\n\n {props.canFollowSubjects && (\n <ActionButton\n svg={isFollowing ? BellFilledSvg : BellSvg}\n onClick={onClick}\n showSpinner={props.showFollowButtonSpinner}\n className={`btn follow-btn me-2 ${isFollowing ? 'btn-outline-dark' : 'btn-dark'}`}\n >\n <Text phrase={isFollowing ? 'following' : 'follow'} />\n </ActionButton>\n )}\n\n {props.showSignUp && !props.canFollowSubjects && (\n <AppLink\n appLink={props.signUpAppLink}\n className='btn btn-dark d-none d-lg-inline-block'\n analyticsOptions={{\n actionType: UserAction.Click,\n location: LocationContext.ClassificationComingSoon,\n entity: EntityType.AppLink,\n workflowPhase: WorkflowPhase.Start,\n descriptor: SignUpDescriptors.SignUp\n }}\n analyticsData={{}}\n tag='button'\n >\n {getPhrase('signUp')}\n </AppLink>\n )}\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}\n","import React from 'react';\n\nimport { Core } from 'libs/common/core';\n\nimport { AudienceFilter } from 'libs/shared/apps/subjects/components/audience-filter/AudienceFilter';\nimport { PresentationAudience } from 'libs/shared/interfaces';\n\ninterface ClassificationDashboardAudiencesProps {\n audiences: PresentationAudience[];\n activeAudiences: PresentationAudience[];\n appLink: Core.AppLink;\n disabled: boolean;\n disablePersist: boolean;\n tooltip: string;\n}\n\nexport function ClassificationDashboardAudiences(props: ClassificationDashboardAudiencesProps): JSX.Element {\n return (\n <AudienceFilter\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n disabled={props.disabled}\n appLink={props.appLink}\n disablePersist={props.disablePersist}\n tooltip={props.tooltip}\n />\n );\n}\n","import React from 'react';\n\nexport function WidgetSeriesSvg(props: React.SVGProps<SVGSVGElement>) {\n return (\n <svg {...props}>\n <path\n d='M4.5 4a.5.5 0 0 0 0 1h16a.5.5 0 0 1 .5.5v12a.5.5 0 0 0 1 0v-12A1.5 1.5 0 0 0 20.5 4zM9 10.26a.256.256 0 0 1 .39-.218l4.482 2.74a.256.256 0 0 1 0 .437L9.39 15.958A.256.256 0 0 1 9 15.739zM18.5 6A1.5 1.5 0 0 1 20 7.5v11a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 2 18.5v-11A1.5 1.5 0 0 1 3.5 6zm-15 1a.5.5 0 0 0-.5.5v11a.5.5 0 0 0 .5.5h15a.5.5 0 0 0 .5-.5v-11a.5.5 0 0 0-.5-.5z'\n fill='currentColor'\n />\n </svg>\n );\n}\n","import React from 'react';\n\nimport { useViewModel } from 'libs/common/react/hooks/UseViewModel';\n\nimport { ClassificationTab } from '../components/classification-dashboard/classification-tabs/ClassificationTabs';\n\ninterface ViewModel {\n tab: ClassificationTab;\n on: boolean;\n}\n\nexport function useDirectoryTabProductTipSwitcher(initialTab?: ClassificationTab) {\n const initialState: ViewModel = {\n on: false,\n tab: initialTab || 'new-releases'\n };\n\n const [ viewModel, setViewModel ] = useViewModel<ViewModel>('directory:product:tip:switcher', initialState);\n\n React.useEffect(() => {\n if (!initialTab)\n return;\n\n setViewModel('tab', initialTab);\n }, [initialTab]);\n\n React.useEffect(() => {\n let interval: number = null;\n\n if (viewModel.on) {\n interval = window.setInterval(() => {\n if (viewModel.tab === 'new-releases' || viewModel.tab === 'all-topics')\n setViewModel('tab', viewModel.tab === 'new-releases' ? 'all-topics' : 'new-releases');\n else\n setViewModel('tab', viewModel.tab === 'curated-topic' ? 'video-list' : 'curated-topic');\n }, 2000);\n }\n\n return () => {\n window.clearInterval(interval);\n };\n }, [ viewModel.on, viewModel.tab ]);\n\n return {\n tab: viewModel.tab,\n isHighlighting: viewModel.on,\n start: () => setViewModel('on', true),\n stop: () => {\n setViewModel({\n on: false,\n tab: initialTab || viewModel.tab\n });\n }\n };\n}\n",":local {\n .curatedTopicTab {\n min-width: 6rem !important;\n }\n \n .tabTransition {\n transition: background-color .5s ease-in-out;\n }\n}","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { EntityType, LocationContext, UserAction } from 'libs/analytics/interfaces';\n\nimport { PillTab, PillTabSelector } from 'libs/shared/components/pill-tab-selector/PillTabSelector';\nimport { Breakpoints, useBreakpoints } from 'libs/shared/hooks/useBreakpoints';\nimport { GridSvg } from 'libs/shared/images/svg/objects/GridSvg';\nimport { RectanglesSvg } from 'libs/shared/images/svg/objects/RectanglesSvg';\nimport { SparkleSvg } from 'libs/shared/images/svg/objects/SparkleSvg';\nimport { WidgetSeriesSvg } from 'libs/shared/images/svg/widgets/WidgetSeriesSvg';\nimport { Classification, Presentation } from 'libs/shared/interfaces';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nimport { useDirectoryTabProductTipSwitcher } from '../../../hooks/useDirectoryTabProductTipSwitcher';\n\nimport styles from './classification-tabs.module.scss';\n\nconst namespace = 'shared.classificationDashboard';\n\nexport type ClassificationTab = 'new-releases' | 'all-topics' | 'curated-topic' | 'curriculum';\n\nfunction getTabs(\n props: ClassificationTabsProps,\n breakpoints: Breakpoints,\n activeTab: ClassificationTab,\n isHighlighting: boolean\n): PillTab[] {\n const showText = breakpoints.lg || breakpoints.xl || breakpoints.xxl || breakpoints.xs;\n\n function getTopicTabClassName(): string {\n let className = isHighlighting ? styles.tabTransition : '';\n\n if (breakpoints.xs)\n return className + ' w-100';\n\n if (showText)\n return className = ` ${styles.curatedTopicTab}`;\n\n return className;\n }\n\n if (TopicsHelper.isTopLevelTopic(props.classification)) {\n return [{\n name: showText ? LanguageService.getPhrase(namespace, 'newReleases') : '',\n appLink: props.appLinks?.classification?.(props.classification),\n active: activeTab === 'new-releases',\n svg: SparkleSvg,\n analyticsData: {\n id: 'new-releases',\n classificationId: props.classification.id,\n classificationName: props.classification.name,\n presentationId: props.presentation.id,\n presentationDescription: props.presentation.description,\n name: LanguageService.getPhrase(namespace, 'newReleases'),\n url: Core.AppLinkHelper.getHref(props.appLinks?.classification?.(props.classification))\n },\n analyticsOptions: {\n actionType: UserAction.Click,\n entity: EntityType.Url,\n location: LocationContext.MagicTabs\n },\n className: `${breakpoints.xs ? 'w-100' : ''} ${isHighlighting ? styles.tabTransition : ''}`\n }, {\n name: showText ? LanguageService.getPhrase(namespace, 'allTopics') : '',\n appLink: props.appLinks?.classificationDirectory?.(props.classification),\n active: activeTab === 'all-topics',\n svg: GridSvg,\n analyticsData: {\n id: 'all-topics',\n classificationId: props.classification.id,\n classificationName: props.classification.name,\n presentationId: props.presentation.id,\n presentationDescription: props.presentation.description,\n name: LanguageService.getPhrase(namespace, 'allTopics'),\n url: Core.AppLinkHelper.getHref(props.appLinks?.classificationDirectory?.(props.classification))\n },\n analyticsOptions: {\n actionType: UserAction.Click,\n entity: EntityType.Url,\n location: LocationContext.MagicTabs\n },\n className: `${breakpoints.xs ? 'w-100' : ''} ${isHighlighting ? styles.tabTransition : ''}`\n }];\n }\n\n return [{\n name: showText ? LanguageService.getPhrase(namespace, 'topic') : '',\n appLink: props.appLinks?.classification?.(props.classification),\n active: activeTab === 'curated-topic',\n svg: RectanglesSvg,\n analyticsData: {\n id: 'curated-topic',\n classificationId: props.classification.id,\n classificationName: props.classification.name,\n presentationId: props.presentation.id,\n presentationDescription: props.presentation.description,\n name: LanguageService.getPhrase(namespace, 'topic'),\n url: Core.AppLinkHelper.getHref(props.appLinks?.classification?.(props.classification))\n },\n analyticsOptions: {\n actionType: UserAction.Click,\n entity: EntityType.Url,\n location: LocationContext.MagicTabs\n },\n className: getTopicTabClassName()\n }, {\n name: showText ? LanguageService.getPhrase(namespace, 'curriculum') : '',\n appLink: props.appLinks?.classificationCurriculum?.(props.classification),\n active: activeTab === 'curriculum',\n svg: WidgetSeriesSvg,\n analyticsData: {\n id: 'curriculum',\n classificationId: props.classification.id,\n classificationName: props.classification.name,\n presentationId: props.presentation.id,\n presentationDescription: props.presentation.description,\n name: LanguageService.getPhrase(namespace, 'curriculum'),\n url: Core.AppLinkHelper.getHref(props.appLinks?.classificationCurriculum?.(props.classification))\n },\n analyticsOptions: {\n actionType: UserAction.Click,\n entity: EntityType.Url,\n location: LocationContext.MagicTabs\n },\n className: `${breakpoints.xs ? 'w-100' : ''} ${isHighlighting ? styles.tabTransition : ''}`\n }];\n}\n\ninterface ClassificationTabsProps {\n classification: Classification;\n presentation: Presentation;\n appLinks: {\n classification: (classification: Classification | null) => Core.AppLink,\n classificationDirectory: (classification: Classification) => Core.AppLink,\n classificationCurriculum: (classification: Classification) => Core.AppLink\n };\n activeTab: ClassificationTab;\n}\n\nexport function ClassificationTabs(props: ClassificationTabsProps): JSX.Element {\n const breakpoints = useBreakpoints();\n const { tab, isHighlighting } = useDirectoryTabProductTipSwitcher(props.activeTab);\n\n return (\n <PillTabSelector\n borderRadius='sm'\n className={breakpoints.xs ? 'w-100' : ''}\n listClassName='d-flex flex-nowrap'\n tabs={getTabs(props, breakpoints, tab, isHighlighting)}\n />\n );\n}\n","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\n\nimport { Breadcrumb, Breadcrumbs } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { useBreakpoints } from 'libs/shared/hooks/useBreakpoints';\nimport { Classification, CuratedDashboard, Presentation, PresentationAudience } from 'libs/shared/interfaces';\nimport { AudienceHelper } from 'libs/shared/utils/audience-helper/AudienceHelper';\nimport { CuratedDashboardHelper } from 'libs/shared/utils/DashboardHelper';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nimport { ClassificationDashboardAudiences } from '../audiences/ClassificationDashboardAudiences';\nimport { ClassificationTab, ClassificationTabs } from '../classification-tabs/ClassificationTabs';\n\nfunction shouldHideAudiences(\n audiences: PresentationAudience[],\n activeAudiences: PresentationAudience[],\n activeTab: ClassificationTab,\n isEmpty: boolean,\n isComingSoon: boolean\n): boolean {\n if (isComingSoon)\n return true;\n\n if (isEmpty && !activeAudiences?.length)\n return true;\n\n if (!AudienceHelper.shouldShowAudiences(audiences))\n return true;\n\n if (activeTab === 'curriculum')\n return true;\n\n return false;\n}\n\ninterface ClassificationDashboardNavProps {\n dashboard: CuratedDashboard;\n classification: Classification;\n presentation: Presentation;\n appLinks: {\n audience: () => Core.AppLink,\n classification: (classification: Classification | null) => Core.AppLink,\n classificationDirectory: (classification: Classification) => Core.AppLink,\n classificationCurriculum: (classification: Classification) => Core.AppLink\n };\n activeTab: ClassificationTab;\n audiences: PresentationAudience[];\n activeAudiences: PresentationAudience[];\n getBreadcrumbs: () => Breadcrumb[];\n\n hasTopicDirectoryDashboard: boolean;\n hasTopicCurriculumDashboard: boolean;\n isComingSoon: boolean;\n isEmpty: boolean;\n isViewingCurrentPresentation: boolean;\n disableAudiences: boolean;\n audienceTooltip: string;\n}\n\nexport function ClassificationDashboardNav(props: ClassificationDashboardNavProps): JSX.Element {\n const breakpoints = useBreakpoints();\n\n const hideAudiences = shouldHideAudiences(\n props.audiences,\n props.activeAudiences,\n props.activeTab,\n props.isEmpty,\n props.isComingSoon\n );\n\n function canShowTabs(): boolean {\n if (!props.classification || !props.dashboard)\n return false;\n\n if (CuratedDashboardHelper.isSystemGeneratedDashboard(props.dashboard.widgets))\n return false;\n\n /**\n * For our top-level topics, we can show the topic tab if the topic has a directory dashboard.\n */\n if (TopicsHelper.isTopLevelTopic(props.classification))\n return props.hasTopicDirectoryDashboard;\n\n /**\n * For our curated topics, we can show the curriculum tab if the topic has one, which it should\n */\n if (props.classification.externalMetadata?.isCurated && props.hasTopicCurriculumDashboard)\n return true;\n\n return false;\n }\n\n function getContainerClass(): string {\n let className = 'd-flex flex-column py-3 mb-3';\n\n if (!props.isComingSoon)\n className += ' border-bottom';\n\n if ((canShowTabs() || hideAudiences) && !breakpoints.xs)\n return className;\n\n return className + ' row-gap-3';\n }\n\n function getTopRowClass(): string {\n if (hideAudiences) {\n if (breakpoints.xs)\n return 'd-flex flex-column justify-content-between row-gap-3';\n\n return 'd-flex align-items-center justify-content-between';\n }\n\n let className = '';\n\n className += 'd-flex align-items-center justify-content-between mb-1';\n\n if (breakpoints.xs)\n className += ' row-gap-3 mb-0';\n\n return className;\n }\n\n function getBottomRowClass(): string {\n let className = 'd-flex align-items-end justify-content-between';\n\n if (breakpoints.xs)\n className += ' row-gap-3 flex-wrap';\n\n return className;\n }\n\n return (\n <div className={getContainerClass()}>\n <div className={getTopRowClass()}>\n <Breadcrumbs breadcrumbs={props.getBreadcrumbs?.()} />\n\n {canShowTabs() && hideAudiences && (\n <ClassificationTabs\n classification={props.classification}\n activeTab={props.activeTab}\n appLinks={props.appLinks}\n presentation={props.presentation}\n />\n )}\n </div>\n\n <div className={getBottomRowClass()}>\n {!hideAudiences && (\n <ClassificationDashboardAudiences\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n appLink={props.appLinks.audience?.()}\n disabled={props.disableAudiences}\n tooltip={props.audienceTooltip}\n disablePersist={!props.isViewingCurrentPresentation}\n />\n )}\n\n {canShowTabs() && !hideAudiences && (\n <ClassificationTabs\n classification={props.classification}\n activeTab={props.activeTab}\n appLinks={props.appLinks}\n presentation={props.presentation}\n />\n )}\n </div>\n </div>\n );\n}\n","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\n\nimport { AnalyticsOptions, HashObject, LocationContext } from 'libs/analytics/interfaces';\n\nimport { ClassificationHeaderDetails } from 'libs/shared/apps/subjects/components/classification-dashboard/classification-header-details/ClassificationHeaderDetails';\nimport { CuratedClassificationEmptyState } from 'libs/shared/apps/subjects/components/classification-dashboard/empty-state/CuratedClassificationEmptyState';\nimport { TableOfContentsContainer } from 'libs/shared/apps/subjects/components/classification-dashboard/table-of-contents/TableOfContents';\nimport { TeacherOnlyEmptyState } from 'libs/shared/apps/subjects/components/classification-dashboard/teacher-only/TeacherOnlyEmptyState';\nimport { useGetTopicsWidgets } from 'libs/shared/apps/subjects/hooks/useGetTopicsWidgets';\nimport { ActionOptions } from 'libs/shared/components/actions/Actions';\nimport { BannerHeader } from 'libs/shared/components/banner-header/BannerHeader';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { DashboardFeedbackData } from 'libs/shared/components/feedback-form/FeedbackForm';\nimport { VideoList } from 'libs/shared/components/video-list/VideoList';\nimport { WidgetHeader } from 'libs/shared/components/widgets/curated-widgets/components/header/WidgetHeader';\nimport { WidgetContainerView } from 'libs/shared/components/widgets/curated-widgets/WidgetContainerView';\nimport { AllClassificationWidgetTemplates } from 'libs/shared/components/widgets/curated-widgets/WidgetProps';\nimport { ClassificationType } from 'libs/shared/enums/ClassificationType';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { LocalPermissionName } from 'libs/shared/enums/PermissionName';\nimport { WidgetTemplate } from 'libs/shared/enums/WidgetTemplate';\nimport { WidgetTypeId } from 'libs/shared/enums/WidgetTypeId';\nimport { useMediaQuery } from 'libs/shared/hooks/UseMediaQuery';\nimport { HasLocalPermissionsFunc, HasPermissionsFunc } from 'libs/shared/hooks/usePermissions';\nimport { useTableOfContentsActiveHeading } from 'libs/shared/hooks/useTableOfContentsActiveHeading';\nimport { useTableOfContentsScroll } from 'libs/shared/hooks/useTableOfContentsScroll';\nimport { CalendarEvent, CalendarEventContentType, Classification, CuratedDashboard, CuratedWidget, CuratedWidgetQueryParams, CurriculumData, DashboardStatus, DashboardTargetType, InteractiveMetadata, Presentation, PresentationAudience } from 'libs/shared/interfaces';\nimport { CommonVideoProps } from 'libs/shared/interfaces/CommonVideoProps';\nimport { CuratedDashboardHelper } from 'libs/shared/utils/DashboardHelper';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nimport { ClassificationComingSoon } from './classification-coming-soon/ClassificationComingSoon';\nimport { ClassificationDashboardNav } from './classification-dashboard-nav/ClassificationDashboardNav';\nimport { ClassificationTab } from './classification-tabs/ClassificationTabs';\n\nconst namespace = 'shared.classificationDashboard';\n\nfunction isHeadingWidget(widget: CuratedWidget) {\n return widget.widgetId === WidgetTypeId.Blurb && widget.templateId === WidgetTemplate.Heading;\n}\n\nfunction isTopicWidget(widget: CuratedWidget) {\n return widget.widgetId === WidgetTypeId.CuratedClassifications || widget.widgetId === WidgetTypeId.Classifications;\n}\n\nexport interface ClassificationDashboardProps {\n dashboard: CuratedDashboard;\n classification: Classification;\n presentation: Presentation;\n hasPermissions: HasPermissionsFunc;\n hasLocalPermissions: HasLocalPermissionsFunc;\n resourceThumbnailFallbackImageUrl: string;\n hasTopicDirectoryDashboard: boolean;\n hasTopicCurriculumDashboard: boolean;\n isTertiaryCustomerWithoutExchange: boolean;\n tab: ClassificationTab;\n specialEvent?: CalendarEvent;\n curriculums: CurriculumData;\n\n audiences: PresentationAudience[];\n activeAudiences?: PresentationAudience[];\n\n getWidgetContentRequest: (\n id: string,\n params: CuratedWidgetQueryParams,\n widgetTemplate: WidgetTemplate\n ) => Flight.Request;\n\n getBannerActions?: () => ActionOptions[];\n getBreadcrumbs?: () => Breadcrumb[];\n onToggleFollow?: (classification: Classification, locationContext: LocationContext) => void;\n canFollowSubjects: boolean;\n onSubmitFeedback?: (feedback: DashboardFeedbackData) => Promise<void>;\n\n appLinks?: AllClassificationWidgetTemplates['appLinks'] & {\n signUp: () => Core.AppLink,\n widgetWizard: () => Core.AppLink,\n previewQuestions: (interactive: InteractiveMetadata) => Core.AppLink,\n classificationCurriculum: (classification: Classification) => Core.AppLink,\n audience: () => Core.AppLink\n };\n\n imageCdnUrl: string;\n emptyImageUrl: string;\n comingSoonImageUrl?: string;\n\n analyticsOptions?: AnalyticsOptions;\n analyticsData?: HashObject;\n\n scrollToWidgetId?: string;\n tableOfContentsId?: string;\n\n // Means the dashboard contains no linked or working filters\n isReadonly?: boolean;\n\n // Means the dashboard is being previewed by ClickView staff either in product or in curator\n isPreviewing?: boolean;\n\n // Means the parent topic for the dashboard has a status of \"Coming Soon\"\n isComingSoon?: boolean;\n\n showFollowButtonSpinner?: boolean;\n \n isViewCurrentPresentation?: boolean;\n\n // By default widgets will always be lazyloaded. We override this behaviour only in extenuating \n // circumstances, such as dynamic rendering for SEO.\n lazyLoad?: boolean;\n\n moviesAndTv?: boolean;\n\n isTeacherOnly?: boolean;\n \n contentType?: CalendarEventContentType;\n\n isBot?: boolean;\n\n settings?: AllClassificationWidgetTemplates['settings'];\n\n commonVideoProps: CommonVideoProps;\n}\n\nClassificationDashboard.defaultProps = {\n appLinks: {}\n};\n\nexport function ClassificationDashboard(props: ClassificationDashboardProps): JSX.Element {\n const { widgets, videoList, videoListWidgetId } = useGetTopicsWidgets(props.dashboard, props.activeAudiences);\n\n const isSmallScreen = useMediaQuery(MediaQueryStrings.LGDown);\n const headingRef = React.useRef<Set<Element>>(new Set());\n\n const initialEmptyWidgets = React.useMemo(() => {\n return widgets.reduce((acc: HashObject<boolean>, widget) => {\n acc[widget.id] = false;\n return acc;\n }, {});\n }, [widgets?.length]);\n\n const [ emptyWidgets, setEmptyWidgets ] = React.useState(initialEmptyWidgets);\n\n const [ controlledId, setControlledId ] = React.useState(props.tableOfContentsId);\n\n const [ tableOfContentActiveId, setTableOfContentActiveId ] = React.useState<string>('');\n\n const headingElements = Array.from(headingRef.current);\n useTableOfContentsScroll(headingElements, controlledId);\n useTableOfContentsActiveHeading({\n setActiveId: setTableOfContentActiveId,\n headingElements,\n controlledId,\n setControlledId\n });\n\n const isHubDashboard = props.classification.type === ClassificationType.Hub;\n\n function shouldShowEmptyState(): boolean {\n if (props.isComingSoon)\n return false;\n\n if (props.isTeacherOnly)\n return false;\n\n if (!props.dashboard)\n return true;\n\n if (props.dashboard.status === DashboardStatus.Archived && !props.isReadonly)\n return true;\n\n if (props.dashboard.status === DashboardStatus.Draft && !props.isPreviewing)\n return true;\n\n if (!widgets?.length)\n return true;\n\n if (videoList && videoList.length)\n return false;\n\n return Object.values(emptyWidgets).every(state => !!state);\n }\n\n function getWidgetContentRequest(id: string, widgetTypeId: WidgetTypeId, template: WidgetTemplate): Flight.Request {\n const params = CuratedDashboardHelper.getWidgetParams(\n widgetTypeId,\n template,\n CuratedDashboardHelper.getDashboardTargetType(props.dashboard),\n props.activeAudiences?.map(a => a.masterId),\n props.curriculums.preferredCurriculum?.id\n );\n\n return props.getWidgetContentRequest(id, params, template);\n }\n\n const showEmptyState = shouldShowEmptyState();\n\n React.useEffect(() => {\n /**\n * When we add the first widget of the dashboard, the showEmptyState is `true`, the WidgetContainer is not going to be rendered to lazyload the `content`\n * so we set the emptyWidget to initial make sure the widget container is rendered to lazyload `widget.content`\n * and let the WidgetContainer to re-set the empty state based on the actual `widget.content` from backend\n */\n if (showEmptyState) {\n setEmptyWidgets(initialEmptyWidgets);\n }\n }, [widgets?.length]);\n\n const onSetIsEmpty = React.useCallback((widgetId: string, isEmpty: boolean) => {\n if (emptyWidgets[widgetId] === isEmpty)\n return;\n\n const newEmptyState = {\n ...emptyWidgets,\n [widgetId]: isEmpty\n };\n\n // The logic beneath this if-block doesn't apply to classification directories. This is because\n // classification directories don't support audience filtering, so widgets should never be empty,\n // meaning headings should never be hidden.\n if (CuratedDashboardHelper.isType(props.dashboard, DashboardTargetType.ClassificationDirectory)) {\n setEmptyWidgets(newEmptyState);\n return;\n }\n\n let index = 0;\n\n /**\n * Every time a widget is identified as empty, we check each heading blurb widget\n * to see if it should be hidden. This will be the case when all widgets beneath a heading\n * (up until the next heading) are empty.\n */\n while (index < widgets.length) {\n const currentWidget = widgets[index];\n\n if (!isHeadingWidget(currentWidget)) {\n index++;\n continue;\n }\n\n let isHeadingEmpty = true;\n let subWidgetIndex = index + 1;\n\n while (isHeadingEmpty && subWidgetIndex < widgets.length) {\n const headingSubWidget = widgets[subWidgetIndex];\n\n if (isHeadingWidget(headingSubWidget))\n break;\n\n if (!newEmptyState[headingSubWidget.id] && !isTopicWidget(headingSubWidget))\n isHeadingEmpty = false;\n\n subWidgetIndex++;\n }\n\n index = subWidgetIndex;\n\n newEmptyState[currentWidget.id] = isHeadingEmpty;\n }\n\n setEmptyWidgets(newEmptyState);\n }, [ emptyWidgets, widgets ]);\n\n function hideWidget(widget: CuratedWidget): boolean {\n return isHeadingWidget(widget) && emptyWidgets[widget.id];\n }\n\n function useLargeDashboardSpacing(): boolean {\n const target = CuratedDashboardHelper.getDashboardTargetType(props.dashboard);\n\n if (props.moviesAndTv || target === DashboardTargetType.ClassificationCurriculum)\n return false;\n\n return true;\n }\n\n function getWidgetHeading(widget: CuratedWidget, index: number): string {\n if (widget.widgetId === WidgetTypeId.ClassificationDashboardExternalMedia) {\n const previousWidget = widgets[index - 1];\n\n if (emptyWidgets[previousWidget.id])\n return widget.name.replace('Other videos', 'Videos');\n\n return widget.name;\n }\n\n return widget.name;\n }\n\n const widgetsInTableOfContents = widgets.filter(w => {\n return !hideWidget(w) && !!w.metadata?.showInTableOfContents;\n });\n\n const isTopicOnlyDashboard = widgets.every(isTopicWidget);\n\n const shouldShowTableOfContents = widgetsInTableOfContents.length >= 2;\n const shouldShowSideTableOfContents = shouldShowTableOfContents && !isSmallScreen && !isHubDashboard;\n\n const shouldShowTopicCounts = (\n props.settings?.hasTopicDirectories &&\n TopicsHelper.isTopLevelTopic(props.classification) &&\n !props.isTertiaryCustomerWithoutExchange\n );\n\n /**\n * We don't put the .topic-dashboard class when we're in a movies and tv classification\n * because we don't want the extra padding between widgets.\n */\n return (\n <div className={`bg-white px-4 ${useLargeDashboardSpacing() ? 'dashboard-spacing-lg' : ''}`}>\n {isHubDashboard && (\n <>\n <h1 className='h2 mb-4'>{props.classification.name}</h1>\n <hr className='mt-2'/>\n </>\n )}\n\n {!isHubDashboard && (\n <BannerHeader\n heading={props.classification.name}\n banner={props.classification.banner}\n imageCdnUrl={props.imageCdnUrl}\n actions={props.getBannerActions?.()}\n actionsDropdownClassName='btn btn-outline-dark'\n specialEvent={props.specialEvent}\n calendarTheme={{\n background: 'bg-light-blue',\n border: 'border-light-blue'\n }}\n showComingSoon={props.isComingSoon}\n detailsComponent={shouldShowTopicCounts ?\n () => <ClassificationHeaderDetails classification={props.classification} /> :\n null\n }\n />\n )}\n\n {!isHubDashboard && (\n <ClassificationDashboardNav\n dashboard={props.dashboard}\n classification={props.classification}\n presentation={props.presentation}\n appLinks={props.appLinks}\n activeTab={props.tab}\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n getBreadcrumbs={props.getBreadcrumbs}\n hasTopicDirectoryDashboard={props.hasTopicDirectoryDashboard}\n hasTopicCurriculumDashboard={props.hasTopicCurriculumDashboard}\n isComingSoon={props.isComingSoon}\n isEmpty={showEmptyState}\n isViewingCurrentPresentation={props.isViewCurrentPresentation}\n disableAudiences={isTopicOnlyDashboard || props.isReadonly}\n audienceTooltip={isTopicOnlyDashboard ? LanguageService.getPhrase(namespace, 'audienceTooltip') : ''}\n />\n )}\n\n {props.isComingSoon && (\n <ClassificationComingSoon\n imageUrl={props.comingSoonImageUrl}\n data={props.classification}\n canFollowSubjects={props.canFollowSubjects}\n showFollowButtonSpinner={props.showFollowButtonSpinner}\n onToggleFollow={() => props.onToggleFollow(props.classification, LocationContext.ClassificationComingSoon)}\n showSignUp={!props.hasLocalPermissions(LocalPermissionName.FollowComingSoonTopics)}\n signUpAppLink={props.appLinks.signUp?.()}\n />\n )}\n\n {!props.isComingSoon && (\n <div className={`${shouldShowSideTableOfContents ? 'row no-wrap' : ''}`}>\n {shouldShowTableOfContents && (\n <TableOfContentsContainer\n widgets={widgetsInTableOfContents}\n title={props.classification.name}\n activeId={tableOfContentActiveId}\n clickable={!props.isReadonly}\n analyticsData={props.analyticsData}\n setControlledId={setControlledId}\n isSmallScreen={isSmallScreen}\n />\n )}\n\n <div className={shouldShowSideTableOfContents ? 'col-9 order-0' : ''}>\n {widgets.map((widget, idx) => {\n if (hideWidget(widget))\n return <React.Fragment key={widget.id}></React.Fragment>;\n\n return (\n <WidgetContainerView\n widgetCollection={DashboardTargetType.Classification}\n headingElementRef={headingRef}\n key={widget.id}\n id={widget.id}\n name={getWidgetHeading(widget, idx)}\n description={widget.description}\n classification={props.classification}\n templateId={widget.templateId}\n widgetTypeId={widget.widgetId}\n audiences={props.audiences}\n getContentRequest={getWidgetContentRequest}\n setIsEmpty={onSetIsEmpty}\n appLinks={props.appLinks}\n presentation={props.presentation}\n analyticsData={props.analyticsData}\n isScrollToTargetWidget={props.scrollToWidgetId === widget.id}\n imageCdnUrl={props.imageCdnUrl}\n onSubmitFeedback={props.onSubmitFeedback}\n metadata={widget.metadata}\n isBot={props.isBot}\n hasTableOfContents={shouldShowSideTableOfContents}\n lazyLoad={props.lazyLoad}\n dashboardTarget={CuratedDashboardHelper.getDashboardTargetType(props.dashboard)}\n widgetIndex={idx}\n hasPermissions={props.hasPermissions}\n hasLocalPermissions={props.hasLocalPermissions}\n isPreviewing={props.isReadonly}\n contentType={props.contentType}\n resourceThumbnailFallbackImageUrl={props.resourceThumbnailFallbackImageUrl}\n onToggleFollowClassification={props.onToggleFollow}\n settings={props.settings}\n isEditing={props.isReadonly}\n isTertiaryCustomerWithoutExchange={props.isTertiaryCustomerWithoutExchange}\n commonVideoProps={props.commonVideoProps}\n curriculums={props.curriculums}\n\n // TODO: Do we actually need this shit if it wasn't even being passed in?\n limitTotalItems={false}\n seeMoreLink={null}\n onClickRemoveItem={null}\n badgeComponent={null}\n />\n );\n })}\n </div>\n\n {!!videoList?.length && (\n <>\n <WidgetHeader name={LanguageService.getPhrase(namespace, 'videos')} />\n <VideoList\n videos={videoList}\n getVideoAppLink={(video, opts) => props.appLinks.videoType(\n video,\n { ...opts, contextId: videoListWidgetId, includeContext: opts.includeContext }\n )}\n hasPermissions={props.hasPermissions}\n presentationAudiences={props.audiences}\n getPreviewQuestionsAppLink={props.appLinks.previewQuestions}\n commonVideoProps={props.commonVideoProps}\n />\n </>\n )}\n </div>\n )}\n\n {showEmptyState && (\n <CuratedClassificationEmptyState\n dashboard={props.dashboard}\n isReadonly={props.isReadonly}\n imageUrl={props.emptyImageUrl}\n addWidgetApplink={props.appLinks.widgetWizard}\n />\n )}\n\n {props.isTeacherOnly && (\n <TeacherOnlyEmptyState\n imageUrl={props.emptyImageUrl}\n ctaAppLink={() => props.appLinks.allTopics(props.classification.presentationId)}\n />\n )}\n </div>\n );\n}\n","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { ErrorCta, ErrorPageError } from 'libs/shared/errors/primitives/ErrorPageError';\n\nimport { Actions } from 'shared/constants/StreamableActions';\nimport { AppChannels } from 'shared/constants/StreamableRadioChannels';\n\nconst namespace = 'subjects.topicNotFoundError';\n\nexport class TopicNotFoundError extends ErrorPageError {\n constructor() {\n super('Topic doesn\\'t exist');\n }\n\n // @ts-ignore\n public get name(): string {\n return 'TopicNotFoundError';\n }\n\n // @ts-ignore\n public get heading(): string {\n return LanguageService.getPhrase(namespace, 'heading');\n }\n\n // @ts-ignore\n public get description(): string {\n return LanguageService.getPhrase(namespace, 'description');\n }\n\n // @ts-ignore\n public get cta(): ErrorCta {\n return {\n text: LanguageService.getPhrase(namespace, 'cta'),\n appLink: {\n application: AppChannels.SUBJECTS,\n action: Actions.Subjects.CLASSIFICATION_ALL\n }\n };\n }\n}\n","import React from 'react';\n\nimport { PartialAudienceFilter } from 'libs/shared/apps/subjects/components/audience-filter/AudienceFilter';\nimport { PartialBannerHeader } from 'libs/shared/components/banner-header/BannerHeader';\nimport { PartialBreadcrumbs } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\n\nexport function PartialClassification(): JSX.Element {\n return (\n <div className='bg-white px-4'>\n <PartialBannerHeader />\n\n <div className='d-flex flex-column row-gap-3 py-3 mb-3 border-bottom'>\n <PartialBreadcrumbs />\n <PartialAudienceFilter />\n </div>\n </div>\n );\n}\n","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { HashObject } from 'libs/common/react/interfaces';\n\nimport { ClassificationDashboardProps } from 'libs/shared/apps/subjects/components/classification-dashboard/ClassificationDashboard';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { Classification } from 'libs/shared/interfaces';\n\nimport { Actions } from 'shared/constants/StreamableActions';\nimport { AppChannels } from 'shared/constants/StreamableRadioChannels';\nimport { StreamableAppLinks } from 'shared/utils/StreamableAppLinks';\n\nconst namespace = 'subjects.classificationView';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport function getClassificationAppLinks(\n classification: Classification,\n params: HashObject\n): ClassificationDashboardProps['appLinks'] {\n return {\n ...StreamableAppLinks,\n classification: c => StreamableAppLinks.classification(c || classification, params),\n classificationDirectory: () => StreamableAppLinks.classificationDirectory(params),\n audience: () => StreamableAppLinks.classification(classification, params),\n\n // TODO: Find a nice way around having to pass these in\n previewQuestions: () => null,\n series: () => null,\n latestReleases: () => null,\n classificationLatestReleases: () => null,\n playlist: () => null,\n signUp: () => null,\n widgetWizard: () => null,\n classificationCurriculum: () => null,\n searchSettings: () => null,\n searchHome: () => null,\n search: () => null,\n editCurriculum: () => null,\n getPreviewQuestionsAppLink: () => null\n };\n}\n\ninterface GetClassificationBreadcrumbsOptions {\n classification: Classification;\n path: Classification[];\n appLinks: ClassificationDashboardProps['appLinks'];\n}\n\nexport function getClassificationBreadcrumbs(\n options: GetClassificationBreadcrumbsOptions\n): Breadcrumb[] {\n const { classification, path, appLinks } = options;\n\n const breadcrumbs: Breadcrumb[] = [{\n name: getPhrase('discover'),\n appLink: {\n application: AppChannels.DASHBOARD,\n action: Actions.Dashboard.HOME\n }\n }, {\n name: getPhrase('exploreAllTopicsHeading'),\n appLink: {\n application: AppChannels.SUBJECTS,\n action: Actions.Subjects.CLASSIFICATION_ALL\n }\n }];\n\n path.forEach(item => {\n breadcrumbs.push({\n name: item.name,\n appLink: appLinks.classification(item),\n active: item.name === classification.name\n });\n });\n\n return breadcrumbs;\n}\n","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\nimport { ObjectHelper } from 'libs/common/react/utils/ObjectHelper';\n\nimport { ClassificationDashboard } from 'libs/shared/apps/subjects/components/classification-dashboard/ClassificationDashboard';\nimport { PreviewBanner } from 'libs/shared/apps/subjects/components/preview-banner/PreviewBanner';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { VideoActionsContext } from 'libs/shared/context/VideoActionsContext';\nimport { PresentationType } from 'libs/shared/enums/PresentationType';\nimport { AudienceRequests } from 'libs/shared/flight-requests/AudienceRequests';\nimport { ClassificationRequests } from 'libs/shared/flight-requests/ClassificationRequests';\nimport { ConfigRequests } from 'libs/shared/flight-requests/ConfigRequests';\nimport { DashboardRequests } from 'libs/shared/flight-requests/DashboardRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { useHandleObjectError } from 'libs/shared/hooks/UseHandleObjectError';\nimport { useSetPageMetadata } from 'libs/shared/hooks/useSetPageMetadata';\nimport { AudienceFilterParams, CalendarEventContentType, Classification, Config, CurrentUser, DashboardTargetType, Presentation, PresentationAudience } from 'libs/shared/interfaces';\nimport { AudienceHelper } from 'libs/shared/utils/audience-helper/AudienceHelper';\nimport { PageMetadataHelper } from 'libs/shared/utils/PageMetadataHelper';\n\nimport { ImageUrls } from 'shared/constants/ImageUrls';\nimport { StreamableConstants } from 'shared/constants/StreamableConstants';\nimport { PresentationRequests } from 'shared/flight-requests/PresentationRequests';\nimport { useCommonVideoProps } from 'shared/hooks/useCommonVideoProps';\nimport { useFetchDashboard } from 'shared/hooks/useFetchDashboard';\nimport { useStreamableVideoActions } from 'shared/hooks/useStreamableVideoActions';\nimport { SeoHelper } from 'shared/utils/StreamableSeoHelper';\n\nimport { TopicNotFoundError } from 'apps/subjects/errors/TopicNotFoundError';\nimport { useCurriculums } from 'apps/videos/hooks/useCurriculums';\n\nimport { PartialClassification } from './partial-loading/PartialClassification';\nimport { getClassificationAppLinks, getClassificationBreadcrumbs } from './StreamableClassificationViewUtils';\n\nconst namespace = 'subjects.classificationView';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport interface StreamableClassificationViewQueryParams extends AudienceFilterParams {\n dashboardId?: string;\n tocId?: string;\n}\n\nexport function sanitizeStreamableClassificationParams(\n queryParams: StreamableClassificationViewQueryParams\n): StreamableClassificationViewQueryParams {\n if (!queryParams)\n return {};\n\n return ObjectHelper.pick(queryParams, [ 'a', 'dashboardId', 'tocId' ]);\n}\n\ninterface StreamableClassificationViewProps {\n id: string;\n queryParams: StreamableClassificationViewQueryParams;\n}\n\nexport function StreamableClassificationView(props: StreamableClassificationViewProps): JSX.Element {\n const getVideoActions = useStreamableVideoActions('video-list');\n\n const { commonVideoProps } = useCommonVideoProps();\n\n const config = Flight.useBasicFetch<Config>(ConfigRequests.config());\n const currentUser = Flight.useBasicFetch<CurrentUser>(UserRequests.currentUser());\n const curriculumData = useCurriculums();\n\n const presentation = Flight.useBasicFetch<Presentation>(\n PresentationRequests.streamablePresentation()\n );\n\n const classification = Flight.useBasicFetch<Classification>(\n ClassificationRequests.classification(props.id, currentUser.data?.id)\n );\n\n const { dashboard, isPreviewing } = useFetchDashboard({\n targetType: DashboardTargetType.Classification,\n dashboardId: props.queryParams?.dashboardId,\n classificationId: props.id\n });\n\n const appLinks = getClassificationAppLinks(classification.data, props.queryParams);\n\n useSetPageMetadata(PageMetadataHelper.getClassificationMetadata({\n content: { classification: classification.data },\n phraseContext: {\n phraseHandler: getPhrase,\n titlePhrase: 'pageTitle',\n descriptionPhrase: 'pageDescription'\n },\n canonicalLink: SeoHelper.getCanonicalLink({\n customAppLink: appLinks.classification(classification.data)\n }),\n allowIndexing: true,\n product: StreamableConstants.PRODUCT_NAME\n }));\n\n useHandleObjectError(classification, {\n notFound: TopicNotFoundError\n });\n\n const audiences = Flight.useBasicFetch<PresentationAudience[]>(presentation.data &&\n AudienceRequests.presentationAudiences(PresentationType.StreamableLearning, presentation.data.id));\n\n const path = Flight.useBasicFetch<Classification[]>(\n ClassificationRequests.path(props.id, PresentationType.StreamableLearning)\n );\n\n /**\n * We use the current active audiences to re-fetch content for that specific audience set.\n */\n const activeAudiences = React.useMemo(\n () => AudienceHelper.getActiveAudiencesFromParams(audiences.data, props.queryParams),\n [ audiences.data, props.queryParams ]\n );\n const activeAudienceIds = activeAudiences?.map(a => a.masterId) ?? [];\n\n /**\n * Additional topics data to be mixed in with lower-level component analytics collection\n */\n const analyticsData = {\n presentationId: presentation.data?.id,\n presentationName: presentation.data?.name,\n currentClassificationId: classification.data?.id,\n currentClassificationName: classification.data?.name,\n followingCurrentClassification: !!classification.data?.followers?.data?.length,\n activeAudienceNames: activeAudiences?.length ? activeAudiences.map(a => a.name) : null,\n activeAudienceIds: activeAudienceIds.length ? activeAudienceIds : null\n };\n\n function getBreadcrumbs(): () => Breadcrumb[] {\n return () => getClassificationBreadcrumbs({\n appLinks: appLinks,\n classification: classification.data,\n path: path.data\n });\n }\n\n const dataLoaded = !!config.data\n && dashboard.hasCompleted\n && !!classification.data\n && !!presentation.data\n && !!path.data\n && !!audiences.data;\n\n if (!dataLoaded)\n return <PartialClassification />;\n\n return (\n <VideoActionsContext.Provider value={{ getVideoActions }}>\n <div className='position-relative'>\n {!!(isPreviewing && dashboard.data) && <PreviewBanner status={dashboard.data.status} type='topic' />}\n <ClassificationDashboard\n dashboard={dashboard.data}\n classification={classification.data}\n getWidgetContentRequest={DashboardRequests.dashboardWidgetContent}\n getBreadcrumbs={getBreadcrumbs()}\n hasPermissions={() => false}\n hasLocalPermissions={() => false}\n presentation={presentation.data}\n getBannerActions={() => []}\n audiences={audiences.data}\n activeAudiences={activeAudiences}\n analyticsData={analyticsData}\n imageCdnUrl={config.data.imageCdnUrl}\n resourceThumbnailFallbackImageUrl={ImageUrls.Fallbacks.RESOURCE_THUMBNAIL}\n emptyImageUrl={ImageUrls.EmptyStates.Topics.TOPIC}\n appLinks={appLinks}\n isPreviewing={isPreviewing}\n isViewCurrentPresentation\n canFollowSubjects={false}\n tableOfContentsId={props.queryParams.tocId}\n lazyLoad={!SeoHelper.isBot()}\n isTeacherOnly={false}\n contentType={CalendarEventContentType.Livestream}\n hasTopicDirectoryDashboard={false}\n hasTopicCurriculumDashboard={false}\n isTertiaryCustomerWithoutExchange={false}\n tab='curated-topic'\n curriculums={curriculumData}\n // just... one... more.. prop....\n commonVideoProps={commonVideoProps}\n />\n </div>\n </VideoActionsContext.Provider>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{v as e}from"./Dp9qJj1C.chunk.js";import{t}from"./ImQRQGZr.chunk.js";import{C as n,T as r,dt as i,l as a,lt as o,m as s,n as c,ut as l}from"./Dun43GrB.chunk.js";import{t as u}from"./B-OL6Vs7.chunk.js";import{l as d}from"./BQ5XMoHG.chunk.js";import{t as f}from"./DeldjYRc.chunk.js";import{E as p,R as m,z as h}from"./app-
|
|
2
|
-
//# sourceMappingURL=
|
|
1
|
+
import{v as e}from"./Dp9qJj1C.chunk.js";import{t}from"./ImQRQGZr.chunk.js";import{C as n,T as r,dt as i,l as a,lt as o,m as s,n as c,ut as l}from"./Dun43GrB.chunk.js";import{t as u}from"./B-OL6Vs7.chunk.js";import{l as d}from"./BQ5XMoHG.chunk.js";import{t as f}from"./DeldjYRc.chunk.js";import{E as p,R as m,z as h}from"./app-gjHxcZG3.js";import{t as g}from"./Ct5auYPr2.chunk.js";import{n as _}from"./gbgcwRX-.chunk.js";import{t as v}from"./Cr3Blj6H2.chunk.js";import{t as y}from"./BfT-O7-i2.chunk.js";l();var b=p(),x=o(),S=`shared.videoGuidanceClassroomGuidePopup`,C=350;function w(e){function n(t){return e.curriculums.updateCurriculum(t,{shouldLog:!0,video:e.video,locationContext:s.CurriculumGuidancePopup})}return(0,x.jsx)(h,{closePopup:e.onClickClose,showLoadingSpinner:e.isLoading,title:t.getPhrase(S,`curriculumLinks`),size:`lg`,children:!e.isLoading&&(0,x.jsxs)(x.Fragment,{children:[(0,x.jsxs)(b.Scrollbars,{autoHeightMax:C,autoHeightMin:C,autoHeight:!0,className:`pb-3`,renderThumbVertical:({style:e,...t})=>(0,x.jsx)(`div`,{...t,style:{...e,borderRadius:`inherit`,backgroundColor:`rgba(0, 0, 0, 0.2)`,zIndex:5},className:`thumb-vertical`}),children:[(0,x.jsx)(y,{availableCurriculums:e.curriculums.availableCurriculums,onChangeCurriculum:n,selectedCurriculum:e.curriculums.preferredCurriculum}),(0,x.jsx)(`div`,{className:`pb-3`,children:(0,x.jsx)(_,{curriculumLinks:e.curriculums.curriculumLinks,onChangeCurriculum:n,hasCompleted:e.curriculums.hasCompleted,mappedCurriculums:e.curriculums.mappedCurriculums,isFetching:e.curriculums.isFetching,getCodeAppLink:e.getCodeAppLink,locationContext:s.CurriculumGuidancePopup})})]}),(0,x.jsxs)(m,{children:[(0,x.jsx)(m.Cancel,{onClick:e.onClickClose,text:t.getPhrase(S,`close`)}),(0,x.jsx)(m.Submit,{text:t.getPhrase(S,`viewVideo`),variant:`dark`,onClick:e.onClickViewVideo})]})]})})}function T(t){let o=d(g.video(t.id)),l=v(t.id);function p(){c.logUserAction({id:o.data.id,name:o.data.name},{entity:a.Video,location:s.CurriculumGuidancePopup,actionType:n.Click,descriptor:r.Close}),t.closePopup()}function m(){c.logUserAction({id:o.data.id,name:o.data.name},{entity:a.Video,location:s.CurriculumGuidancePopup,actionType:n.Click,descriptor:r.ViewVideo}),e.trigger({application:u.VIDEOS,action:f.Videos.PLAY_VIDEO,args:[o.data.id,i.slugify(o.data.name)]}),t.closePopup()}return(0,x.jsx)(w,{isLoading:!o.hasCompleted,video:o.data,curriculums:l,onClickClose:p,onClickViewVideo:m,closePopup:t.closePopup})}export{T as VideoGuidanceClassroomGuideView};
|
|
2
|
+
//# sourceMappingURL=D6IzS-bj2.chunk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"
|
|
1
|
+
{"version":3,"file":"D6IzS-bj2.chunk.js","names":[],"sources":["../../../../libs/shared/src/components/video-guidance/classroom-guide/popup/VideoGuidanceClassroomGuidePopup.tsx","../../src/apps/videos/views/video-guidance-classroom-guide/VideoGuidanceClassroomGuideView.tsx"],"sourcesContent":["import React from 'react';\nimport { Scrollbars } from 'react-custom-scrollbars-2';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { LocationContext } from 'libs/analytics/interfaces';\n\nimport { CurriculumDropdown } from 'libs/shared/components/curriculum-links/CurriculumDropdown';\nimport { CurriculumLinks } from 'libs/shared/components/curriculum-links/CurriculumLinks';\nimport { Popup } from 'libs/shared/components/popup/Popup';\nimport { PopupButtons } from 'libs/shared/components/popup/PopupButtons';\nimport { Clip, CurriculumData, PopupViewProps, Video } from 'libs/shared/interfaces';\n\nconst namespace = 'shared.videoGuidanceClassroomGuidePopup';\n\nconst MIN_MAX_HEIGHT = 350;\n\ninterface VideoGuidanceClassroomGuidePopupProps extends PopupViewProps {\n isLoading: boolean;\n video: Video | Clip;\n onClickClose: () => void;\n onClickViewVideo: () => void;\n curriculums: CurriculumData;\n getCodeAppLink?: (query: string, isCode: boolean) => Core.AppLink;\n}\n\nexport function VideoGuidanceClassroomGuidePopup(props: VideoGuidanceClassroomGuidePopupProps): JSX.Element {\n function onChangeCurriculum(curriculumId: string): Promise<void> {\n return props.curriculums.updateCurriculum(curriculumId, {\n shouldLog: true,\n video: props.video,\n locationContext: LocationContext.CurriculumGuidancePopup\n });\n }\n\n return (\n <Popup\n closePopup={props.onClickClose}\n showLoadingSpinner={props.isLoading}\n title={LanguageService.getPhrase(namespace, 'curriculumLinks')}\n size='lg'\n >\n {!props.isLoading && (\n <>\n <Scrollbars\n autoHeightMax={MIN_MAX_HEIGHT}\n autoHeightMin={MIN_MAX_HEIGHT}\n autoHeight\n className='pb-3'\n // move vertical scrollbar to the top\n renderThumbVertical={({ style, ...props }) => <div {...props} style={{ ...style, borderRadius: 'inherit', backgroundColor: 'rgba(0, 0, 0, 0.2)', zIndex: 5 }} className='thumb-vertical'/>}\n >\n <CurriculumDropdown\n availableCurriculums={props.curriculums.availableCurriculums}\n onChangeCurriculum={onChangeCurriculum}\n selectedCurriculum={props.curriculums.preferredCurriculum}\n />\n\n <div className='pb-3'>\n <CurriculumLinks\n curriculumLinks={props.curriculums.curriculumLinks}\n onChangeCurriculum={onChangeCurriculum}\n hasCompleted={props.curriculums.hasCompleted}\n mappedCurriculums={props.curriculums.mappedCurriculums}\n isFetching={props.curriculums.isFetching}\n getCodeAppLink={props.getCodeAppLink}\n locationContext={LocationContext.CurriculumGuidancePopup}\n />\n </div>\n </Scrollbars>\n\n <PopupButtons>\n <PopupButtons.Cancel\n onClick={props.onClickClose}\n text={LanguageService.getPhrase(namespace, 'close')}\n />\n <PopupButtons.Submit\n text={LanguageService.getPhrase(namespace, 'viewVideo')}\n variant='dark'\n onClick={props.onClickViewVideo}\n />\n </PopupButtons>\n </>\n )}\n </Popup>\n );\n}\n","import React from 'react';\n\nimport { Core } from 'libs/common/backbone/index';\nimport { Flight } from 'libs/common/react/index';\nimport { TextHelper } from 'libs/common/react/utils/TextHelper';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { EntityType, LocationContext, UserAction, VideoGuidanceDescriptor } from 'libs/analytics/interfaces';\n\nimport { VideoGuidanceClassroomGuidePopup } from 'libs/shared/components/video-guidance/classroom-guide/popup/VideoGuidanceClassroomGuidePopup';\nimport { VideoRequests } from 'libs/shared/flight-requests/VideoRequests';\nimport { Clip, PopupViewProps, Video } from 'libs/shared/interfaces';\n\nimport { Actions } from 'shared/constants/StreamableActions';\nimport { AppChannels } from 'shared/constants/StreamableRadioChannels';\n\nimport { useCurriculums } from 'apps/videos/hooks/useCurriculums';\n\ninterface VideoGuidanceClassroomGuideViewProps extends PopupViewProps {\n id: string;\n}\n\n// eslint-disable-next-line rulesdir/require-view-title\nexport function VideoGuidanceClassroomGuideView(props: VideoGuidanceClassroomGuideViewProps): JSX.Element {\n const video = Flight.useBasicFetch<Clip | Video>(VideoRequests.video(props.id));\n const curriculums = useCurriculums(props.id);\n\n function onClickClose(): void {\n AnalyticsHelper.logUserAction({\n id: video.data.id,\n name: video.data.name\n }, {\n entity: EntityType.Video,\n location: LocationContext.CurriculumGuidancePopup,\n actionType: UserAction.Click,\n descriptor: VideoGuidanceDescriptor.Close\n });\n\n props.closePopup();\n }\n\n function onClickViewVideo(): void {\n AnalyticsHelper.logUserAction({\n id: video.data.id,\n name: video.data.name\n }, {\n entity: EntityType.Video,\n location: LocationContext.CurriculumGuidancePopup,\n actionType: UserAction.Click,\n descriptor: VideoGuidanceDescriptor.ViewVideo\n });\n\n Core.AppLinkHelper.trigger({\n application: AppChannels.VIDEOS,\n action: Actions.Videos.PLAY_VIDEO,\n args: [ video.data.id, TextHelper.slugify(video.data.name) ]\n });\n\n props.closePopup();\n }\n\n return (\n <VideoGuidanceClassroomGuidePopup\n isLoading={!video.hasCompleted}\n video={video.data}\n curriculums={curriculums}\n onClickClose={onClickClose}\n onClickViewVideo={onClickViewVideo}\n closePopup={props.closePopup}\n />\n );\n}\n"],"mappings":"0gBAcM,EAAY,0CAEZ,EAAiB,IAWvB,SAAgB,EAAiC,EAA2D,CAC1G,SAAS,EAAmB,EAAqC,CAC/D,OAAO,EAAM,YAAY,iBAAiB,EAAc,CACtD,UAAW,GACX,MAAO,EAAM,MACb,gBAAiB,EAAgB,wBAClC,CAAC,CAGJ,OACE,EAAA,EAAA,KAAC,EAAD,CACE,WAAY,EAAM,aAClB,mBAAoB,EAAM,UAC1B,MAAO,EAAgB,UAAU,EAAW,kBAAkB,CAC9D,KAAK,cAEJ,CAAC,EAAM,YACN,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,MAAC,EAAA,WAAD,CACE,cAAe,EACf,cAAe,EACf,WAAA,GACA,UAAU,OAEV,qBAAsB,CAAE,QAAO,GAAG,MAAY,EAAA,EAAA,KAAC,MAAD,CAAK,GAAI,EAAO,MAAO,CAAE,GAAG,EAAO,aAAc,UAAW,gBAAiB,qBAAsB,OAAQ,EAAG,CAAE,UAAU,iBAAkB,CAAA,UAN5L,EAQE,EAAA,EAAA,KAAC,EAAD,CACE,qBAAsB,EAAM,YAAY,qBACpB,qBACpB,mBAAoB,EAAM,YAAY,oBACtC,CAAA,EAEF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iBACb,EAAA,EAAA,KAAC,EAAD,CACE,gBAAiB,EAAM,YAAY,gBACf,qBACpB,aAAc,EAAM,YAAY,aAChC,kBAAmB,EAAM,YAAY,kBACrC,WAAY,EAAM,YAAY,WAC9B,eAAgB,EAAM,eACtB,gBAAiB,EAAgB,wBACjC,CAAA,CACE,CAAA,CACK,IAEb,EAAA,EAAA,MAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAa,OAAd,CACE,QAAS,EAAM,aACf,KAAM,EAAgB,UAAU,EAAW,QAAQ,CACnD,CAAA,EACF,EAAA,EAAA,KAAC,EAAa,OAAd,CACE,KAAM,EAAgB,UAAU,EAAW,YAAY,CACvD,QAAQ,OACR,QAAS,EAAM,iBACf,CAAA,CACW,CAAA,CAAA,CACd,CAAA,CAAA,CAEC,CAAA,CC9DZ,SAAgB,EAAgC,EAA0D,CACxG,IAAM,EAAQ,EAAmC,EAAc,MAAM,EAAM,GAAG,CAAC,CACzE,EAAc,EAAe,EAAM,GAAG,CAE5C,SAAS,GAAqB,CAC5B,EAAgB,cAAc,CAC5B,GAAI,EAAM,KAAK,GACf,KAAM,EAAM,KAAK,KAClB,CAAE,CACD,OAAQ,EAAW,MACnB,SAAU,EAAgB,wBAC1B,WAAY,EAAW,MACvB,WAAY,EAAwB,MACrC,CAAC,CAEF,EAAM,YAAY,CAGpB,SAAS,GAAyB,CAChC,EAAgB,cAAc,CAC5B,GAAI,EAAM,KAAK,GACf,KAAM,EAAM,KAAK,KAClB,CAAE,CACD,OAAQ,EAAW,MACnB,SAAU,EAAgB,wBAC1B,WAAY,EAAW,MACvB,WAAY,EAAwB,UACrC,CAAC,CAEF,EAAmB,QAAQ,CACzB,YAAa,EAAY,OACzB,OAAQ,EAAQ,OAAO,WACvB,KAAM,CAAE,EAAM,KAAK,GAAI,EAAW,QAAQ,EAAM,KAAK,KAAK,CAAE,CAC7D,CAAC,CAEF,EAAM,YAAY,CAGpB,OACE,EAAA,EAAA,KAAC,EAAD,CACE,UAAW,CAAC,EAAM,aAClB,MAAO,EAAM,KACA,cACC,eACI,mBAClB,WAAY,EAAM,WAClB,CAAA"}
|