@clickview/lite 0.48.0-rc.7 → 0.48.1
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/bundles.json +1 -1
- package/dist/scripts/{1285-c322e093f9-lite.chunk.js → 1285-c3795fed18-lite.chunk.js} +2 -2
- package/dist/scripts/1285-c3795fed18-lite.chunk.js.map +1 -0
- package/dist/scripts/{170-1f815b85a1-lite.chunk.js → 170-2d124965b7-lite.chunk.js} +2 -2
- package/dist/scripts/{170-1f815b85a1-lite.chunk.js.map → 170-2d124965b7-lite.chunk.js.map} +1 -1
- package/dist/scripts/{1818-b9f9297d6d-lite.chunk.js → 1818-72409e60a9-lite.chunk.js} +1 -1
- package/dist/scripts/{1818-b9f9297d6d-lite.chunk.js.map → 1818-72409e60a9-lite.chunk.js.map} +1 -1
- package/dist/scripts/{1863-cf9df40052-lite.chunk.js → 1863-e7c4a6f342-lite.chunk.js} +1 -1
- package/dist/scripts/{1863-cf9df40052-lite.chunk.js.map → 1863-e7c4a6f342-lite.chunk.js.map} +1 -1
- package/dist/scripts/{1958-9889c1ad24-lite.chunk.js → 1958-5336189397-lite.chunk.js} +1 -1
- package/dist/scripts/{1958-9889c1ad24-lite.chunk.js.map → 1958-5336189397-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2086-a247f6e201-lite.chunk.js → 2086-f7082703d0-lite.chunk.js} +1 -1
- package/dist/scripts/{2086-a247f6e201-lite.chunk.js.map → 2086-f7082703d0-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2118-462a279c5a-lite.chunk.js → 2118-ec2a5f1e9b-lite.chunk.js} +2 -2
- package/dist/scripts/{2118-462a279c5a-lite.chunk.js.map → 2118-ec2a5f1e9b-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2182-5c9db07f5b-lite.chunk.js → 2182-8e4d603a1b-lite.chunk.js} +1 -1
- package/dist/scripts/{2182-5c9db07f5b-lite.chunk.js.map → 2182-8e4d603a1b-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2279-5e92c84310-lite.chunk.js → 2279-252e92e1d8-lite.chunk.js} +1 -1
- package/dist/scripts/{2279-5e92c84310-lite.chunk.js.map → 2279-252e92e1d8-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2355-6cd89fa80d-lite.chunk.js → 2355-c588dc3ce2-lite.chunk.js} +1 -1
- package/dist/scripts/{2355-6cd89fa80d-lite.chunk.js.map → 2355-c588dc3ce2-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2469-aa5bbbb17f-lite.chunk.js → 2469-46411b862e-lite.chunk.js} +1 -1
- package/dist/scripts/{2469-aa5bbbb17f-lite.chunk.js.map → 2469-46411b862e-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2672-0fc559f1d1-lite.chunk.js → 2672-b01985cee8-lite.chunk.js} +1 -1
- package/dist/scripts/{2672-0fc559f1d1-lite.chunk.js.map → 2672-b01985cee8-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2734-6c6d57d0f3-lite.chunk.js → 2734-6a7beb2ce2-lite.chunk.js} +1 -1
- package/dist/scripts/{2734-6c6d57d0f3-lite.chunk.js.map → 2734-6a7beb2ce2-lite.chunk.js.map} +1 -1
- package/dist/scripts/{287-ba98be7f21-lite.chunk.js → 287-3cbed16363-lite.chunk.js} +1 -1
- package/dist/scripts/{287-ba98be7f21-lite.chunk.js.map → 287-3cbed16363-lite.chunk.js.map} +1 -1
- package/dist/scripts/{2875-0e5f209e47-lite.chunk.js → 2875-aefd69a61f-lite.chunk.js} +1 -1
- package/dist/scripts/{2875-0e5f209e47-lite.chunk.js.map → 2875-aefd69a61f-lite.chunk.js.map} +1 -1
- package/dist/scripts/{3012-b5208d6981-lite.chunk.js → 3012-fd3eb34a14-lite.chunk.js} +2 -2
- package/dist/scripts/3012-fd3eb34a14-lite.chunk.js.map +1 -0
- package/dist/scripts/{3042-6650521d8b-lite.chunk.js → 3042-7c1b5e4ff7-lite.chunk.js} +1 -1
- package/dist/scripts/{3042-6650521d8b-lite.chunk.js.map → 3042-7c1b5e4ff7-lite.chunk.js.map} +1 -1
- package/dist/scripts/{3158-31baada6cc-lite.chunk.js → 3158-2147de456d-lite.chunk.js} +1 -1
- package/dist/scripts/{3158-31baada6cc-lite.chunk.js.map → 3158-2147de456d-lite.chunk.js.map} +1 -1
- package/dist/scripts/{3296-6d80e4dd56-lite.chunk.js → 3296-f3732c93d9-lite.chunk.js} +1 -1
- package/dist/scripts/{3296-6d80e4dd56-lite.chunk.js.map → 3296-f3732c93d9-lite.chunk.js.map} +1 -1
- package/dist/scripts/{3541-7ebd9db295-lite.chunk.js → 3541-15581012d3-lite.chunk.js} +1 -1
- package/dist/scripts/{3541-7ebd9db295-lite.chunk.js.map → 3541-15581012d3-lite.chunk.js.map} +1 -1
- package/dist/scripts/{3841-95df66e647-lite.chunk.js → 3841-bfae79638b-lite.chunk.js} +2 -2
- package/dist/scripts/{3841-95df66e647-lite.chunk.js.map → 3841-bfae79638b-lite.chunk.js.map} +1 -1
- package/dist/scripts/{3888-0bee9a9309-lite.chunk.js → 3888-87c1075a1b-lite.chunk.js} +1 -1
- package/dist/scripts/{3888-0bee9a9309-lite.chunk.js.map → 3888-87c1075a1b-lite.chunk.js.map} +1 -1
- package/dist/scripts/{4138-75a2bb69ab-lite.chunk.js → 4138-b9b03c9900-lite.chunk.js} +1 -1
- package/dist/scripts/{4138-75a2bb69ab-lite.chunk.js.map → 4138-b9b03c9900-lite.chunk.js.map} +1 -1
- package/dist/scripts/{4778-ebe369973c-lite.chunk.js → 4778-3c9f2b7f76-lite.chunk.js} +2 -2
- package/dist/scripts/{4778-ebe369973c-lite.chunk.js.map → 4778-3c9f2b7f76-lite.chunk.js.map} +1 -1
- package/dist/scripts/{4942-a27a31e79e-lite.chunk.js → 4942-acce40b333-lite.chunk.js} +2 -2
- package/dist/scripts/{4942-a27a31e79e-lite.chunk.js.map → 4942-acce40b333-lite.chunk.js.map} +1 -1
- package/dist/scripts/{5075-f8719465be-lite.chunk.js → 5075-53172298fe-lite.chunk.js} +1 -1
- package/dist/scripts/{5075-f8719465be-lite.chunk.js.map → 5075-53172298fe-lite.chunk.js.map} +1 -1
- package/dist/scripts/{5157-cd12e2e443-lite.chunk.js → 5157-47a0f5c088-lite.chunk.js} +1 -1
- package/dist/scripts/{5157-cd12e2e443-lite.chunk.js.map → 5157-47a0f5c088-lite.chunk.js.map} +1 -1
- package/dist/scripts/{5268-f4db3933ff-lite.chunk.js → 5268-9b7560f3b1-lite.chunk.js} +2 -2
- package/dist/scripts/{5268-f4db3933ff-lite.chunk.js.map → 5268-9b7560f3b1-lite.chunk.js.map} +1 -1
- package/dist/scripts/{5442-01ffd95162-lite.chunk.js → 5442-5ddfa2d951-lite.chunk.js} +1 -1
- package/dist/scripts/{5442-01ffd95162-lite.chunk.js.map → 5442-5ddfa2d951-lite.chunk.js.map} +1 -1
- package/dist/scripts/{5591-98cfe6c6e5-lite.chunk.js → 5591-119d72ede5-lite.chunk.js} +1 -1
- package/dist/scripts/{5591-98cfe6c6e5-lite.chunk.js.map → 5591-119d72ede5-lite.chunk.js.map} +1 -1
- package/dist/scripts/{5595-3763b14d77-lite.chunk.js → 5595-628d4f252c-lite.chunk.js} +2 -2
- package/dist/scripts/5595-628d4f252c-lite.chunk.js.map +1 -0
- package/dist/scripts/{6102-4d948a5e48-lite.chunk.js → 6102-6e5494bf09-lite.chunk.js} +3 -3
- package/dist/scripts/{6102-4d948a5e48-lite.chunk.js.map → 6102-6e5494bf09-lite.chunk.js.map} +1 -1
- package/dist/scripts/{6158-0c5e44f800-lite.chunk.js → 6158-d123add596-lite.chunk.js} +1 -1
- package/dist/scripts/{6158-0c5e44f800-lite.chunk.js.map → 6158-d123add596-lite.chunk.js.map} +1 -1
- package/dist/scripts/{6263-8957d50afe-lite.chunk.js → 6263-24e67b7df2-lite.chunk.js} +1 -1
- package/dist/scripts/{6263-8957d50afe-lite.chunk.js.map → 6263-24e67b7df2-lite.chunk.js.map} +1 -1
- package/dist/scripts/{6330-c66465bd6d-lite.chunk.js → 6330-9a2a5fc07e-lite.chunk.js} +1 -1
- package/dist/scripts/{6330-c66465bd6d-lite.chunk.js.map → 6330-9a2a5fc07e-lite.chunk.js.map} +1 -1
- package/dist/scripts/{671-003843ca84-lite.chunk.js → 671-5571f33165-lite.chunk.js} +1 -1
- package/dist/scripts/{671-003843ca84-lite.chunk.js.map → 671-5571f33165-lite.chunk.js.map} +1 -1
- package/dist/scripts/{7167-efe85af16e-lite.chunk.js → 7167-dc4c954c2b-lite.chunk.js} +1 -1
- package/dist/scripts/{7167-efe85af16e-lite.chunk.js.map → 7167-dc4c954c2b-lite.chunk.js.map} +1 -1
- package/dist/scripts/7293-58f4a7cf47-lite.chunk.js +2 -0
- package/dist/scripts/{7293-afd3349468-lite.chunk.js.map → 7293-58f4a7cf47-lite.chunk.js.map} +1 -1
- package/dist/scripts/{7301-f20e4bdb8f-lite.chunk.js → 7301-7c9342ef0c-lite.chunk.js} +1 -1
- package/dist/scripts/{7301-f20e4bdb8f-lite.chunk.js.map → 7301-7c9342ef0c-lite.chunk.js.map} +1 -1
- package/dist/scripts/{7708-ece31b78a9-lite.chunk.js → 7708-e91903481a-lite.chunk.js} +1 -1
- package/dist/scripts/{7708-ece31b78a9-lite.chunk.js.map → 7708-e91903481a-lite.chunk.js.map} +1 -1
- package/dist/scripts/{771-eb60e33941-lite.chunk.js → 771-5612b4ffc2-lite.chunk.js} +2 -2
- package/dist/scripts/{771-eb60e33941-lite.chunk.js.map → 771-5612b4ffc2-lite.chunk.js.map} +1 -1
- package/dist/scripts/{7855-37bcdd134e-lite.chunk.js → 7855-4b69540a71-lite.chunk.js} +1 -1
- package/dist/scripts/{7855-37bcdd134e-lite.chunk.js.map → 7855-4b69540a71-lite.chunk.js.map} +1 -1
- package/dist/scripts/{8024-66413cc05b-lite.chunk.js → 8024-765a4170c7-lite.chunk.js} +2 -2
- package/dist/scripts/{8024-66413cc05b-lite.chunk.js.map → 8024-765a4170c7-lite.chunk.js.map} +1 -1
- package/dist/scripts/{823-58d27c255b-lite.chunk.js → 823-33c5207c68-lite.chunk.js} +1 -1
- package/dist/scripts/{823-58d27c255b-lite.chunk.js.map → 823-33c5207c68-lite.chunk.js.map} +1 -1
- package/dist/scripts/8261-69854ff4d5-lite.chunk.js +2 -0
- package/dist/scripts/8261-69854ff4d5-lite.chunk.js.map +1 -0
- package/dist/scripts/{8466-ee9d40ee97-lite.chunk.js → 8466-cea62163e8-lite.chunk.js} +1 -1
- package/dist/scripts/{8466-ee9d40ee97-lite.chunk.js.map → 8466-cea62163e8-lite.chunk.js.map} +1 -1
- package/dist/scripts/{8681-41edd08b98-lite.chunk.js → 8681-49db3daae6-lite.chunk.js} +2 -2
- package/dist/scripts/{8681-41edd08b98-lite.chunk.js.map → 8681-49db3daae6-lite.chunk.js.map} +1 -1
- package/dist/scripts/{8772-9ae4d77363-lite.chunk.js → 8772-6c11095cea-lite.chunk.js} +1 -1
- package/dist/scripts/{8772-9ae4d77363-lite.chunk.js.map → 8772-6c11095cea-lite.chunk.js.map} +1 -1
- package/dist/scripts/{8906-b75b51bd0f-lite.chunk.js → 8906-2f6b5e4c5c-lite.chunk.js} +2 -2
- package/dist/scripts/{8906-b75b51bd0f-lite.chunk.js.map → 8906-2f6b5e4c5c-lite.chunk.js.map} +1 -1
- package/dist/scripts/{920-4de8efbcf1-lite.chunk.js → 920-acc6596891-lite.chunk.js} +1 -1
- package/dist/scripts/{920-4de8efbcf1-lite.chunk.js.map → 920-acc6596891-lite.chunk.js.map} +1 -1
- package/dist/scripts/{9212-8f95fbd9b9-lite.chunk.js → 9212-cc987a13bf-lite.chunk.js} +1 -1
- package/dist/scripts/{9212-8f95fbd9b9-lite.chunk.js.map → 9212-cc987a13bf-lite.chunk.js.map} +1 -1
- package/dist/scripts/{9242-2e533bdc0d-lite.chunk.js → 9242-144e7728ad-lite.chunk.js} +1 -1
- package/dist/scripts/{9242-2e533bdc0d-lite.chunk.js.map → 9242-144e7728ad-lite.chunk.js.map} +1 -1
- package/dist/scripts/{9264-d2285d4310-lite.chunk.js → 9264-518952f13f-lite.chunk.js} +1 -1
- package/dist/scripts/{9264-d2285d4310-lite.chunk.js.map → 9264-518952f13f-lite.chunk.js.map} +1 -1
- package/dist/scripts/{9478-8eacf2fe47-lite.chunk.js → 9478-4b3c088537-lite.chunk.js} +2 -2
- package/dist/scripts/{9478-8eacf2fe47-lite.chunk.js.map → 9478-4b3c088537-lite.chunk.js.map} +1 -1
- package/dist/scripts/{9484-be04a34bbf-lite.chunk.js → 9484-b85011dbea-lite.chunk.js} +2 -2
- package/dist/scripts/{9484-be04a34bbf-lite.chunk.js.map → 9484-b85011dbea-lite.chunk.js.map} +1 -1
- package/dist/scripts/bundle-11bfce2e8c.min.js +3 -0
- package/dist/scripts/{bundle-8f540a1154.min.js.map → bundle-11bfce2e8c.min.js.map} +1 -1
- package/package.json +1 -1
- package/dist/scripts/1285-c322e093f9-lite.chunk.js.map +0 -1
- package/dist/scripts/3012-b5208d6981-lite.chunk.js.map +0 -1
- package/dist/scripts/5595-3763b14d77-lite.chunk.js.map +0 -1
- package/dist/scripts/7293-afd3349468-lite.chunk.js +0 -2
- package/dist/scripts/8261-72453f1978-lite.chunk.js +0 -2
- package/dist/scripts/8261-72453f1978-lite.chunk.js.map +0 -1
- package/dist/scripts/bundle-8f540a1154.min.js +0 -3
- /package/dist/scripts/{170-1f815b85a1-lite.chunk.js.LICENSE.txt → 170-2d124965b7-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{2118-462a279c5a-lite.chunk.js.LICENSE.txt → 2118-ec2a5f1e9b-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{3841-95df66e647-lite.chunk.js.LICENSE.txt → 3841-bfae79638b-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{4778-ebe369973c-lite.chunk.js.LICENSE.txt → 4778-3c9f2b7f76-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{4942-a27a31e79e-lite.chunk.js.LICENSE.txt → 4942-acce40b333-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{5268-f4db3933ff-lite.chunk.js.LICENSE.txt → 5268-9b7560f3b1-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{6102-4d948a5e48-lite.chunk.js.LICENSE.txt → 6102-6e5494bf09-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{771-eb60e33941-lite.chunk.js.LICENSE.txt → 771-5612b4ffc2-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{8024-66413cc05b-lite.chunk.js.LICENSE.txt → 8024-765a4170c7-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{8681-41edd08b98-lite.chunk.js.LICENSE.txt → 8681-49db3daae6-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{8906-b75b51bd0f-lite.chunk.js.LICENSE.txt → 8906-2f6b5e4c5c-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{9478-8eacf2fe47-lite.chunk.js.LICENSE.txt → 9478-4b3c088537-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{9484-be04a34bbf-lite.chunk.js.LICENSE.txt → 9484-b85011dbea-lite.chunk.js.LICENSE.txt} +0 -0
- /package/dist/scripts/{bundle-8f540a1154.min.js.LICENSE.txt → bundle-11bfce2e8c.min.js.LICENSE.txt} +0 -0
package/dist/scripts/{2875-0e5f209e47-lite.chunk.js.map → 2875-aefd69a61f-lite.chunk.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scripts/2875-0e5f209e47-lite.chunk.js","mappings":"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","sources":["file:///app/packages/libs/shared/src/apps/calendar/flight-request/CalendarRequests.ts","file:///app/packages/libs/shared/src/apps/subjects/components/audience-item/audience-item.scss","file:///app/packages/libs/shared/src/apps/subjects/components/audience-item/AudienceItem.tsx","file:///app/packages/libs/shared/src/apps/subjects/constants/DashboardStatusConfig.ts","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/dashboard-status-badge/dashboard-status-badge.scss","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/dashboard-status-badge/DashboardStatusBadge.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/preview-banner/preview-banner.scss","file:///app/packages/libs/shared/src/apps/subjects/components/preview-banner/PreviewBanner.tsx","file:///app/packages/libs/common/src/react/utils/PortalHelper.ts","file:///app/packages/libs/shared/src/components/back-button/BackButton.tsx","file:///app/packages/libs/shared/src/components/banner-header/banner-header.scss","file:///app/packages/libs/shared/src/components/banner-header/BannerHeader.tsx","file:///app/packages/libs/shared/src/components/breadcrumbs/Breadcrumbs.tsx","file:///app/packages/libs/shared/src/errors/handlers/HttpErrorHandlers.ts","file:///app/packages/libs/shared/src/flight-requests/FollowRequests.ts","file:///app/packages/libs/shared/src/hooks/UseHandleObjectError.ts","file:///app/packages/libs/shared/src/hooks/usePrevious.ts","file:///app/packages/libs/shared/src/hooks/useTableOfContentsScroll.tsx","file:///app/packages/projects/lite/src/apps/subjects/utils/ClassificationAppLinks.ts","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/empty-state/CuratedClassificationEmptyState.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/table-of-contents/table-of-contents.scss","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/table-of-contents/TableOfContents.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/teacher-only/TeacherOnlyEmptyState.tsx","file:///app/packages/libs/shared/src/hooks/useTableOfContentsActiveHeading.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/audience-filter/AudienceFilter.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/audiences/ClassificationDashboardAudiences.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/ClassificationDashboard.tsx","file:///app/packages/libs/shared/src/apps/subjects/hooks/useGetTopicsWidgets.ts","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/partial-loading/PartialClassificationDashboard.tsx","file:///app/packages/projects/lite/src/apps/subjects/errors/TopicNotFoundError.ts","file:///app/packages/projects/lite/src/apps/subjects/views/classification/ClassificationViewUtils.ts","file:///app/packages/projects/lite/src/apps/subjects/views/classification/curated-classification-view.scss","file:///app/packages/projects/lite/src/apps/subjects/views/classification/CuratedClassificationView.tsx","file:///app/packages/projects/lite/src/shared/flight-requests/ProductboardRequests.ts"],"sourcesContent":["import { UrlHelper } from 'libs/common/backbone/utils/UrlHelper';\nimport { Flight } from 'libs/common/flight';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\nimport { DateHelper } from 'libs/common/react/utils/DateHelper';\n\nimport { CalendarEvent, CalendarEventContentType } from 'libs/shared/interfaces';\n\nexport const CalendarRequests = {\n calendarEvents(\n from: string,\n to: string,\n presentationId: string\n ): Flight.PublicRequest {\n return {\n url: UrlHelper.urlBuilder('{gateway}/v1/discover/special-events/content', { from, to, presentationId }),\n publicUrl: UrlHelper.urlBuilder(`/api/discover/special-events/content`, { from, to, presentationId }),\n key: `presentation:${presentationId}:events:from:${from}:to${to}`\n };\n },\n\n nextTopicSpecialEvent(\n classificationId: string,\n presentationId: string\n ): Flight.PublicRequest {\n const params = {\n presentationId,\n limit: 1,\n from: DateHelper.format(new Date(), 'YYYY-MM-DD'),\n objectType: CalendarEventContentType.Classification\n };\n\n return {\n url: UrlHelper.urlBuilder(`{gateway}/v1/discover/special-events/object/${classificationId}/next-events`, params),\n publicUrl: UrlHelper.urlBuilder(`/api/discover/special-events/object/${classificationId}/next-events`, params),\n key: `presentation:${presentationId}:events:classification:${classificationId}`,\n formatData: (events: CalendarEvent[]) => ArrayHelper.first(events)\n };\n }\n};\n","// extracted by mini-css-extract-plugin\nexport default {\"disabled\":\"pERi4\",\"disabledHighlighted\":\"AxyWm\"};","import * as React from 'react';\n\nimport { FunctionHelper } from 'libs/common/backbone/utils/FunctionHelper';\n\nimport { PresentationAudience } from 'libs/shared/interfaces';\n\nimport styles from './audience-item.scss';\n\nfunction lowerCaseToTitleCase(str: string): string {\n return str.split(' ').map((s: string) => s.charAt(0).toUpperCase() + s.substring(1)).join(' ');\n}\n\nfunction getColourClass(highlight: boolean, isDisabled: boolean): string {\n if (highlight) return isDisabled ? `${styles.disabledHighlighted} text-light` : 'bg-info text-light';\n if (isDisabled) return `${styles.disabled} text-secondary`;\n return 'bg-light';\n}\n\ninterface AudienceItemProps {\n audience: PresentationAudience;\n highlight: boolean;\n setAudience?: (audience: PresentationAudience, highlight: boolean) => void;\n isDisabled?: boolean;\n extraClasses?: string;\n}\n\nAudienceItem.defaultProps = {\n extraClasses: ''\n};\n\nexport function AudienceItem(props: AudienceItemProps): React.ReactElement {\n const { audience, highlight, setAudience, isDisabled, extraClasses } = props;\n\n const colourClass = getColourClass(highlight, isDisabled);\n const cursorClass = isDisabled ? 'cursor-default' : 'cursor-pointer';\n const className = `rounded-pill d-inline-block me-1 user-select-none ${cursorClass} ${colourClass} ${extraClasses}`;\n\n const onClick = () => {\n if (isDisabled || !FunctionHelper.isFunction(setAudience))\n return;\n\n setAudience(audience, !highlight);\n };\n\n return (\n <span\n className={className}\n onClick={onClick}\n role='checkbox'\n aria-checked={highlight}\n >\n {lowerCaseToTitleCase(audience.name)}\n </span>\n );\n}","import { localSvgs } from 'libs/shared/images/svg';\nimport { DashboardStatus } from 'libs/shared/interfaces/models/Dashboard';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\ninterface DashboardStatusConfigType {\n statusName: string;\n actionName: string;\n svgName: localSvgs;\n svgColorClassName: string;\n}\n\nexport const DashboardStatusConfig: Record<DashboardStatus, DashboardStatusConfigType> = {\n [DashboardStatus.Archived]: {\n svgName: cvSvgLibrary.Archive,\n svgColorClassName: 'text-secondary',\n actionName: 'Archive',\n statusName: 'Archived'\n },\n [DashboardStatus.Draft]: {\n svgName: cvSvgLibrary.Edit,\n svgColorClassName: '',\n actionName: 'Draft',\n statusName: 'Draft'\n },\n [DashboardStatus.Published]: {\n svgName: cvSvgLibrary.VisibleOn,\n svgColorClassName: 'text-success',\n actionName: 'Publish',\n statusName: 'Published'\n }\n};","// extracted by mini-css-extract-plugin\nexport default {\"badge\":\"ciO47\",\"draftLight\":\"A6Yi7\",\"draftDark\":\"fkXBX\",\"published\":\"Ovzwy\",\"archived\":\"r_dco\"};","import React from 'react';\n\nimport { DashboardStatusConfig } from 'libs/shared/apps/subjects/constants/DashboardStatusConfig';\nimport { SvgContainer } from 'libs/shared/components/svg-container/SvgContainer';\nimport { DashboardStatus } from 'libs/shared/interfaces';\n\nimport styles from './dashboard-status-badge.scss';\n\nfunction getClassName(props: DashboardStatusBadgeProps): string {\n let className = `rounded-pill d-flex align-items-center ps-2 py-1 fw-semibold ms-2 ${styles.badge}`;\n\n switch (props.status) {\n case DashboardStatus.Published:\n className += ` ${styles.published}`;\n break;\n case DashboardStatus.Archived:\n className += ` ${styles.archived}`;\n break;\n case DashboardStatus.Draft:\n className += ` ${props.darkMode ? styles.draftDark : styles.draftLight}`;\n break;\n }\n\n if (props.wrapperClassName)\n className += ` ${props.wrapperClassName}`;\n\n return className;\n}\n\ninterface DashboardStatusBadgeProps {\n status: DashboardStatus;\n darkMode?: boolean;\n wrapperClassName?: string;\n}\n\nexport function DashboardStatusBadge(props: DashboardStatusBadgeProps): JSX.Element {\n const { statusName, svgName } = DashboardStatusConfig[props.status];\n\n return (\n <div className={getClassName(props)}>\n <SvgContainer svgName={svgName} />\n <div>{statusName}</div>\n </div>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"stickyWrapper\":\"zhw6K\",\"badgeWrapper\":\"NOvn1\",\"badge\":\"pxQSR\"};","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { DashboardStatusBadge } from 'libs/shared/apps/subjects/components/classification-dashboard/dashboard-status-badge/DashboardStatusBadge';\nimport { EmojiText } from 'libs/shared/components/emoji-text/EmojiText';\nimport { DashboardStatus } from 'libs/shared/interfaces';\n\nimport styles from './preview-banner.scss';\n\nconst namespace = 'shared.classificationPreviewBanner';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface PreviewBannerProps {\n status: DashboardStatus;\n type: 'company' | 'topic';\n}\n\nexport function PreviewBanner(props: PreviewBannerProps): JSX.Element {\n return (\n <div className={`${styles.stickyWrapper} py-2 d-flex justify-content-space-between bg-dark text-white mx-2 rounded`}>\n <div className={`position-absolute d-flex ${styles.badgeWrapper}`}>\n <DashboardStatusBadge status={props.status} wrapperClassName={`${styles.badge}`} darkMode />\n </div>\n <div className='flex-grow-1'>\n <h1 className='text-center my-3 h5'>\n <EmojiText emoji='👀' />\n {getPhrase(props.type === 'topic' ? 'topicTitle' : 'companyTitle')}\n </h1>\n </div>\n </div>\n );\n}\n","import React from 'react';\nimport { createPortal } from 'react-dom';\n\nexport const PortalHelper = {\n renderInPortalIfExists(component: React.ReactElement, portalContainer: Element | null): React.ReactElement {\n if (portalContainer)\n return createPortal(component, portalContainer);\n\n return component;\n }\n};","import * as React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\n\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { SvgContainer, SvgContainerSize } from 'libs/shared/components/svg-container/SvgContainer';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nconst namespace = 'shared.backButton';\n\ninterface BackButtonProps {\n appLink: Core.AppLink;\n backToName?: string;\n color?: 'black' | 'white';\n extraClasses?: string;\n /**\n * Whether or not the button text has a text shadow. Defaults to true\n */\n textShadow?: boolean;\n}\n\nBackButton.defaultProps = {\n color: 'black',\n extraClasses: ''\n};\n\nexport function BackButton(props: BackButtonProps): React.ReactElement {\n const { backToName, appLink, color, extraClasses, textShadow } = {\n textShadow: true,\n ...props\n };\n\n const backPhrase = backToName\n ? LanguageService.getPhrase(namespace, 'backTo', { backToName })\n : LanguageService.getPhrase(namespace, 'back');\n\n const colorClass = color === 'black' ? '' : 'text-white';\n const textShadowClass = textShadow ? 'text-shadow' : '';\n\n return (\n <AppLink\n appLink={appLink}\n className={`d-inline-flex align-items-center h5 mb-0 ${extraClasses} ${colorClass} ${textShadowClass}`}\n >\n <SvgContainer svgName={cvSvgLibrary.ChevronLeft} size={SvgContainerSize.Medium} />\n <span className='ms-1'>{backPhrase}</span>\n </AppLink>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"bannerContent\":\"sSCTB\",\"actionsContainer\":\"Z5WI2\",\"bannerContentWithLogo\":\"rgs7Q\",\"container\":\"M51HJ\",\"logoContainer\":\"vkeJk\",\"logoContainerLeft\":\"M3U9B\",\"logoHeading\":\"EtRwC\",\"specialEventContainer\":\"rOxDc\",\"headingLarge\":\"_8pnV\",\"heading\":\"JXVBH\"};","import * as React from 'react';\n\nimport { Core } from 'libs/common/core';\nimport { DateHelper } from 'libs/common/react/utils/DateHelper';\nimport { PortalHelper } from 'libs/common/react/utils/PortalHelper';\n\nimport { ComingSoonTag } from 'libs/shared/apps/calendar/components/coming-soon-tag/ComingSoonTag';\nimport { GenericCalendarDate } from 'libs/shared/apps/calendar/components/generic-calendar-date/GenericCalendarDate';\nimport { CalendarTheme } from 'libs/shared/apps/calendar/interfaces/CalendarTheme';\nimport { ActionOptions, Actions } from 'libs/shared/components/actions/Actions';\nimport { BackButton } from 'libs/shared/components/back-button/BackButton';\nimport { LazyImage } from 'libs/shared/components/lazy-image/LazyImage';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { ImageMinDimensions } from 'libs/shared/constants/ImageSizes';\nimport { BannerPortalContext } from 'libs/shared/context/BannerPortalContext';\nimport { ImageSize, ImageType, ResizeType } from 'libs/shared/enums/Images';\nimport { useBreakpoints } from 'libs/shared/hooks/useBreakpoints';\nimport { Banner, CalendarEvent, Logo } from 'libs/shared/interfaces';\nimport { ImageHelper, ImageOptions } from 'libs/shared/utils/ImageHelper';\n\nimport styles from './banner-header.scss';\n\nconst RATIO = `${ImageMinDimensions[ImageType.Banners].width}:${ImageMinDimensions[ImageType.Banners].height}`;\nconst DEFAULT_WIDTH = 1200; // This is ImageSize.Large for a Banner.\nconst LARGE_SCREEN_WIDTH = 1920;\n\nfunction useGetImageWidth(): number {\n const breakpoints = useBreakpoints();\n\n if (breakpoints.xxl)\n return LARGE_SCREEN_WIDTH;\n\n return DEFAULT_WIDTH;\n}\n\nfunction getSizeClass(heading: string): string {\n if (heading.length < 160)\n return 'h1';\n\n return styles.headingLarge;\n}\n\ninterface BannerHeaderProps {\n heading: string;\n banner?: Banner;\n bannerClassName?: string;\n imageCdnUrl?: string;\n logo?: Logo;\n actions?: ActionOptions[];\n specialEvent?: CalendarEvent;\n backButtonAppLink?: Core.AppLink;\n backButtonText?: string;\n backButtonClasses?: string;\n sortComponent?: JSX.Element;\n blockColourClass?: string;\n actionsDropdownClassName?: string;\n detailsComponent?: () => React.ReactElement;\n imageOptions?: ImageOptions;\n showComingSoon?: boolean;\n alignLogoLeft?: boolean;\n calendarTheme?: CalendarTheme;\n}\n\nconst namespace = 'shared.bannerHeader';\n\nexport const BannerHeader = React.memo(function(props: React.PropsWithChildren<BannerHeaderProps>): React.ReactElement {\n const { heading, banner, imageCdnUrl, actions, sortComponent, blockColourClass, specialEvent } = props;\n\n const portalContainerContext = React.useContext(BannerPortalContext);\n\n const imageWidth = useGetImageWidth();\n\n const specialEventIsToday = React.useMemo(() => {\n if (!specialEvent || props.showComingSoon)\n return false;\n\n const today = DateHelper.format(new Date(), 'YYYY-MM-DD');\n\n if (!specialEvent.endDate)\n return specialEvent.startDate === today;\n\n return specialEvent.startDate <= today && specialEvent.endDate >= today;\n }, [specialEvent]);\n\n const imageOptions = props.imageOptions || {\n width: imageWidth,\n ratio: RATIO,\n resizeType: ResizeType.Cover\n };\n\n const url = !!banner && !!imageCdnUrl && ImageHelper.createBannerUrl(banner, {\n fallbackBaseUrl: imageCdnUrl,\n fallbackCategoryName: heading,\n type: ImageType.Banners\n }, imageOptions);\n\n const containerProps: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> = {\n className: `banner banner-header ${props.bannerClassName}`,\n style: url ? { backgroundImage: `url('${url}')` } : {}\n };\n\n if (!banner && blockColourClass) {\n delete containerProps.style;\n containerProps.className += ` ${blockColourClass}`;\n }\n\n const DetailsComponent = props.detailsComponent;\n\n return PortalHelper.renderInPortalIfExists(\n // \"banner\" is used in playlists in Online. banner-header is used by all other projects\n <header {...containerProps}>\n <div className={`container ${styles.container} position-relative inner-banner`}>\n {props.backButtonAppLink && (\n <div className='pt-3'>\n <BackButton\n appLink={props.backButtonAppLink}\n backToName={props.backButtonText}\n extraClasses={props.backButtonClasses}\n color='white'\n />\n </div>\n )}\n \n <div className={`${props.alignLogoLeft ? 'position-absolute top-50 start-0 translate-middle-y w-100 ps-4' : `${styles.bannerContent} ${props.logo?.url ? styles.bannerContentWithLogo : ''}`}`}>\n {!!specialEvent && (\n <div className={`position-relative ${styles.specialEventContainer}`}>\n <GenericCalendarDate\n body={{\n type: specialEvent.endDate ? 'range' : 'day',\n text: specialEvent.endDate\n ? `${DateHelper.format(specialEvent.startDate, 'DD')}-${DateHelper.format(specialEvent.endDate, 'DD')}`\n : DateHelper.format(specialEvent.startDate, 'DD')\n }}\n month={DateHelper.format(specialEvent.startDate, 'MMMM')}\n theme={props.calendarTheme}\n />\n </div>\n )}\n <div>\n {specialEventIsToday && (\n <div className='rounded-pill py-1 px-2 my-1 me-1 fw-semibold bg-light-blue lh-1 d-inline-block'>\n <Text namespace={namespace} phrase='onToday' />\n </div>\n )}\n {props.showComingSoon && (\n <ComingSoonTag className='pe-2 fw-semibold mb-1 rounded-pill justify-content-start text-nowrap' />\n )}\n <div className='d-flex align-items-center'>\n {props.alignLogoLeft &&\n <div className={`${styles.logoContainerLeft} d-none d-md-block partial-loading-background rounded-circle overflow-hidden me-3`}>\n {props.logo?.url &&\n <LazyImage src={ImageHelper.createUrl(props.logo?.url, { size: ImageSize.Small })} />}\n </div>\n }\n <h1 className={`text-white text-shadow pe-3 ${styles.heading} ${getSizeClass(heading)} ${props.alignLogoLeft ? 'w-50' : ''}`}>\n {heading}\n {DetailsComponent && <DetailsComponent />}\n </h1>\n </div>\n </div>\n {!!actions && (\n <div className={styles.actionsContainer}>\n <Actions\n actions={actions}\n sortComponent={sortComponent}\n actionsDropdownClassName={props.actionsDropdownClassName}\n />\n </div>\n )}\n </div>\n {!props.alignLogoLeft && !!props.logo?.url &&\n <div className={styles.logoContainer}>\n <img\n src={ImageHelper.createUrl(props.logo.url, { size: ImageSize.Small })}\n className='rounded-circle'\n />\n </div>\n }\n </div>\n </header>,\n portalContainerContext?.container\n );\n}, (prevProps, nextProps): boolean => (\n prevProps.actions === nextProps.actions\n && prevProps.heading === nextProps.heading\n && prevProps.logo?.url === nextProps.logo?.url\n));\n\nexport function PartialBannerHeader(): JSX.Element {\n const portalContainerContext = React.useContext(BannerPortalContext);\n\n return PortalHelper.renderInPortalIfExists(\n <div className={`partial-banner partial-loading-background ${styles.banner}`} />,\n portalContainerContext?.container\n );\n}","import * as React from 'react';\n\nimport { Core } from 'libs/common/core';\n\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { useMediaQuery } from 'libs/shared/hooks/UseMediaQuery';\nimport { PartialLoadingHelper } from 'libs/shared/utils/PartialLoadingHelper';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport { SvgContainer, SvgContainerSize } from '../svg-container/SvgContainer';\n\nexport interface Breadcrumb {\n name: string;\n appLink?: Core.AppLink;\n active?: boolean;\n}\n\ninterface BreadcrumbItemProps {\n breadcrumb: Breadcrumb;\n withBackIcon?: boolean;\n}\n\nexport const BreadcrumbItem = ({ breadcrumb: { name, appLink, active }, withBackIcon }: BreadcrumbItemProps) => (\n <li className={`breadcrumb-item${active ? ' active' : ''}`}>\n {active\n ? <strong>{name}</strong>\n : <AppLink appLink={appLink}>\n {withBackIcon && <SvgContainer svgName={cvSvgLibrary.ChevronLeft} size={SvgContainerSize.Small} />}\n <span className={withBackIcon ? 'ms-2' : ''}>{name}</span>\n </AppLink>\n }\n </li>\n);\n\ninterface BreadcrumbsProps {\n breadcrumbs: Breadcrumb[];\n}\n\nexport const Breadcrumbs = ({ breadcrumbs }: BreadcrumbsProps) => {\n const isMobile = useMediaQuery(MediaQueryStrings.XS);\n\n const length = breadcrumbs?.length;\n\n if (!length || (isMobile && length < 2))\n return <></>;\n\n if (isMobile)\n return (\n <nav aria-label='breadcrumb'>\n <ol className='breadcrumb m-0 p-0'>\n <BreadcrumbItem breadcrumb={breadcrumbs[length - 2]} withBackIcon />\n </ol>\n </nav>\n );\n\n return (\n <nav aria-label='breadcrumb'>\n <ol className='breadcrumb m-0 p-0'>\n {breadcrumbs.map((b, idx) => <BreadcrumbItem key={idx} breadcrumb={b} />)}\n </ol>\n </nav>\n );\n};\n\nexport const PartialBreadcrumbs = React.memo(function({ numItems = 3 }: { numItems?: number; }) {\n const isMobile = useMediaQuery(MediaQueryStrings.XS);\n\n if (isMobile) {\n return (\n <div className='partial-loading-background' style={{ height: '1.3125rem', width: '6rem' }} />\n );\n }\n\n return (\n <nav aria-label='breadcrumb'>\n <ol className='breadcrumb m-0 p-0'>\n {PartialLoadingHelper.getPartialLoadingItems({ numItems }).map(({ width }, idx) => (\n <li key={idx} className='breadcrumb-item'>\n <span className='d-inline-block partial-loading-background' style={{ width }} dangerouslySetInnerHTML={{ __html: ' ' }} />\n </li>\n ))}\n </ol>\n </nav>\n );\n});","import { BaseError } from 'libs/common/backbone/core/BaseError';\nimport { HttpStatus } from 'libs/common/backbone/enums/HttpStatus';\nimport { Xhr } from 'libs/common/backbone/interfaces';\nimport { Core } from 'libs/common/core';\n\nimport { NotFoundError } from 'libs/shared/errors/general/not-found/NotFoundError';\nimport { PrivateResourceError } from 'libs/shared/errors/general/private-resource/PrivateResourceError';\nimport { RegionLockedResourceError } from 'libs/shared/errors/general/region-locked-resource/RegionLockedResourceError';\nimport { UnspecifiedError } from 'libs/shared/errors/general/unspecified-error/UnspecifiedError';\nimport { VideoTypes } from 'libs/shared/interfaces';\n\nexport interface HttpErrorMap {\n notFound?: new () => BaseError;\n forbidden?: {\n rating?: new (description: string) => BaseError;\n yearLevel?: new (description: string) => BaseError;\n region?: new () => BaseError;\n privacy?: new (video?: VideoTypes) => BaseError;\n };\n badRequest?: new () => BaseError;\n}\n\nexport type IgnoreHttpErrorMap = {\n [key in keyof HttpErrorMap]: boolean;\n};\n\nconst defaultErrors: HttpErrorMap = {\n notFound: NotFoundError,\n forbidden: {\n rating: PrivateResourceError,\n yearLevel: PrivateResourceError,\n region: RegionLockedResourceError,\n privacy: PrivateResourceError\n },\n badRequest: UnspecifiedError\n};\n\nexport function handleHttpError(\n info: HttpStatus | Xhr,\n customErrorMap: HttpErrorMap = {},\n /**\n * Prevent certain errors in the errorMap from being thrown\n * so that you may implement your own handler\n */\n ignoreMap: IgnoreHttpErrorMap = {}\n): void {\n if (!info)\n return;\n\n let statusCode: HttpStatus;\n\n if (typeof(info) === 'number') {\n statusCode = info;\n } else {\n statusCode = info.status;\n }\n\n const errorMap = {\n ...defaultErrors,\n ...customErrorMap\n };\n\n if (!statusCode)\n return;\n\n if (!Core.ErrorHelper.isStatusCodeError(statusCode))\n return;\n\n if (statusCode === HttpStatus.NotFound) {\n if (!ignoreMap.notFound)\n Core.ErrorHelper.throw(new errorMap.notFound());\n return;\n }\n\n if (statusCode === HttpStatus.Forbidden) {\n /**\n * TODO: Work out how to go about handling all forbidden errors, such as region locking, year levels,\n * ratings, and privacy.\n */\n if (!ignoreMap.forbidden)\n Core.ErrorHelper.throw(new errorMap.forbidden.privacy());\n return;\n }\n\n if (!ignoreMap.badRequest)\n Core.ErrorHelper.throw(new errorMap.badRequest());\n}\n\nexport function handleXhrError(xhr: Xhr, customErrorMap?: HttpErrorMap): void {\n handleHttpError(xhr.status, customErrorMap);\n}","import { HttpVerbs } from 'libs/common/backbone/enums/HttpVerbs';\nimport { UrlHelper } from 'libs/common/backbone/utils/UrlHelper';\nimport { Flight } from 'libs/common/flight';\n\nconst endpoints = {\n follow: () => `/api/domain/v1/subjects/classifications/following`,\n unfollow: (ids: string[]) => UrlHelper.urlBuilder('/api/domain/v1/subjects/classifications/following', { id: ids })\n};\n\nexport const FollowRequests = {\n /**\n * @param data - array of object ids the user is going to follow\n */\n follow(ids: string[], success?: (data: string[]) => void, error?: () => void): Flight.Request {\n return {\n url: endpoints.follow(),\n key: `follow:${ids.join(',')}`,\n type: HttpVerbs.POST,\n data: ids,\n success,\n error,\n invalidationKeys: [ ...ids.map(id => `classification:${id}`), 'my:subject:preferences', 'classifications' ]\n };\n },\n\n unfollow(ids: string[], success?: () => void, error?: () => void): Flight.Request {\n return {\n url: endpoints.unfollow(ids),\n key: `unfollow:${ids.join(',')}`,\n type: HttpVerbs.DELETE,\n success,\n error,\n invalidationKeys: [ ...ids.map(id => `classification:${id}`), 'my:subject:preferences', 'classifications' ]\n };\n }\n};\n","import { useEffect } from 'react';\n\nimport { Flight } from 'libs/common/flight';\n\nimport { handleHttpError, HttpErrorMap, IgnoreHttpErrorMap } from 'libs/shared/errors/handlers/HttpErrorHandlers';\n\nfunction generateCacheKey(flightObjs: Array<Flight.Response<any>>): string {\n return flightObjs.map(obj => obj.statusCode).join(':');\n}\n\n// TODO: Change this to just `useHandleHttpError` and only accept a status code.\nexport function useHandleObjectError(\n _flightObjs: Flight.Response<any> | Array<Flight.Response<any>>,\n customErrors?: HttpErrorMap,\n ignoreErrors?: IgnoreHttpErrorMap\n): void {\n const flightObjs = Array.isArray(_flightObjs) ? _flightObjs : [_flightObjs];\n\n useEffect(() => {\n flightObjs.forEach(obj => {\n handleHttpError(obj.statusCode, customErrors, ignoreErrors);\n });\n }, [ generateCacheKey(flightObjs), customErrors, ignoreErrors ]);\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>();\n React.useEffect(() => {\n ref.current = value;\n });\n return ref.current;\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};","import { Core } from 'libs/common/core';\nimport { HashObject } from 'libs/common/react/interfaces/HashObject';\nimport { TextHelper } from 'libs/common/react/utils/TextHelper';\n\nimport { Classification, Playlist } from 'libs/shared/interfaces';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nexport const getClassificationAppLink = (params?: HashObject) =>\n (classification?: Classification): Core.AppLink => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION,\n args: classification ? [ classification.id, TextHelper.slugify(classification.name) ] : [],\n params: params || {}\n });\n\nexport const getPlaylistAppLink = (playlist: Playlist, classificationId: string): Core.AppLink => ({\n application: AppChannels.PLAYLISTS,\n action: Actions.Playlists.PLAYLIST,\n args: [ playlist.id, TextHelper.slugify(playlist.name) ],\n params: { classificationId }\n});\n\nexport const getAllTopicsAppLink = (presentationId?: string): Core.AppLink => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_ALL,\n params: presentationId ? { presentationId } : {}\n});\n\nexport const getClassificationTopicsAppLink = (params?: HashObject) =>\n (classification?: Classification): Core.AppLink => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_TOPICS,\n args: classification ? [ classification.id, TextHelper.slugify(classification.name) ] : [],\n params: params || {}\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 { CuratedDashboard, DashboardStatus } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\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={cvSvgLibrary.Plus}\n disabled={isArchived}\n />\n </Tooltip>\n </>\n )}\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"container\":\"k1iOO\",\"itemsWrapper\":\"IC4wJ\",\"anchorWrapper\":\"ciEf6\",\"default\":\"CJonr\",\"selectedItem\":\"A9mBx\",\"disabled\":\"sp1Xl\"};","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 { CuratedWidget } from 'libs/shared/interfaces';\n\nimport styles from './table-of-contents.scss';\n\ninterface TableOfContentsProps {\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}\n\nexport function TableOfContents(props: TableOfContentsProps): JSX.Element {\n function getAppLink(widget: CuratedWidget): Core.AppLink {\n const currentAppLink = Core.AppLinkHelper.getCurrentAppLink();\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 <div className={`${styles.container} ps-3`}>\n <h2 className='h5'>{props.title}</h2>\n <div className={`${styles.itemsWrapper}`}>\n {props.widgets.map((w, idx) => {\n return (\n <AppLink\n key={w.id}\n appLink={getAppLink(w)}\n appLinkOptions={{ replace: true }}\n className={`${styles.anchorWrapper} ${!props.clickable ? styles.disabled : ''} ${props.activeId === w.id ? styles.selectedItem : ''}`}\n onClick={() => {\n ScrollHelper.preventScrollTop();\n props.setControlledId(w.id);\n }}\n analyticsData={{\n ...props.analyticsData,\n id: w.id,\n name: w.name\n }}\n analyticsOptions={{\n actionType: UserAction.Click,\n entity: EntityType.Widget,\n location: LocationContext.TableOfContents\n }}\n >\n <div className={`${!props.activeId && idx === 0 ? styles.default : ''} `}>\n {w.name}\n </div>\n </AppLink>\n );\n })}\n </div>\n </div>\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}","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 * as React from 'react';\n\nimport { StorageType } from 'libs/common/backbone/utils/LocalStorageHelper';\nimport { Core } from 'libs/common/core';\nimport { useViewModel } from 'libs/common/react/hooks/UseViewModel';\nimport { ObjectHelper } from 'libs/common/react/utils/ObjectHelper';\n\nimport { AudienceItem } from 'libs/shared/apps/subjects/components/audience-item/AudienceItem';\nimport { DivButton } from 'libs/shared/components/div-button/DivButton';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { SharedViewModelKeys } from 'libs/shared/constants/SharedViewModelKeys';\nimport { PresentationAudience } from 'libs/shared/interfaces';\nimport { PartialLoadingHelper } from 'libs/shared/utils/PartialLoadingHelper';\n\nconst namespace = 'subjects.audienceFilter';\n\ninterface AudienceFilterProps {\n audiences: PresentationAudience[];\n activeAudiences?: PresentationAudience[];\n disabled?: boolean;\n appLink: Core.AppLink;\n disablePersist?: boolean;\n}\n\nexport function AudienceFilter(props: AudienceFilterProps): React.ReactElement {\n const { audiences, activeAudiences, disabled, appLink } = props;\n\n const [ , setActiveAudiences ] = useViewModel<PresentationAudience[]>(\n SharedViewModelKeys.AUDIENCE_FILTER,\n undefined,\n { storage: StorageType.SessionStorage }\n );\n\n React.useEffect(() => {\n if (!props.disablePersist)\n setActiveAudiences(activeAudiences);\n }, [activeAudiences]);\n\n function onToggleAudience(audience: PresentationAudience, isSelected: boolean): void {\n const activeAudienceNames = isSelected\n ? [ ...(activeAudiences?.map(a => a.name) ?? []), audience.name ]\n : activeAudiences.map(a => a.name).filter(name => name !== audience.name);\n\n const getParams = () => {\n const otherParams = ObjectHelper.omit(appLink.params, ['a']);\n\n if (!activeAudienceNames.length)\n return otherParams;\n\n return Object.assign({}, otherParams, { a: activeAudienceNames });\n };\n\n Core.AppLinkHelper.trigger({\n ...appLink,\n params: getParams()\n }, { replace: true });\n }\n\n function onClickClearAudiences(): void {\n const params = ObjectHelper.omit(appLink.params, ['a']);\n\n Core.AppLinkHelper.trigger({\n ...appLink,\n params\n }, { replace: true });\n }\n\n if (!audiences || !audiences.length)\n return <></>;\n\n return (\n <div className='d-flex flex-wrap row-gap-2'>\n {audiences.map((a: PresentationAudience) => (\n <AudienceItem\n key={a.masterId}\n audience={a}\n highlight={!!activeAudiences?.find(aa => aa.masterId === a.masterId)}\n setAudience={onToggleAudience}\n isDisabled={disabled}\n />\n ))}\n {(!!activeAudiences && !!Object.keys(activeAudiences).length) && (\n <DivButton className='info-link d-inline-block fw-semibold ms-1' onClick={onClickClearAudiences}>\n <Text namespace={namespace} phrase='clear' />\n </DivButton>\n )}\n </div>\n );\n}\n\nconst PARTIAL_AUDIENCES = PartialLoadingHelper.getPartialLoadingItems({ numItems: 6 });\n\nexport const PartialAudienceFilter = () => (\n <div className={'d-flex flex-wrap row-gap-2'}>\n {PARTIAL_AUDIENCES.map(({ width }, idx) => (\n <span\n key={idx}\n className='rounded-pill partial-loading-background me-1'\n dangerouslySetInnerHTML={{ __html: ' ' }}\n style={{ width }}\n />\n ))}\n </div>\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 { Classification, PresentationAudience } from 'libs/shared/interfaces';\nimport { AudienceHelper } from 'libs/shared/utils/audience-helper/AudienceHelper';\n\ninterface ClassificationDashboardAudiencesProps {\n classification: Classification;\n audiences: PresentationAudience[];\n activeAudiences: PresentationAudience[];\n\n appLink: Core.AppLink;\n isEmpty: boolean;\n isReadonly: boolean;\n isComingSoon: boolean;\n disablePersist: boolean;\n}\n\nexport function ClassificationDashboardAudiences(props: ClassificationDashboardAudiencesProps): JSX.Element {\n if (props.isComingSoon)\n return <></>;\n\n if (props.isEmpty && !props.activeAudiences?.length)\n return <></>;\n\n if (!AudienceHelper.shouldShowAudiences(props.audiences))\n return <></>;\n\n return (\n <AudienceFilter\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n disabled={props.isReadonly}\n appLink={props.appLink}\n disablePersist={props.disablePersist}\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 { CuratedClassificationEmptyState } from 'libs/shared/apps/subjects/components/classification-dashboard/empty-state/CuratedClassificationEmptyState';\nimport { TableOfContents } 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, Breadcrumbs } 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 { VideoSubTextType } from 'libs/shared/components/video-sub-text/VideoSubText';\nimport { WidgetHeader } from 'libs/shared/components/widgets/curated-widgets/components/header/WidgetHeader';\nimport { WidgetContainerView } from 'libs/shared/components/widgets/curated-widgets/WidgetContainerView';\nimport { WidgetAppLinks } from 'libs/shared/components/widgets/curated-widgets/WidgetProps';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { WidgetTemplate } from 'libs/shared/enums/WidgetTemplate';\nimport { WidgetTypeId } from 'libs/shared/enums/WidgetTypeId';\nimport { NotFoundError } from 'libs/shared/errors/general/not-found/NotFoundError';\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, CanFavouriteFunc, Classification, CuratedDashboard, CuratedWidget, CuratedWidgetQueryParams, DashboardStatus, DashboardTargetType, FavouriteFunc, Presentation, PresentationAudience, YearGroup } from 'libs/shared/interfaces';\nimport { CuratedDashboardHelper } from 'libs/shared/utils/DashboardHelper';\n\nimport { ClassificationDashboardAudiences } from './audiences/ClassificationDashboardAudiences';\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\ninterface ClassificationDashboardProps {\n dashboard: CuratedDashboard;\n classification: Classification;\n presentation: Presentation;\n hasPermissions: HasPermissionsFunc;\n hasLocalPermissions: HasLocalPermissionsFunc;\n resourceThumbnailFallbackImageUrl: string;\n specialEvent?: CalendarEvent;\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?: (locationContext: LocationContext) => void;\n setFavourite?: FavouriteFunc;\n canFavourite?: CanFavouriteFunc;\n canFollowSubjects: boolean;\n onSubmitFeedback?: (feedback: DashboardFeedbackData) => Promise<void>;\n\n appLinks?: WidgetAppLinks;\n\n imageCdnUrl: string\n emptyImageUrl: 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 isViewCurrentPresentation?: boolean;\n\n yearGroups?: YearGroup[];\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 // Fallback url to display for the company logo. Only used by Streamable Learning atm\n companyLogoFallbackUrl?: string;\n\n subTextType?: VideoSubTextType;\n \n contentType?: CalendarEventContentType;\n\n isBot?: boolean;\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(window.location.hash.slice(1) || '');\n\n const [ tableOfContentActiveId, setTableOfContentActiveId ] = React.useState<string>('');\n\n const headingElements = Array.from(headingRef.current);\n useTableOfContentsScroll(headingElements, props.tableOfContentsId);\n useTableOfContentsActiveHeading({\n setActiveId: setTableOfContentActiveId,\n headingElements,\n controlledId,\n setControlledId\n });\n \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 (props.isComingSoon)\n return false;\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 );\n\n return props.getWidgetContentRequest(id, params, template);\n }\n\n const showEmptyState = shouldShowEmptyState();\n const breadcrumbs = props.getBreadcrumbs?.();\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 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 const widgetsInTableOfContents = widgets.filter(w => {\n return !hideWidget(w) && !!w.metadata?.showInTableOfContents;\n });\n\n const shouldShowTableOfContents = widgetsInTableOfContents.length >= 2 && !isSmallScreen;\n \n if (props.isComingSoon) {\n Core.ErrorHelper.throw(new NotFoundError());\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 ${props.moviesAndTv ? '' : 'topic-dashboard'}`}>\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 />\n\n <div className={`d-flex flex-column row-gap-3 py-3 mb-3 ${(!props.isComingSoon) ? 'border-bottom' : ''}`}>\n <Breadcrumbs breadcrumbs={breadcrumbs} />\n <ClassificationDashboardAudiences\n classification={props.classification}\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n appLink={props.appLinks.audience?.()}\n isEmpty={showEmptyState}\n isReadonly={props.isReadonly}\n isComingSoon={props.isComingSoon}\n disablePersist={!props.isViewCurrentPresentation}\n />\n </div>\n\n <div className={`${shouldShowTableOfContents ? 'row no-wrap' : ''}`}>\n <div className={shouldShowTableOfContents ? 'col-9' : ''}>\n {widgets.map((widget, idx) => {\n if (hideWidget(widget))\n return <React.Fragment key={widget.id}></React.Fragment>;\n\n return (\n <WidgetContainerView\n headingElementRef={headingRef}\n key={widget.id}\n id={widget.id}\n name={widget.name}\n description={widget.description}\n templateId={widget.templateId}\n widgetTypeId={widget.widgetId}\n audiences={props.audiences}\n getContentRequest={getWidgetContentRequest}\n setIsEmpty={onSetIsEmpty}\n setFavourite={props.setFavourite}\n canFavourite={props.canFavourite}\n appLinks={props.appLinks}\n yearGroups={props.yearGroups}\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={shouldShowTableOfContents}\n lazyLoad={props.lazyLoad}\n dashboardTarget={DashboardTargetType.Classification}\n widgetIndex={idx}\n hasPermissions={props.hasPermissions}\n hasLocalPermissions={props.hasLocalPermissions}\n isPreviewing={props.isReadonly}\n companyLogoFallbackUrl={props.companyLogoFallbackUrl}\n subTextType={props.subTextType}\n contentType={props.contentType}\n resourceThumbnailFallbackImageUrl={props.resourceThumbnailFallbackImageUrl}\n preferences={widget.preferences}\n />\n );\n })}\n\n {!!videoList?.length && (\n <>\n <WidgetHeader name={LanguageService.getPhrase(namespace, 'videos')} description='' />\n <VideoList\n videos={videoList}\n yearGroups={props.yearGroups}\n getVideoAppLink={(v, opts) => props.appLinks.videoType(v, { ...opts, contextId: videoListWidgetId })}\n getSubTextAppLink={props.appLinks.subText}\n hasPermissions={props.hasPermissions}\n setFavourite={props.setFavourite}\n canFavourite={props.canFavourite}\n presentationAudiences={props.audiences}\n companyLogoFallbackUrl={props.companyLogoFallbackUrl}\n subTextType={props.subTextType}\n getPreviewQuestionsAppLink={props.appLinks.previewQuestions}\n />\n </>\n )}\n </div>\n\n {shouldShowTableOfContents && (\n <aside className='col-3'>\n <TableOfContents\n widgets={widgetsInTableOfContents}\n title={props.classification.name}\n activeId={tableOfContentActiveId}\n clickable={!props.isReadonly}\n analyticsData={props.analyticsData}\n setControlledId={setControlledId}\n />\n </aside>\n )}\n </div>\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}","import React from 'react';\n\nimport { Flight } from 'libs/common/react/index';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\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 widget.widgetId === WidgetTypeId.ClassificationPinnedVideos;\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 => widget.widgetId !== WidgetTypeId.ClassificationPinnedVideos) ?? [],\n videoList: systemGeneratedVideoContent.data?.content ?? [],\n videoListWidgetId: systemGeneratedVideoWidget?.id\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 PartialClassificationDashboard(): 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}","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { ErrorCta, ErrorPageError } from 'libs/shared/errors/primitives/ErrorPageError';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\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.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_ALL\n }\n };\n }\n}","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\nimport { ObjectHelper } from 'libs/common/react/utils/ObjectHelper';\nimport { TextHelper } from 'libs/common/react/utils/TextHelper';\n\nimport { ActionOptions } from 'libs/shared/components/actions/Actions';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { WidgetAppLinks } from 'libs/shared/components/widgets/curated-widgets/WidgetProps';\nimport { RelatedVideosContext } from 'libs/shared/enums/RelatedVideosContext';\nimport { Classification, Playlist, PlaylistCollection, Presentation, Resource, Series, SeriesCollection, Video, VideoCollection } from 'libs/shared/interfaces';\nimport { GetVideoAppLinkOptions } from 'libs/shared/interfaces/VideoAppLinkOptions';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\nimport { VideoAppLinkHelper } from 'shared/utils/VideoAppLinkHelper';\n\nimport { SeriesAppLinkHelper } from 'apps/series/SeriesAppLinkHelper';\nimport { getAllTopicsAppLink } from 'apps/subjects/utils/ClassificationAppLinks';\n\nexport interface ClassificationViewQueryParams {\n a?: string[];\n dashboardId?: string;\n preview?: 'true';\n tocId?: string;\n mtv?: boolean;\n}\n\n/**\n * Checks if the classification would have any content with\n * no filters applied\n */\nexport function hasNoContentUnfiltered(classification: Classification): boolean {\n if (!classification)\n return false;\n\n return (\n classification.series?.count === 0 &&\n classification.pinnedVideos?.count === 0 &&\n classification.playlists?.count === 0\n );\n}\n\ninterface HeroVideoWithVideoList {\n heroVideo: Video;\n videoList: Video[];\n}\n\nexport function extractHeroVideo(\n series: SeriesCollection,\n playlists: PlaylistCollection,\n videos: VideoCollection,\n classification: Classification\n): HeroVideoWithVideoList {\n if (!series || !playlists || !videos || !classification)\n return {\n heroVideo: null,\n videoList: videos && videos.data\n };\n\n // If the subject has no series/playlists, and has only 1 video, that video is displayed as the hero.\n if (!series.data.length && !playlists.data.length && videos.data.length === 1) {\n return {\n heroVideo: ArrayHelper.first(videos.data),\n videoList: []\n };\n }\n\n const pinnedVideoIndex = videos.data.findIndex(video => video.id === classification.pinnedVideoMasterId);\n\n if (pinnedVideoIndex === -1)\n return {\n heroVideo: null,\n videoList: videos.data\n };\n\n return {\n heroVideo: videos.data[pinnedVideoIndex],\n videoList: videos.data.filter(vid => vid.id !== classification.pinnedVideoMasterId)\n };\n}\nconst getPhrase = LanguageService.encloseNamespace('subjects.classification');\n\nexport function getBannerActions(\n classification: Classification,\n canFollowSubjects: boolean,\n onFollow: () => void,\n showFollowButtonSpinner: boolean,\n isSmallScreen: boolean\n): ActionOptions[] {\n if (!canFollowSubjects)\n return [];\n\n const isFollowing = !!classification.followers?.data?.length;\n\n return [{\n label: getPhrase(isFollowing ? 'unfollow' : 'follow'),\n onClick: onFollow,\n svgName: isFollowing ? cvSvgLibrary.Check : cvSvgLibrary.Bell,\n className: `btn follow-btn ${isFollowing ? 'btn-outline-dark' : 'btn-dark'}`,\n button: true,\n tooltip: (isFollowing || isSmallScreen) ? undefined : getPhrase('followBtnTooltip'),\n showSpinner: showFollowButtonSpinner\n }];\n}\n\nexport function getClassificationAppLinks(\n classification: Classification,\n params: ClassificationViewQueryParams\n): WidgetAppLinks {\n return {\n audience: () => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION,\n args: [ classification.id, TextHelper.slugify(classification.name) ],\n params\n }),\n \n classification: (_classification: Classification | null) => {\n const appLinkClassification = _classification || classification;\n\n return {\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION,\n args: [ appLinkClassification.id, TextHelper.slugify(appLinkClassification.name) ],\n params: ObjectHelper.omit(params, [ 'preview', 'dashboardId', 'skipPrompt' ])\n };\n },\n\n classificationTopics: () => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_TOPICS,\n args: classification ? [ classification.id, TextHelper.slugify(classification.name) ] : [],\n params: params || {}\n }),\n\n videoType: (video: Video, opts: GetVideoAppLinkOptions) => (\n VideoAppLinkHelper.getAppLink(video, {\n ...opts,\n context: RelatedVideosContext.Widget,\n moviesAndTv: params.mtv\n })\n ),\n\n allTopics: (presentationId: string) => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_ALL,\n params: { presentationId }\n }),\n\n series: (series: Series) => {\n return SeriesAppLinkHelper.getSeriesAppLink(series, {\n classificationId: classification.id,\n mtv: params.mtv ? true : undefined\n });\n },\n\n subText: (video: Video) => SeriesAppLinkHelper.getSeriesAppLink(video.series, {\n classificationId: classification.id,\n mtv: params.mtv ? true : undefined\n }),\n\n playlist: (playlist: Playlist) => ({\n application: AppChannels.PLAYLISTS,\n action: Actions.Playlists.PLAYLIST,\n args: [ playlist.id, TextHelper.slugify(playlist.name) ],\n params: {\n classificationId: classification.id,\n mtv: params.mtv ? true : undefined\n }\n }),\n\n resource: (resource: Resource, videoId: string, canViewResources: boolean) => {\n if (!canViewResources) {\n return {\n application: AppChannels.SIGN_UP,\n action: Actions.SignUp.SIGN_UP\n };\n }\n\n return {\n application: AppChannels.VIDEOS,\n action: Actions.Videos.PREVIEW_PDF,\n args: [resource.id],\n params: {\n videoId\n }\n };\n }\n };\n}\n\ninterface GetClassificationBreadcrumbsOptions {\n queryParams: ClassificationViewQueryParams;\n classification: Classification;\n path: Classification[];\n appLinks: WidgetAppLinks;\n presentation: Presentation;\n availablePresentations: Presentation[];\n}\n\nexport function getClassificationBreadcrumbs(\n options: GetClassificationBreadcrumbsOptions\n): Breadcrumb[] {\n const { queryParams, classification, path, presentation, availablePresentations, appLinks } = options;\n\n if (queryParams.mtv) {\n const breadcrumbs: Breadcrumb[] = [{\n name: getPhrase('moviesAndTv'),\n appLink: {\n application: AppChannels.MOVIES_AND_TV,\n action: Actions.MoviesAndTv.HOME\n }\n }];\n\n path.slice(1, path.length).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 \n const breadcrumbs: Breadcrumb[] = [{\n name: TopicsHelper.getExploreAllTopicsTitle(presentation?.name, availablePresentations?.length),\n appLink: getAllTopicsAppLink(presentation?.id)\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}","// extracted by mini-css-extract-plugin\nexport default {\"followButton\":\"HlRXj\"};","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\nimport { TextHelper } from 'libs/common/react/utils/TextHelper';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { EntityType, LocationContext, ToggleDescriptor, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { CalendarRequests } from 'libs/shared/apps/calendar/flight-request/CalendarRequests';\nimport { ClassificationDashboard } from 'libs/shared/apps/subjects/components/classification-dashboard/ClassificationDashboard';\nimport { PartialClassificationDashboard } from 'libs/shared/apps/subjects/components/classification-dashboard/partial-loading/PartialClassificationDashboard';\nimport { PreviewBanner } from 'libs/shared/apps/subjects/components/preview-banner/PreviewBanner';\nimport { ActionOptions } from 'libs/shared/components/actions/Actions';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { DashboardFeedbackData } from 'libs/shared/components/feedback-form/FeedbackForm';\nimport { VideoActionsContext } from 'libs/shared/context/VideoActionsContext';\nimport { ClassificationStatus } from 'libs/shared/enums/ClassificationStatus';\nimport { MasterType } from 'libs/shared/enums/MasterType';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { PermissionName } from 'libs/shared/enums/PermissionName';\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 { CustomerRequests } from 'libs/shared/flight-requests/CustomerRequests';\nimport { DashboardRequests } from 'libs/shared/flight-requests/DashboardRequests';\nimport { FollowRequests } from 'libs/shared/flight-requests/FollowRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { useCurationStudio } from 'libs/shared/hooks/useCurationStudio';\nimport { useHandleObjectError } from 'libs/shared/hooks/UseHandleObjectError';\nimport { useMediaQuery } from 'libs/shared/hooks/UseMediaQuery';\nimport { usePermissions } from 'libs/shared/hooks/usePermissions';\nimport { useSetPageMetadata } from 'libs/shared/hooks/useSetPageMetadata';\nimport { CalendarEvent, Classification, Config, CurrentUser, Customer, DashboardTargetType, Presentation, PresentationAudience, RegionAlternative, YearGroup } from 'libs/shared/interfaces';\nimport { AudienceHelper } from 'libs/shared/utils/audience-helper/AudienceHelper';\nimport { PageMetadataHelper } from 'libs/shared/utils/PageMetadataHelper';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport { ImageUrls } from 'shared/constants/ImageUrls';\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\nimport { ProductboardRequests } from 'shared/flight-requests/ProductboardRequests';\nimport { useVideoActions, VideoActionsLocation } from 'shared/hooks/use-video-actions/useVideoActions';\nimport { useDeepLinks } from 'shared/hooks/useDeepLinks';\nimport { useLiteFavourites } from 'shared/hooks/useLiteFavourites';\nimport { usePresentation } from 'shared/hooks/usePresentation';\nimport { useFetchCuratedDashboard } from 'shared/utils/DashboardHelper';\nimport { SeoHelper } from 'shared/utils/SeoHelper';\n\nimport { TopicNotFoundError } from 'apps/subjects/errors/TopicNotFoundError';\n\nimport { ClassificationViewQueryParams, getClassificationAppLinks, getClassificationBreadcrumbs } from './ClassificationViewUtils';\n\nimport styles from './curated-classification-view.scss';\n\ninterface CuratedClassificationViewProps {\n id: string;\n queryParams?: ClassificationViewQueryParams;\n}\n\nCuratedClassificationView.defaultProps = {\n queryParams: {}\n};\n\nconst namespace = 'subjects.classification';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport function CuratedClassificationView(props: CuratedClassificationViewProps): React.ReactElement {\n const [ showFollowButtonSpinner, setShowFollowButtonSpinner ] = React.useState<boolean>(false);\n\n const fetchAsync = Flight.useGetFetchAsync();\n const { hasPermissions, hasLocalPermissions } = usePermissions();\n\n const config = Flight.useBasicFetch<Config>(ConfigRequests.config());\n const currentUser = Flight.useBasicFetch<CurrentUser>(UserRequests.currentUser());\n const { openInCurationStudioLabel, isUserCurator, getOpenInCurationStudioLink } = useCurationStudio();\n\n const customer = Flight.useBasicFetch<Customer>(\n hasPermissions(PermissionName.CanSubmitFeedback) &&\n currentUser.data &&\n CustomerRequests.customer(currentUser.data.customerId)\n );\n\n const classification = Flight.useBasicFetch<Classification>(\n ClassificationRequests.classification(props.id, currentUser.data?.id)\n );\n\n const presentation = Flight.useBasicFetch<Presentation>(\n classification.data &&\n ClassificationRequests.presentationById(classification.data.presentationId)\n );\n\n const audiences = Flight.useBasicFetch<PresentationAudience[]>(\n classification.data &&\n AudienceRequests.audiencesByPresentationId(classification.data.presentationId)\n );\n\n const specialEvent = Flight.useBasicFetch<CalendarEvent>(\n classification.data &&\n CalendarRequests.nextTopicSpecialEvent(props.id, classification.data.presentationId)\n );\n\n const {\n activePresentation,\n availablePresentations,\n canAccessPresentation\n } = usePresentation();\n\n const yearGroups = Flight.useBasicFetch<YearGroup[]>(\n currentUser.data?.isAuthenticated && CustomerRequests.yearGroups(currentUser.data.customerId)\n );\n\n const path = Flight.useBasicFetch<Classification[]>(ClassificationRequests.path(props.id));\n\n const {\n dashboard,\n isPreviewing,\n isTeacherOnly\n } = useFetchCuratedDashboard({\n classificationId: props.id,\n queryParams: props.queryParams,\n targetType: DashboardTargetType.Classification\n });\n\n const regionAlternatives = Flight.useBasicFetch<RegionAlternative[]>(\n ClassificationRequests.regionAlternatives(props.id)\n );\n\n useSetPageMetadata(PageMetadataHelper.getClassificationMetadata({\n content: classification.data,\n phraseContext: {\n phraseHandler: getPhrase,\n titlePhrase: 'pageTitle',\n descriptionPhrase: 'pageDescription'\n },\n canonicalLink: SeoHelper.getCanonicalLink({ stripPresentationSlug: true }),\n allowIndexing: SeoHelper.allowIndexing(),\n hrefLang: SeoHelper.getContentHrefLang(regionAlternatives.data, (id: string, name: string) => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION,\n args: [ id, TextHelper.slugify(name) ]\n }))\n }));\n\n useHandleObjectError(classification, {\n notFound: TopicNotFoundError\n });\n useDeepLinks({ id: props.id, app: 'topics' });\n\n const isViewCurrentPresentation = activePresentation?.id === presentation.data?.id;\n \n const isSmallScreen = useMediaQuery(MediaQueryStrings.MDDown);\n const isMobile = useMediaQuery(MediaQueryStrings.SMDown);\n\n const { setFavourite, canFavourite } = useLiteFavourites(LocationContext.ExpandableVideoThumbnail);\n const videoActions = useVideoActions({ location: VideoActionsLocation.VideoItem });\n\n const canFollowSubjects = hasPermissions(PermissionName.FollowSubjects);\n const isComingSoon = (\n classification.data?.status === ClassificationStatus.ComingSoon &&\n !isPreviewing\n );\n\n /**\n * We use the current active audiences to re-fetch content for that specific audience set.\n */\n const activeAudiences = AudienceHelper.getActiveAudiencesFromParams(audiences.data, props.queryParams);\n const activeAudienceIds = activeAudiences?.map(a => a.masterId) ?? [];\n\n /**\n * Following\n */\n function onToggleFollow(location: LocationContext) {\n if (!canFollowSubjects)\n return;\n\n setShowFollowButtonSpinner(true);\n\n const isFollowing = !!classification.data.followers?.data?.length;\n\n const request = isFollowing\n ? FollowRequests.unfollow\n : FollowRequests.follow;\n\n fetchAsync(request([classification.data.id]))\n .then(() => {\n AnalyticsHelper.logUserAction(analyticsData, {\n location,\n actionType: UserAction.Follow,\n workflowPhase: WorkflowPhase.Complete,\n descriptor: isFollowing ? ToggleDescriptor.Off : ToggleDescriptor.On,\n entity: EntityType.Classification\n });\n })\n .finally(() => setShowFollowButtonSpinner(false));\n }\n\n function onSubmitFeedback(feedback: DashboardFeedbackData): Promise<void> {\n const promise = fetchAsync<void>(ProductboardRequests.sendTopicFooterFeedback(\n feedback,\n currentUser.data,\n customer.data,\n presentation.data,\n classification.data,\n dashboard.data,\n hasPermissions(PermissionName.StudentExperience)\n ));\n\n AnalyticsHelper.logUserAction({\n feedbackType: feedback.type,\n content: feedback.content,\n presentationId: presentation.data.id,\n classificationId: classification.data.id,\n dashboardId: dashboard.data.id\n }, {\n actionType: UserAction.Submit,\n location: LocationContext.ClassificationFooter,\n entity: EntityType.Feedback,\n workflowPhase: WorkflowPhase.Complete\n });\n\n return promise;\n }\n\n function getBannerActions(): ActionOptions[] {\n const isFollowing = !!classification.data?.followers?.data?.length;\n\n if (!canFollowSubjects || isComingSoon)\n return [];\n\n const actions: ActionOptions[] = [{\n label: isMobile ? '' : getPhrase(isFollowing ? 'unfollow' : 'follow'),\n onClick: () => onToggleFollow(LocationContext.Banner),\n svgName: isFollowing ? cvSvgLibrary.Check : cvSvgLibrary.Bell,\n className: `btn follow-btn me-2 ${isFollowing ? 'btn-outline-dark' : 'btn-dark'} ${styles.followButton}`,\n button: true,\n tooltip: (isFollowing || isSmallScreen) ? undefined : getPhrase('followBtnTooltip'),\n showSpinner: showFollowButtonSpinner\n }];\n\n if (isUserCurator)\n actions.push({\n label: openInCurationStudioLabel,\n href: getOpenInCurationStudioLink(MasterType.Subject, classification.data?.id, presentation.data?.id),\n openInNewTab: true\n });\n \n return actions;\n }\n\n const appLinks = getClassificationAppLinks(classification.data, props.queryParams);\n\n function getBreadcrumbs(): () => Breadcrumb[] {\n if (!canAccessPresentation(presentation.data?.id))\n return;\n\n return () => getClassificationBreadcrumbs({\n appLinks: appLinks,\n availablePresentations,\n classification: classification.data,\n path: path.data,\n presentation: presentation.data,\n queryParams: props.queryParams\n });\n }\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 const dataLoaded = !!config.data\n && dashboard.hasCompleted\n && !!classification.data\n && !!presentation.data\n && !!path.data\n && !!availablePresentations\n && !!audiences.data\n && specialEvent.hasCompleted;\n\n if (!dataLoaded)\n return <PartialClassificationDashboard />;\n\n return (\n <VideoActionsContext.Provider value={videoActions}>\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={hasPermissions}\n hasLocalPermissions={hasLocalPermissions}\n presentation={presentation.data}\n onToggleFollow={onToggleFollow}\n getBannerActions={getBannerActions}\n audiences={props.queryParams.mtv ? null : audiences.data}\n activeAudiences={activeAudiences}\n analyticsData={analyticsData}\n imageCdnUrl={config.data.imageCdnUrl}\n resourceThumbnailFallbackImageUrl={ImageUrls.Fallbacks.RESOURCE_THUMBNAIL}\n emptyImageUrl={isTeacherOnly ? ImageUrls.EmptyStates.Topics.TEACHER_ONLY : ImageUrls.EmptyStates.Topics.TOPIC}\n isComingSoon={isComingSoon}\n appLinks={appLinks}\n isPreviewing={isPreviewing}\n setFavourite={setFavourite}\n canFavourite={canFavourite}\n isViewCurrentPresentation={isViewCurrentPresentation}\n canFollowSubjects={canFollowSubjects}\n onSubmitFeedback={\n hasPermissions(PermissionName.CanSubmitFeedback) &&\n onSubmitFeedback\n }\n tableOfContentsId={props.queryParams.tocId}\n yearGroups={yearGroups.data}\n lazyLoad={!SeoHelper.isBot()}\n moviesAndTv={props.queryParams.mtv}\n isTeacherOnly={isTeacherOnly}\n specialEvent={specialEvent.data}\n isBot={SeoHelper.isBot()}\n // just... one... more.. prop....\n />\n </div>\n </VideoActionsContext.Provider>\n );\n}\n","import { HttpVerbs } from 'libs/common/backbone/enums/HttpVerbs';\nimport { Flight } from 'libs/common/react/index';\n\nimport { DashboardFeedbackData } from 'libs/shared/components/feedback-form/FeedbackForm';\nimport { InstanceRegion } from 'libs/shared/enums/InstanceRegion';\nimport { UserRole } from 'libs/shared/enums/UserRole';\nimport { Classification, CuratedDashboard, CurrentUser, Customer, Presentation } from 'libs/shared/interfaces';\n\nexport const ProductboardRequests = {\n sendDiscoverFooterFeedback(\n feedback: DashboardFeedbackData,\n currentUser: CurrentUser,\n customer: Customer,\n presentation: Presentation,\n dashboard: CuratedDashboard,\n hasStudentExperience: boolean\n ): Flight.Request {\n const userContent = feedback.content.split('\\n').join('<br />');\n\n const content = `\n <b>Type:</b> ${feedback.type === 'positive' ? 'Positive' : 'Negative'}\n <br />\n <b>Location:</b> Discover Footer\n <br />\n <b>Presentation:</b> ${presentation.description} (ID: ${presentation.id})\n <br />\n <b>Dashboard:</b> ${dashboard.name} (ID: ${dashboard.id})\n <br />\n ${getUserInfo(currentUser, customer, hasStudentExperience)}\n <br />\n <b>Feedback:</b>\n <br />\n ${userContent}\n `;\n\n const extraTags = [ 'discover', hasStudentExperience ? 'student' : 'staff' ];\n\n return getRequest('Discover Footer Feedback', content, currentUser, extraTags);\n },\n\n sendTopicFooterFeedback(\n feedback: DashboardFeedbackData,\n currentUser: CurrentUser,\n customer: Customer,\n presentation: Presentation,\n classification: Classification,\n dashboard: CuratedDashboard,\n hasStudentExperience: boolean\n ): Flight.Request {\n const userContent = feedback.content.split('\\n').join('<br />');\n\n const content = `\n <b>Type:</b> ${feedback.type === 'positive' ? 'Positive' : 'Negative'}\n <br />\n <b>Location:</b> Topic Footer\n <br />\n <b>Presentation:</b> ${presentation.description} (ID: ${presentation.id})\n <br />\n <b>Classification:</b> ${classification.name} (ID: ${classification.id})\n <br />\n <b>Dashboard:</b> ${dashboard.name} (ID: ${dashboard.id})\n <br />\n ${getUserInfo(currentUser, customer, hasStudentExperience)}\n <br />\n <b>Feedback:</b>\n <br />\n ${userContent}\n `;\n\n const extraTags = [ 'topics', hasStudentExperience ? 'student' : 'staff' ];\n\n return getRequest('Topic Footer Feedback', content, currentUser, extraTags);\n }\n};\n\nfunction getRequest(\n title: string,\n content: string,\n currentUser: CurrentUser,\n extraTags: string[]\n): Flight.Request {\n const tags = [\n 'new product',\n 'in product feedback',\n ...extraTags\n ];\n\n if (currentUser.role === UserRole.Admin)\n tags.push('administrator');\n\n const regionTag = mapInstanceRegionToTag(currentUser.instanceRegion);\n\n if (regionTag)\n tags.push(regionTag);\n\n return {\n url: '/api/productboard/notes',\n key: 'productboard:feedback',\n data: {\n title,\n content,\n user: {\n email: currentUser.emailVerified ? currentUser.email : ''\n },\n tags\n },\n type: HttpVerbs.POST\n };\n}\n\nfunction mapInstanceRegionToTag(instanceRegion: InstanceRegion): string {\n switch (instanceRegion) {\n case InstanceRegion.AU:\n return 'au';\n case InstanceRegion.NZ:\n return 'nz';\n case InstanceRegion.UK:\n return 'uk';\n case InstanceRegion.US:\n return 'us';\n }\n}\n\nfunction getUserInfo(currentUser: CurrentUser, customer: Customer, hasStudentExperience: boolean): string {\n return `\n <b>User:</b>\n <br />\n <li>ID: ${currentUser.id}</li>\n <li>Username: ${currentUser.username}</li>\n <li>Email: ${currentUser.email}</li>\n <li>User Type / Role: ${getRole(currentUser, hasStudentExperience)}</li>\n <li>Customer ID: ${currentUser.customerId}</li>\n <li>CVC ID: ${customer.crmId}</li>\n <li>Customer Name: ${customer.name}</li>\n <li>Instance Region: ${currentUser.instanceRegion}</li>\n <li>Content Region: ${currentUser.contentRegion}</li>\n `;\n}\n\nfunction getRole(currentUser: CurrentUser, hasStudentExperience: boolean): string {\n if (hasStudentExperience)\n return 'Learner';\n\n return currentUser.role === UserRole.Admin ? 'Admin' : 'Staff';\n}"],"names":["CalendarRequests","calendarEvents","from","to","presentationId","url","publicUrl","key","nextTopicSpecialEvent","classificationId","params","limit","Date","objectType","formatData","events","AudienceItem","props","audience","highlight","setAudience","isDisabled","extraClasses","colourClass","getColourClass","className","onClick","FunctionHelper","role","name","split","map","s","charAt","toUpperCase","substring","join","defaultProps","DashboardStatusConfig","Dashboard","svgName","svgColorClassName","actionName","statusName","getClassName","status","darkMode","wrapperClassName","DashboardStatusBadge","SvgContainer","getPhrase","LanguageService","PreviewBanner","EmojiText","emoji","type","PortalHelper","renderInPortalIfExists","component","portalContainer","createPortal","namespace","BackButton","textShadow","backToName","appLink","color","backPhrase","colorClass","textShadowClass","AppLink","size","S","RATIO","width","height","getSizeClass","heading","length","BannerHeader","banner","imageCdnUrl","actions","sortComponent","blockColourClass","specialEvent","portalContainerContext","BannerPortalContext","imageWidth","useBreakpoints","xxl","specialEventIsToday","showComingSoon","today","DateHelper","endDate","startDate","imageOptions","ratio","resizeType","ImageHelper","fallbackBaseUrl","fallbackCategoryName","containerProps","bannerClassName","style","backgroundImage","DetailsComponent","detailsComponent","backButtonAppLink","backButtonText","backButtonClasses","alignLogoLeft","logo","GenericCalendarDate","body","text","month","theme","calendarTheme","Text","phrase","ComingSoonTag","LazyImage","src","Actions","actionsDropdownClassName","container","prevProps","nextProps","PartialBannerHeader","BreadcrumbItem","breadcrumb","active","withBackIcon","Breadcrumbs","breadcrumbs","isMobile","b","idx","PartialBreadcrumbs","numItems","dangerouslySetInnerHTML","__html","defaultErrors","notFound","forbidden","rating","yearLevel","region","privacy","badRequest","handleHttpError","info","customErrorMap","ignoreMap","statusCode","errorMap","endpoints","ids","id","FollowRequests","follow","success","error","data","invalidationKeys","unfollow","generateCacheKey","flightObjs","obj","useHandleObjectError","_flightObjs","customErrors","ignoreErrors","Array","isArray","useEffect","forEach","usePrevious","value","ref","current","useTableOfContentsScroll","elements","activeId","hasDoneInitialScroll","setHasDoneInitialScroll","previousId","currentId","target","find","rec","getBoundingClientRect","window","scrollBy","top","behavior","getClassificationAppLink","classification","application","action","args","getAllTopicsAppLink","CuratedClassificationEmptyState","isArchived","dashboard","EmptyState","imageUrl","altText","isReadonly","Tooltip","title","spanHack","addWidgetApplink","icon","disabled","TableOfContents","widgets","w","widget","currentAppLink","tocId","appLinkOptions","replace","clickable","ScrollHelper","setControlledId","analyticsData","analyticsOptions","actionType","entity","location","TeacherOnlyEmptyState","ctaAppLink","timer","useTableOfContentsActiveHeading","setActiveId","headingElements","controlledId","scrollPositionRef","observer","IntersectionObserver","headings","setTimeout","isIntersecting","scrollY","isScrollingUp","curIndex","findIndex","h","prevHeading","rootMargin","element","observe","clearTimeout","disconnect","AudienceFilter","audiences","activeAudiences","setActiveAudiences","SharedViewModelKeys","undefined","storage","onToggleAudience","isSelected","otherParams","activeAudienceNames","a","filter","ObjectHelper","Object","assign","disablePersist","masterId","aa","keys","DivButton","PARTIAL_AUDIENCES","PartialLoadingHelper","PartialAudienceFilter","ClassificationDashboardAudiences","isComingSoon","isEmpty","AudienceHelper","isHeadingWidget","widgetId","WidgetTypeId","templateId","WidgetTemplate","ClassificationDashboard","isSystemGeneratedDashboard","systemGeneratedVideoWidget","systemGeneratedVideoContent","DashboardRequests","videoList","content","videoListWidgetId","useGetTopicsWidgets","isSmallScreen","headingRef","Set","initialEmptyWidgets","reduce","acc","emptyWidgets","setEmptyWidgets","hash","slice","tableOfContentActiveId","setTableOfContentActiveId","getWidgetContentRequest","widgetTypeId","template","tableOfContentsId","showEmptyState","isTeacherOnly","isPreviewing","values","every","state","getBreadcrumbs","onSetIsEmpty","newEmptyState","index","currentWidget","isHeadingEmpty","subWidgetIndex","headingSubWidget","hideWidget","widgetsInTableOfContents","metadata","showInTableOfContents","shouldShowTableOfContents","NotFoundError","moviesAndTv","getBannerActions","background","border","appLinks","isViewCurrentPresentation","WidgetContainerView","headingElementRef","description","getContentRequest","setIsEmpty","setFavourite","canFavourite","yearGroups","presentation","isScrollToTargetWidget","scrollToWidgetId","onSubmitFeedback","isBot","hasTableOfContents","lazyLoad","dashboardTarget","widgetIndex","hasPermissions","hasLocalPermissions","companyLogoFallbackUrl","subTextType","contentType","resourceThumbnailFallbackImageUrl","preferences","WidgetHeader","VideoList","videos","getVideoAppLink","v","opts","videoType","contextId","getSubTextAppLink","subText","presentationAudiences","getPreviewQuestionsAppLink","previewQuestions","emptyImageUrl","widgetWizard","allTopics","PartialClassificationDashboard","TopicNotFoundError","ErrorPageError","CuratedClassificationView","queryParams","showFollowButtonSpinner","setShowFollowButtonSpinner","fetchAsync","usePermissions","config","ConfigRequests","currentUser","UserRequests","useCurationStudio","openInCurationStudioLabel","isUserCurator","getOpenInCurationStudioLink","customer","PermissionName","CustomerRequests","customerId","ClassificationRequests","AudienceRequests","usePresentation","activePresentation","availablePresentations","canAccessPresentation","isAuthenticated","path","targetType","regionAlternatives","useSetPageMetadata","PageMetadataHelper","phraseContext","phraseHandler","titlePhrase","descriptionPhrase","canonicalLink","SeoHelper","stripPresentationSlug","allowIndexing","hrefLang","TextHelper","useDeepLinks","app","useLiteFavourites","u","videoActions","useVideoActions","canFollowSubjects","ClassificationStatus","activeAudienceIds","onToggleFollow","isFollowing","followers","request","then","AnalyticsHelper","workflowPhase","descriptor","_classification","appLinkClassification","classificationTopics","video","VideoAppLinkHelper","context","RelatedVideosContext","mtv","series","SeriesAppLinkHelper","playlist","resource","videoId","canViewResources","presentationName","currentClassificationId","currentClassificationName","followingCurrentClassification","hasCompleted","VideoActionsContext","options","item","push","TopicsHelper","getClassificationBreadcrumbs","label","button","tooltip","showSpinner","href","MasterType","openInNewTab","ImageUrls","feedback","promise","ProductboardRequests","feedbackType","dashboardId","sendDiscoverFooterFeedback","hasStudentExperience","userContent","getRequest","getUserInfo","sendTopicFooterFeedback","extraTags","tags","regionTag","instanceRegion","mapInstanceRegionToTag","user","email","emailVerified","username","getRole","crmId","contentRegion"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"scripts/2875-aefd69a61f-lite.chunk.js","mappings":"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","sources":["file:///app/packages/libs/shared/src/apps/calendar/flight-request/CalendarRequests.ts","file:///app/packages/libs/shared/src/apps/subjects/components/audience-item/audience-item.scss","file:///app/packages/libs/shared/src/apps/subjects/components/audience-item/AudienceItem.tsx","file:///app/packages/libs/shared/src/apps/subjects/constants/DashboardStatusConfig.ts","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/dashboard-status-badge/dashboard-status-badge.scss","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/dashboard-status-badge/DashboardStatusBadge.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/preview-banner/preview-banner.scss","file:///app/packages/libs/shared/src/apps/subjects/components/preview-banner/PreviewBanner.tsx","file:///app/packages/libs/common/src/react/utils/PortalHelper.ts","file:///app/packages/libs/shared/src/components/back-button/BackButton.tsx","file:///app/packages/libs/shared/src/components/banner-header/banner-header.scss","file:///app/packages/libs/shared/src/components/banner-header/BannerHeader.tsx","file:///app/packages/libs/shared/src/components/breadcrumbs/Breadcrumbs.tsx","file:///app/packages/libs/shared/src/errors/handlers/HttpErrorHandlers.ts","file:///app/packages/libs/shared/src/flight-requests/FollowRequests.ts","file:///app/packages/libs/shared/src/hooks/UseHandleObjectError.ts","file:///app/packages/libs/shared/src/hooks/usePrevious.ts","file:///app/packages/libs/shared/src/hooks/useTableOfContentsScroll.tsx","file:///app/packages/projects/lite/src/apps/subjects/utils/ClassificationAppLinks.ts","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/empty-state/CuratedClassificationEmptyState.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/table-of-contents/table-of-contents.scss","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/table-of-contents/TableOfContents.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/teacher-only/TeacherOnlyEmptyState.tsx","file:///app/packages/libs/shared/src/hooks/useTableOfContentsActiveHeading.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/audience-filter/AudienceFilter.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/audiences/ClassificationDashboardAudiences.tsx","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/ClassificationDashboard.tsx","file:///app/packages/libs/shared/src/apps/subjects/hooks/useGetTopicsWidgets.ts","file:///app/packages/libs/shared/src/apps/subjects/components/classification-dashboard/partial-loading/PartialClassificationDashboard.tsx","file:///app/packages/projects/lite/src/apps/subjects/errors/TopicNotFoundError.ts","file:///app/packages/projects/lite/src/apps/subjects/views/classification/ClassificationViewUtils.ts","file:///app/packages/projects/lite/src/apps/subjects/views/classification/curated-classification-view.scss","file:///app/packages/projects/lite/src/apps/subjects/views/classification/CuratedClassificationView.tsx","file:///app/packages/projects/lite/src/shared/flight-requests/ProductboardRequests.ts"],"sourcesContent":["import { UrlHelper } from 'libs/common/backbone/utils/UrlHelper';\nimport { Flight } from 'libs/common/flight';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\nimport { DateHelper } from 'libs/common/react/utils/DateHelper';\n\nimport { CalendarEvent, CalendarEventContentType } from 'libs/shared/interfaces';\n\nexport const CalendarRequests = {\n calendarEvents(\n from: string,\n to: string,\n presentationId: string\n ): Flight.PublicRequest {\n return {\n url: UrlHelper.urlBuilder('{gateway}/v1/discover/special-events/content', { from, to, presentationId }),\n publicUrl: UrlHelper.urlBuilder(`/api/discover/special-events/content`, { from, to, presentationId }),\n key: `presentation:${presentationId}:events:from:${from}:to${to}`\n };\n },\n\n nextTopicSpecialEvent(\n classificationId: string,\n presentationId: string\n ): Flight.PublicRequest {\n const params = {\n presentationId,\n limit: 1,\n from: DateHelper.format(new Date(), 'YYYY-MM-DD'),\n objectType: CalendarEventContentType.Classification\n };\n\n return {\n url: UrlHelper.urlBuilder(`{gateway}/v1/discover/special-events/object/${classificationId}/next-events`, params),\n publicUrl: UrlHelper.urlBuilder(`/api/discover/special-events/object/${classificationId}/next-events`, params),\n key: `presentation:${presentationId}:events:classification:${classificationId}`,\n formatData: (events: CalendarEvent[]) => ArrayHelper.first(events)\n };\n }\n};\n","// extracted by mini-css-extract-plugin\nexport default {\"disabled\":\"pERi4\",\"disabledHighlighted\":\"AxyWm\"};","import * as React from 'react';\n\nimport { FunctionHelper } from 'libs/common/backbone/utils/FunctionHelper';\n\nimport { PresentationAudience } from 'libs/shared/interfaces';\n\nimport styles from './audience-item.scss';\n\nfunction lowerCaseToTitleCase(str: string): string {\n return str.split(' ').map((s: string) => s.charAt(0).toUpperCase() + s.substring(1)).join(' ');\n}\n\nfunction getColourClass(highlight: boolean, isDisabled: boolean): string {\n if (highlight) return isDisabled ? `${styles.disabledHighlighted} text-light` : 'bg-info text-light';\n if (isDisabled) return `${styles.disabled} text-secondary`;\n return 'bg-light';\n}\n\ninterface AudienceItemProps {\n audience: PresentationAudience;\n highlight: boolean;\n setAudience?: (audience: PresentationAudience, highlight: boolean) => void;\n isDisabled?: boolean;\n extraClasses?: string;\n}\n\nAudienceItem.defaultProps = {\n extraClasses: ''\n};\n\nexport function AudienceItem(props: AudienceItemProps): React.ReactElement {\n const { audience, highlight, setAudience, isDisabled, extraClasses } = props;\n\n const colourClass = getColourClass(highlight, isDisabled);\n const cursorClass = isDisabled ? 'cursor-default' : 'cursor-pointer';\n const className = `rounded-pill d-inline-block me-1 user-select-none ${cursorClass} ${colourClass} ${extraClasses}`;\n\n const onClick = () => {\n if (isDisabled || !FunctionHelper.isFunction(setAudience))\n return;\n\n setAudience(audience, !highlight);\n };\n\n return (\n <span\n className={className}\n onClick={onClick}\n role='checkbox'\n aria-checked={highlight}\n >\n {lowerCaseToTitleCase(audience.name)}\n </span>\n );\n}","import { localSvgs } from 'libs/shared/images/svg';\nimport { DashboardStatus } from 'libs/shared/interfaces/models/Dashboard';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\ninterface DashboardStatusConfigType {\n statusName: string;\n actionName: string;\n svgName: localSvgs;\n svgColorClassName: string;\n}\n\nexport const DashboardStatusConfig: Record<DashboardStatus, DashboardStatusConfigType> = {\n [DashboardStatus.Archived]: {\n svgName: cvSvgLibrary.Archive,\n svgColorClassName: 'text-secondary',\n actionName: 'Archive',\n statusName: 'Archived'\n },\n [DashboardStatus.Draft]: {\n svgName: cvSvgLibrary.Edit,\n svgColorClassName: '',\n actionName: 'Draft',\n statusName: 'Draft'\n },\n [DashboardStatus.Published]: {\n svgName: cvSvgLibrary.VisibleOn,\n svgColorClassName: 'text-success',\n actionName: 'Publish',\n statusName: 'Published'\n }\n};","// extracted by mini-css-extract-plugin\nexport default {\"badge\":\"ciO47\",\"draftLight\":\"A6Yi7\",\"draftDark\":\"fkXBX\",\"published\":\"Ovzwy\",\"archived\":\"r_dco\"};","import React from 'react';\n\nimport { DashboardStatusConfig } from 'libs/shared/apps/subjects/constants/DashboardStatusConfig';\nimport { SvgContainer } from 'libs/shared/components/svg-container/SvgContainer';\nimport { DashboardStatus } from 'libs/shared/interfaces';\n\nimport styles from './dashboard-status-badge.scss';\n\nfunction getClassName(props: DashboardStatusBadgeProps): string {\n let className = `rounded-pill d-flex align-items-center ps-2 py-1 fw-semibold ms-2 ${styles.badge}`;\n\n switch (props.status) {\n case DashboardStatus.Published:\n className += ` ${styles.published}`;\n break;\n case DashboardStatus.Archived:\n className += ` ${styles.archived}`;\n break;\n case DashboardStatus.Draft:\n className += ` ${props.darkMode ? styles.draftDark : styles.draftLight}`;\n break;\n }\n\n if (props.wrapperClassName)\n className += ` ${props.wrapperClassName}`;\n\n return className;\n}\n\ninterface DashboardStatusBadgeProps {\n status: DashboardStatus;\n darkMode?: boolean;\n wrapperClassName?: string;\n}\n\nexport function DashboardStatusBadge(props: DashboardStatusBadgeProps): JSX.Element {\n const { statusName, svgName } = DashboardStatusConfig[props.status];\n\n return (\n <div className={getClassName(props)}>\n <SvgContainer svgName={svgName} />\n <div>{statusName}</div>\n </div>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"stickyWrapper\":\"zhw6K\",\"badgeWrapper\":\"NOvn1\",\"badge\":\"pxQSR\"};","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { DashboardStatusBadge } from 'libs/shared/apps/subjects/components/classification-dashboard/dashboard-status-badge/DashboardStatusBadge';\nimport { EmojiText } from 'libs/shared/components/emoji-text/EmojiText';\nimport { DashboardStatus } from 'libs/shared/interfaces';\n\nimport styles from './preview-banner.scss';\n\nconst namespace = 'shared.classificationPreviewBanner';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface PreviewBannerProps {\n status: DashboardStatus;\n type: 'company' | 'topic';\n}\n\nexport function PreviewBanner(props: PreviewBannerProps): JSX.Element {\n return (\n <div className={`${styles.stickyWrapper} py-2 d-flex justify-content-space-between bg-dark text-white mx-2 rounded`}>\n <div className={`position-absolute d-flex ${styles.badgeWrapper}`}>\n <DashboardStatusBadge status={props.status} wrapperClassName={`${styles.badge}`} darkMode />\n </div>\n <div className='flex-grow-1'>\n <h1 className='text-center my-3 h5'>\n <EmojiText emoji='👀' />\n {getPhrase(props.type === 'topic' ? 'topicTitle' : 'companyTitle')}\n </h1>\n </div>\n </div>\n );\n}\n","import React from 'react';\nimport { createPortal } from 'react-dom';\n\nexport const PortalHelper = {\n renderInPortalIfExists(component: React.ReactElement, portalContainer: Element | null): React.ReactElement {\n if (portalContainer)\n return createPortal(component, portalContainer);\n\n return component;\n }\n};","import * as React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Core } from 'libs/common/core';\n\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { SvgContainer, SvgContainerSize } from 'libs/shared/components/svg-container/SvgContainer';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nconst namespace = 'shared.backButton';\n\ninterface BackButtonProps {\n appLink: Core.AppLink;\n backToName?: string;\n color?: 'black' | 'white';\n extraClasses?: string;\n /**\n * Whether or not the button text has a text shadow. Defaults to true\n */\n textShadow?: boolean;\n}\n\nBackButton.defaultProps = {\n color: 'black',\n extraClasses: ''\n};\n\nexport function BackButton(props: BackButtonProps): React.ReactElement {\n const { backToName, appLink, color, extraClasses, textShadow } = {\n textShadow: true,\n ...props\n };\n\n const backPhrase = backToName\n ? LanguageService.getPhrase(namespace, 'backTo', { backToName })\n : LanguageService.getPhrase(namespace, 'back');\n\n const colorClass = color === 'black' ? '' : 'text-white';\n const textShadowClass = textShadow ? 'text-shadow' : '';\n\n return (\n <AppLink\n appLink={appLink}\n className={`d-inline-flex align-items-center h5 mb-0 ${extraClasses} ${colorClass} ${textShadowClass}`}\n >\n <SvgContainer svgName={cvSvgLibrary.ChevronLeft} size={SvgContainerSize.Medium} />\n <span className='ms-1'>{backPhrase}</span>\n </AppLink>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"bannerContent\":\"sSCTB\",\"actionsContainer\":\"Z5WI2\",\"bannerContentWithLogo\":\"rgs7Q\",\"container\":\"M51HJ\",\"logoContainer\":\"vkeJk\",\"logoContainerLeft\":\"M3U9B\",\"logoHeading\":\"EtRwC\",\"specialEventContainer\":\"rOxDc\",\"headingLarge\":\"_8pnV\",\"heading\":\"JXVBH\"};","import * as React from 'react';\n\nimport { Core } from 'libs/common/core';\nimport { DateHelper } from 'libs/common/react/utils/DateHelper';\nimport { PortalHelper } from 'libs/common/react/utils/PortalHelper';\n\nimport { ComingSoonTag } from 'libs/shared/apps/calendar/components/coming-soon-tag/ComingSoonTag';\nimport { GenericCalendarDate } from 'libs/shared/apps/calendar/components/generic-calendar-date/GenericCalendarDate';\nimport { CalendarTheme } from 'libs/shared/apps/calendar/interfaces/CalendarTheme';\nimport { ActionOptions, Actions } from 'libs/shared/components/actions/Actions';\nimport { BackButton } from 'libs/shared/components/back-button/BackButton';\nimport { LazyImage } from 'libs/shared/components/lazy-image/LazyImage';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { ImageMinDimensions } from 'libs/shared/constants/ImageSizes';\nimport { BannerPortalContext } from 'libs/shared/context/BannerPortalContext';\nimport { ImageSize, ImageType, ResizeType } from 'libs/shared/enums/Images';\nimport { useBreakpoints } from 'libs/shared/hooks/useBreakpoints';\nimport { Banner, CalendarEvent, Logo } from 'libs/shared/interfaces';\nimport { ImageHelper, ImageOptions } from 'libs/shared/utils/ImageHelper';\n\nimport styles from './banner-header.scss';\n\nconst RATIO = `${ImageMinDimensions[ImageType.Banners].width}:${ImageMinDimensions[ImageType.Banners].height}`;\nconst DEFAULT_WIDTH = 1200; // This is ImageSize.Large for a Banner.\nconst LARGE_SCREEN_WIDTH = 1920;\n\nfunction useGetImageWidth(): number {\n const breakpoints = useBreakpoints();\n\n if (breakpoints.xxl)\n return LARGE_SCREEN_WIDTH;\n\n return DEFAULT_WIDTH;\n}\n\nfunction getSizeClass(heading: string): string {\n if (heading.length < 160)\n return 'h1';\n\n return styles.headingLarge;\n}\n\ninterface BannerHeaderProps {\n heading: string;\n banner?: Banner;\n bannerClassName?: string;\n imageCdnUrl?: string;\n logo?: Logo;\n actions?: ActionOptions[];\n specialEvent?: CalendarEvent;\n backButtonAppLink?: Core.AppLink;\n backButtonText?: string;\n backButtonClasses?: string;\n sortComponent?: JSX.Element;\n blockColourClass?: string;\n actionsDropdownClassName?: string;\n detailsComponent?: () => React.ReactElement;\n imageOptions?: ImageOptions;\n showComingSoon?: boolean;\n alignLogoLeft?: boolean;\n calendarTheme?: CalendarTheme;\n}\n\nconst namespace = 'shared.bannerHeader';\n\nexport const BannerHeader = React.memo(function(props: React.PropsWithChildren<BannerHeaderProps>): React.ReactElement {\n const { heading, banner, imageCdnUrl, actions, sortComponent, blockColourClass, specialEvent } = props;\n\n const portalContainerContext = React.useContext(BannerPortalContext);\n\n const imageWidth = useGetImageWidth();\n\n const specialEventIsToday = React.useMemo(() => {\n if (!specialEvent || props.showComingSoon)\n return false;\n\n const today = DateHelper.format(new Date(), 'YYYY-MM-DD');\n\n if (!specialEvent.endDate)\n return specialEvent.startDate === today;\n\n return specialEvent.startDate <= today && specialEvent.endDate >= today;\n }, [specialEvent]);\n\n const imageOptions = props.imageOptions || {\n width: imageWidth,\n ratio: RATIO,\n resizeType: ResizeType.Cover\n };\n\n const url = !!banner && !!imageCdnUrl && ImageHelper.createBannerUrl(banner, {\n fallbackBaseUrl: imageCdnUrl,\n fallbackCategoryName: heading,\n type: ImageType.Banners\n }, imageOptions);\n\n const containerProps: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> = {\n className: `banner banner-header ${props.bannerClassName}`,\n style: url ? { backgroundImage: `url('${url}')` } : {}\n };\n\n if (!banner && blockColourClass) {\n delete containerProps.style;\n containerProps.className += ` ${blockColourClass}`;\n }\n\n const DetailsComponent = props.detailsComponent;\n\n return PortalHelper.renderInPortalIfExists(\n // \"banner\" is used in playlists in Online. banner-header is used by all other projects\n <header {...containerProps}>\n <div className={`container ${styles.container} position-relative inner-banner`}>\n {props.backButtonAppLink && (\n <div className='pt-3'>\n <BackButton\n appLink={props.backButtonAppLink}\n backToName={props.backButtonText}\n extraClasses={props.backButtonClasses}\n color='white'\n />\n </div>\n )}\n \n <div className={`${props.alignLogoLeft ? 'position-absolute top-50 start-0 translate-middle-y w-100 ps-4' : `${styles.bannerContent} ${props.logo?.url ? styles.bannerContentWithLogo : ''}`}`}>\n {!!specialEvent && (\n <div className={`position-relative ${styles.specialEventContainer}`}>\n <GenericCalendarDate\n body={{\n type: specialEvent.endDate ? 'range' : 'day',\n text: specialEvent.endDate\n ? `${DateHelper.format(specialEvent.startDate, 'DD')}-${DateHelper.format(specialEvent.endDate, 'DD')}`\n : DateHelper.format(specialEvent.startDate, 'DD')\n }}\n month={DateHelper.format(specialEvent.startDate, 'MMMM')}\n theme={props.calendarTheme}\n />\n </div>\n )}\n <div>\n {specialEventIsToday && (\n <div className='rounded-pill py-1 px-2 my-1 me-1 fw-semibold bg-light-blue lh-1 d-inline-block'>\n <Text namespace={namespace} phrase='onToday' />\n </div>\n )}\n {props.showComingSoon && (\n <ComingSoonTag className='pe-2 fw-semibold mb-1 rounded-pill justify-content-start text-nowrap' />\n )}\n <div className='d-flex align-items-center'>\n {props.alignLogoLeft &&\n <div className={`${styles.logoContainerLeft} d-none d-md-block partial-loading-background rounded-circle overflow-hidden me-3`}>\n {props.logo?.url &&\n <LazyImage src={ImageHelper.createUrl(props.logo?.url, { size: ImageSize.Small })} />}\n </div>\n }\n <h1 className={`text-white text-shadow pe-3 ${styles.heading} ${getSizeClass(heading)} ${props.alignLogoLeft ? 'w-50' : ''}`}>\n {heading}\n {DetailsComponent && <DetailsComponent />}\n </h1>\n </div>\n </div>\n {!!actions && (\n <div className={styles.actionsContainer}>\n <Actions\n actions={actions}\n sortComponent={sortComponent}\n actionsDropdownClassName={props.actionsDropdownClassName}\n />\n </div>\n )}\n </div>\n {!props.alignLogoLeft && !!props.logo?.url &&\n <div className={styles.logoContainer}>\n <img\n src={ImageHelper.createUrl(props.logo.url, { size: ImageSize.Small })}\n className='rounded-circle'\n />\n </div>\n }\n </div>\n </header>,\n portalContainerContext?.container\n );\n}, (prevProps, nextProps): boolean => (\n prevProps.actions === nextProps.actions\n && prevProps.heading === nextProps.heading\n && prevProps.logo?.url === nextProps.logo?.url\n));\n\nexport function PartialBannerHeader(): JSX.Element {\n const portalContainerContext = React.useContext(BannerPortalContext);\n\n return PortalHelper.renderInPortalIfExists(\n <div className={`partial-banner partial-loading-background ${styles.banner}`} />,\n portalContainerContext?.container\n );\n}","import * as React from 'react';\n\nimport { Core } from 'libs/common/core';\n\nimport { AppLink } from 'libs/shared/components/app-link/AppLink';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { useMediaQuery } from 'libs/shared/hooks/UseMediaQuery';\nimport { PartialLoadingHelper } from 'libs/shared/utils/PartialLoadingHelper';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport { SvgContainer, SvgContainerSize } from '../svg-container/SvgContainer';\n\nexport interface Breadcrumb {\n name: string;\n appLink?: Core.AppLink;\n active?: boolean;\n}\n\ninterface BreadcrumbItemProps {\n breadcrumb: Breadcrumb;\n withBackIcon?: boolean;\n}\n\nexport const BreadcrumbItem = ({ breadcrumb: { name, appLink, active }, withBackIcon }: BreadcrumbItemProps) => (\n <li className={`breadcrumb-item${active ? ' active' : ''}`}>\n {active\n ? <strong>{name}</strong>\n : <AppLink appLink={appLink}>\n {withBackIcon && <SvgContainer svgName={cvSvgLibrary.ChevronLeft} size={SvgContainerSize.Small} />}\n <span className={withBackIcon ? 'ms-2' : ''}>{name}</span>\n </AppLink>\n }\n </li>\n);\n\ninterface BreadcrumbsProps {\n breadcrumbs: Breadcrumb[];\n}\n\nexport const Breadcrumbs = ({ breadcrumbs }: BreadcrumbsProps) => {\n const isMobile = useMediaQuery(MediaQueryStrings.XS);\n\n const length = breadcrumbs?.length;\n\n if (!length || (isMobile && length < 2))\n return <></>;\n\n if (isMobile)\n return (\n <nav aria-label='breadcrumb'>\n <ol className='breadcrumb m-0 p-0'>\n <BreadcrumbItem breadcrumb={breadcrumbs[length - 2]} withBackIcon />\n </ol>\n </nav>\n );\n\n return (\n <nav aria-label='breadcrumb'>\n <ol className='breadcrumb m-0 p-0'>\n {breadcrumbs.map((b, idx) => <BreadcrumbItem key={idx} breadcrumb={b} />)}\n </ol>\n </nav>\n );\n};\n\nexport const PartialBreadcrumbs = React.memo(function({ numItems = 3 }: { numItems?: number; }) {\n const isMobile = useMediaQuery(MediaQueryStrings.XS);\n\n if (isMobile) {\n return (\n <div className='partial-loading-background' style={{ height: '1.3125rem', width: '6rem' }} />\n );\n }\n\n return (\n <nav aria-label='breadcrumb'>\n <ol className='breadcrumb m-0 p-0'>\n {PartialLoadingHelper.getPartialLoadingItems({ numItems }).map(({ width }, idx) => (\n <li key={idx} className='breadcrumb-item'>\n <span className='d-inline-block partial-loading-background' style={{ width }} dangerouslySetInnerHTML={{ __html: ' ' }} />\n </li>\n ))}\n </ol>\n </nav>\n );\n});","import { BaseError } from 'libs/common/backbone/core/BaseError';\nimport { HttpStatus } from 'libs/common/backbone/enums/HttpStatus';\nimport { Xhr } from 'libs/common/backbone/interfaces';\nimport { Core } from 'libs/common/core';\n\nimport { NotFoundError } from 'libs/shared/errors/general/not-found/NotFoundError';\nimport { PrivateResourceError } from 'libs/shared/errors/general/private-resource/PrivateResourceError';\nimport { RegionLockedResourceError } from 'libs/shared/errors/general/region-locked-resource/RegionLockedResourceError';\nimport { UnspecifiedError } from 'libs/shared/errors/general/unspecified-error/UnspecifiedError';\nimport { VideoTypes } from 'libs/shared/interfaces';\n\nexport interface HttpErrorMap {\n notFound?: new () => BaseError;\n forbidden?: {\n rating?: new (description: string) => BaseError;\n yearLevel?: new (description: string) => BaseError;\n region?: new () => BaseError;\n privacy?: new (video?: VideoTypes) => BaseError;\n };\n badRequest?: new () => BaseError;\n}\n\nexport type IgnoreHttpErrorMap = {\n [key in keyof HttpErrorMap]: boolean;\n};\n\nconst defaultErrors: HttpErrorMap = {\n notFound: NotFoundError,\n forbidden: {\n rating: PrivateResourceError,\n yearLevel: PrivateResourceError,\n region: RegionLockedResourceError,\n privacy: PrivateResourceError\n },\n badRequest: UnspecifiedError\n};\n\nexport function handleHttpError(\n info: HttpStatus | Xhr,\n customErrorMap: HttpErrorMap = {},\n /**\n * Prevent certain errors in the errorMap from being thrown\n * so that you may implement your own handler\n */\n ignoreMap: IgnoreHttpErrorMap = {}\n): void {\n if (!info)\n return;\n\n let statusCode: HttpStatus;\n\n if (typeof(info) === 'number') {\n statusCode = info;\n } else {\n statusCode = info.status;\n }\n\n const errorMap = {\n ...defaultErrors,\n ...customErrorMap\n };\n\n if (!statusCode)\n return;\n\n if (!Core.ErrorHelper.isStatusCodeError(statusCode))\n return;\n\n if (statusCode === HttpStatus.NotFound) {\n if (!ignoreMap.notFound)\n Core.ErrorHelper.throw(new errorMap.notFound());\n return;\n }\n\n if (statusCode === HttpStatus.Forbidden) {\n /**\n * TODO: Work out how to go about handling all forbidden errors, such as region locking, year levels,\n * ratings, and privacy.\n */\n if (!ignoreMap.forbidden)\n Core.ErrorHelper.throw(new errorMap.forbidden.privacy());\n return;\n }\n\n if (!ignoreMap.badRequest)\n Core.ErrorHelper.throw(new errorMap.badRequest());\n}\n\nexport function handleXhrError(xhr: Xhr, customErrorMap?: HttpErrorMap): void {\n handleHttpError(xhr.status, customErrorMap);\n}","import { HttpVerbs } from 'libs/common/backbone/enums/HttpVerbs';\nimport { UrlHelper } from 'libs/common/backbone/utils/UrlHelper';\nimport { Flight } from 'libs/common/flight';\n\nconst endpoints = {\n follow: () => `/api/domain/v1/subjects/classifications/following`,\n unfollow: (ids: string[]) => UrlHelper.urlBuilder('/api/domain/v1/subjects/classifications/following', { id: ids })\n};\n\nexport const FollowRequests = {\n /**\n * @param data - array of object ids the user is going to follow\n */\n follow(ids: string[], success?: (data: string[]) => void, error?: () => void): Flight.Request {\n return {\n url: endpoints.follow(),\n key: `follow:${ids.join(',')}`,\n type: HttpVerbs.POST,\n data: ids,\n success,\n error,\n invalidationKeys: [ ...ids.map(id => `classification:${id}`), 'my:subject:preferences', 'classifications' ]\n };\n },\n\n unfollow(ids: string[], success?: () => void, error?: () => void): Flight.Request {\n return {\n url: endpoints.unfollow(ids),\n key: `unfollow:${ids.join(',')}`,\n type: HttpVerbs.DELETE,\n success,\n error,\n invalidationKeys: [ ...ids.map(id => `classification:${id}`), 'my:subject:preferences', 'classifications' ]\n };\n }\n};\n","import { useEffect } from 'react';\n\nimport { Flight } from 'libs/common/flight';\n\nimport { handleHttpError, HttpErrorMap, IgnoreHttpErrorMap } from 'libs/shared/errors/handlers/HttpErrorHandlers';\n\nfunction generateCacheKey(flightObjs: Array<Flight.Response<any>>): string {\n return flightObjs.map(obj => obj.statusCode).join(':');\n}\n\n// TODO: Change this to just `useHandleHttpError` and only accept a status code.\nexport function useHandleObjectError(\n _flightObjs: Flight.Response<any> | Array<Flight.Response<any>>,\n customErrors?: HttpErrorMap,\n ignoreErrors?: IgnoreHttpErrorMap\n): void {\n const flightObjs = Array.isArray(_flightObjs) ? _flightObjs : [_flightObjs];\n\n useEffect(() => {\n flightObjs.forEach(obj => {\n handleHttpError(obj.statusCode, customErrors, ignoreErrors);\n });\n }, [ generateCacheKey(flightObjs), customErrors, ignoreErrors ]);\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>();\n React.useEffect(() => {\n ref.current = value;\n });\n return ref.current;\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};","import { Core } from 'libs/common/core';\nimport { HashObject } from 'libs/common/react/interfaces/HashObject';\nimport { TextHelper } from 'libs/common/react/utils/TextHelper';\n\nimport { Classification, Playlist } from 'libs/shared/interfaces';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\n\nexport const getClassificationAppLink = (params?: HashObject) =>\n (classification?: Classification): Core.AppLink => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION,\n args: classification ? [ classification.id, TextHelper.slugify(classification.name) ] : [],\n params: params || {}\n });\n\nexport const getPlaylistAppLink = (playlist: Playlist, classificationId: string): Core.AppLink => ({\n application: AppChannels.PLAYLISTS,\n action: Actions.Playlists.PLAYLIST,\n args: [ playlist.id, TextHelper.slugify(playlist.name) ],\n params: { classificationId }\n});\n\nexport const getAllTopicsAppLink = (presentationId?: string): Core.AppLink => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_ALL,\n params: presentationId ? { presentationId } : {}\n});\n\nexport const getClassificationTopicsAppLink = (params?: HashObject) =>\n (classification?: Classification): Core.AppLink => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_TOPICS,\n args: classification ? [ classification.id, TextHelper.slugify(classification.name) ] : [],\n params: params || {}\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 { CuratedDashboard, DashboardStatus } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\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={cvSvgLibrary.Plus}\n disabled={isArchived}\n />\n </Tooltip>\n </>\n )}\n </EmptyState>\n </LanguageNamespaceContext.Provider>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"container\":\"k1iOO\",\"itemsWrapper\":\"IC4wJ\",\"anchorWrapper\":\"ciEf6\",\"default\":\"CJonr\",\"selectedItem\":\"A9mBx\",\"disabled\":\"sp1Xl\"};","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 { CuratedWidget } from 'libs/shared/interfaces';\n\nimport styles from './table-of-contents.scss';\n\ninterface TableOfContentsProps {\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}\n\nexport function TableOfContents(props: TableOfContentsProps): JSX.Element {\n function getAppLink(widget: CuratedWidget): Core.AppLink {\n const currentAppLink = Core.AppLinkHelper.getCurrentAppLink();\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 <div className={`${styles.container} ps-3`}>\n <h2 className='h5'>{props.title}</h2>\n <div className={`${styles.itemsWrapper}`}>\n {props.widgets.map((w, idx) => {\n return (\n <AppLink\n key={w.id}\n appLink={getAppLink(w)}\n appLinkOptions={{ replace: true }}\n className={`${styles.anchorWrapper} ${!props.clickable ? styles.disabled : ''} ${props.activeId === w.id ? styles.selectedItem : ''}`}\n onClick={() => {\n ScrollHelper.preventScrollTop();\n props.setControlledId(w.id);\n }}\n analyticsData={{\n ...props.analyticsData,\n id: w.id,\n name: w.name\n }}\n analyticsOptions={{\n actionType: UserAction.Click,\n entity: EntityType.Widget,\n location: LocationContext.TableOfContents\n }}\n >\n <div className={`${!props.activeId && idx === 0 ? styles.default : ''} `}>\n {w.name}\n </div>\n </AppLink>\n );\n })}\n </div>\n </div>\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}","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 * as React from 'react';\n\nimport { StorageType } from 'libs/common/backbone/utils/LocalStorageHelper';\nimport { Core } from 'libs/common/core';\nimport { useViewModel } from 'libs/common/react/hooks/UseViewModel';\nimport { ObjectHelper } from 'libs/common/react/utils/ObjectHelper';\n\nimport { AudienceItem } from 'libs/shared/apps/subjects/components/audience-item/AudienceItem';\nimport { DivButton } from 'libs/shared/components/div-button/DivButton';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { SharedViewModelKeys } from 'libs/shared/constants/SharedViewModelKeys';\nimport { PresentationAudience } from 'libs/shared/interfaces';\nimport { PartialLoadingHelper } from 'libs/shared/utils/PartialLoadingHelper';\n\nconst namespace = 'subjects.audienceFilter';\n\ninterface AudienceFilterProps {\n audiences: PresentationAudience[];\n activeAudiences?: PresentationAudience[];\n disabled?: boolean;\n appLink: Core.AppLink;\n disablePersist?: boolean;\n}\n\nexport function AudienceFilter(props: AudienceFilterProps): React.ReactElement {\n const { audiences, activeAudiences, disabled, appLink } = props;\n\n const [ , setActiveAudiences ] = useViewModel<PresentationAudience[]>(\n SharedViewModelKeys.AUDIENCE_FILTER,\n undefined,\n { storage: StorageType.SessionStorage }\n );\n\n React.useEffect(() => {\n if (!props.disablePersist)\n setActiveAudiences(activeAudiences);\n }, [activeAudiences]);\n\n function onToggleAudience(audience: PresentationAudience, isSelected: boolean): void {\n const activeAudienceNames = isSelected\n ? [ ...(activeAudiences?.map(a => a.name) ?? []), audience.name ]\n : activeAudiences.map(a => a.name).filter(name => name !== audience.name);\n\n const getParams = () => {\n const otherParams = ObjectHelper.omit(appLink.params, ['a']);\n\n if (!activeAudienceNames.length)\n return otherParams;\n\n return Object.assign({}, otherParams, { a: activeAudienceNames });\n };\n\n Core.AppLinkHelper.trigger({\n ...appLink,\n params: getParams()\n }, { replace: true });\n }\n\n function onClickClearAudiences(): void {\n const params = ObjectHelper.omit(appLink.params, ['a']);\n\n Core.AppLinkHelper.trigger({\n ...appLink,\n params\n }, { replace: true });\n }\n\n if (!audiences || !audiences.length)\n return <></>;\n\n return (\n <div className='d-flex flex-wrap row-gap-2'>\n {audiences.map((a: PresentationAudience) => (\n <AudienceItem\n key={a.masterId}\n audience={a}\n highlight={!!activeAudiences?.find(aa => aa.masterId === a.masterId)}\n setAudience={onToggleAudience}\n isDisabled={disabled}\n />\n ))}\n {(!!activeAudiences && !!Object.keys(activeAudiences).length) && (\n <DivButton className='info-link d-inline-block fw-semibold ms-1' onClick={onClickClearAudiences}>\n <Text namespace={namespace} phrase='clear' />\n </DivButton>\n )}\n </div>\n );\n}\n\nconst PARTIAL_AUDIENCES = PartialLoadingHelper.getPartialLoadingItems({ numItems: 6 });\n\nexport const PartialAudienceFilter = () => (\n <div className={'d-flex flex-wrap row-gap-2'}>\n {PARTIAL_AUDIENCES.map(({ width }, idx) => (\n <span\n key={idx}\n className='rounded-pill partial-loading-background me-1'\n dangerouslySetInnerHTML={{ __html: ' ' }}\n style={{ width }}\n />\n ))}\n </div>\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 { Classification, PresentationAudience } from 'libs/shared/interfaces';\nimport { AudienceHelper } from 'libs/shared/utils/audience-helper/AudienceHelper';\n\ninterface ClassificationDashboardAudiencesProps {\n classification: Classification;\n audiences: PresentationAudience[];\n activeAudiences: PresentationAudience[];\n\n appLink: Core.AppLink;\n isEmpty: boolean;\n isReadonly: boolean;\n isComingSoon: boolean;\n disablePersist: boolean;\n}\n\nexport function ClassificationDashboardAudiences(props: ClassificationDashboardAudiencesProps): JSX.Element {\n if (props.isComingSoon)\n return <></>;\n\n if (props.isEmpty && !props.activeAudiences?.length)\n return <></>;\n\n if (!AudienceHelper.shouldShowAudiences(props.audiences))\n return <></>;\n\n return (\n <AudienceFilter\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n disabled={props.isReadonly}\n appLink={props.appLink}\n disablePersist={props.disablePersist}\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 { CuratedClassificationEmptyState } from 'libs/shared/apps/subjects/components/classification-dashboard/empty-state/CuratedClassificationEmptyState';\nimport { TableOfContents } 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, Breadcrumbs } 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 { VideoSubTextType } from 'libs/shared/components/video-sub-text/VideoSubText';\nimport { WidgetHeader } from 'libs/shared/components/widgets/curated-widgets/components/header/WidgetHeader';\nimport { WidgetContainerView } from 'libs/shared/components/widgets/curated-widgets/WidgetContainerView';\nimport { WidgetAppLinks } from 'libs/shared/components/widgets/curated-widgets/WidgetProps';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { WidgetTemplate } from 'libs/shared/enums/WidgetTemplate';\nimport { WidgetTypeId } from 'libs/shared/enums/WidgetTypeId';\nimport { NotFoundError } from 'libs/shared/errors/general/not-found/NotFoundError';\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, CanFavouriteFunc, Classification, CuratedDashboard, CuratedWidget, CuratedWidgetQueryParams, DashboardStatus, DashboardTargetType, FavouriteFunc, Presentation, PresentationAudience, YearGroup } from 'libs/shared/interfaces';\nimport { CuratedDashboardHelper } from 'libs/shared/utils/DashboardHelper';\n\nimport { ClassificationDashboardAudiences } from './audiences/ClassificationDashboardAudiences';\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\ninterface ClassificationDashboardProps {\n dashboard: CuratedDashboard;\n classification: Classification;\n presentation: Presentation;\n hasPermissions: HasPermissionsFunc;\n hasLocalPermissions: HasLocalPermissionsFunc;\n resourceThumbnailFallbackImageUrl: string;\n specialEvent?: CalendarEvent;\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?: (locationContext: LocationContext) => void;\n setFavourite?: FavouriteFunc;\n canFavourite?: CanFavouriteFunc;\n canFollowSubjects: boolean;\n onSubmitFeedback?: (feedback: DashboardFeedbackData) => Promise<void>;\n\n appLinks?: WidgetAppLinks;\n\n imageCdnUrl: string\n emptyImageUrl: 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 isViewCurrentPresentation?: boolean;\n\n yearGroups?: YearGroup[];\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 // Fallback url to display for the company logo. Only used by Streamable Learning atm\n companyLogoFallbackUrl?: string;\n\n subTextType?: VideoSubTextType;\n \n contentType?: CalendarEventContentType;\n\n isBot?: boolean;\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(window.location.hash.slice(1) || '');\n\n const [ tableOfContentActiveId, setTableOfContentActiveId ] = React.useState<string>('');\n\n const headingElements = Array.from(headingRef.current);\n useTableOfContentsScroll(headingElements, props.tableOfContentsId);\n useTableOfContentsActiveHeading({\n setActiveId: setTableOfContentActiveId,\n headingElements,\n controlledId,\n setControlledId\n });\n \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 (props.isComingSoon)\n return false;\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 );\n\n return props.getWidgetContentRequest(id, params, template);\n }\n\n const showEmptyState = shouldShowEmptyState();\n const breadcrumbs = props.getBreadcrumbs?.();\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 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 const widgetsInTableOfContents = widgets.filter(w => {\n return !hideWidget(w) && !!w.metadata?.showInTableOfContents;\n });\n\n const shouldShowTableOfContents = widgetsInTableOfContents.length >= 2 && !isSmallScreen;\n \n if (props.isComingSoon) {\n Core.ErrorHelper.throw(new NotFoundError());\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 ${props.moviesAndTv ? '' : 'topic-dashboard'}`}>\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 />\n\n <div className={`d-flex flex-column row-gap-3 py-3 mb-3 ${(!props.isComingSoon) ? 'border-bottom' : ''}`}>\n <Breadcrumbs breadcrumbs={breadcrumbs} />\n <ClassificationDashboardAudiences\n classification={props.classification}\n audiences={props.audiences}\n activeAudiences={props.activeAudiences}\n appLink={props.appLinks.audience?.()}\n isEmpty={showEmptyState}\n isReadonly={props.isReadonly}\n isComingSoon={props.isComingSoon}\n disablePersist={!props.isViewCurrentPresentation}\n />\n </div>\n\n <div className={`${shouldShowTableOfContents ? 'row no-wrap' : ''}`}>\n <div className={shouldShowTableOfContents ? 'col-9' : ''}>\n {widgets.map((widget, idx) => {\n if (hideWidget(widget))\n return <React.Fragment key={widget.id}></React.Fragment>;\n\n return (\n <WidgetContainerView\n headingElementRef={headingRef}\n key={widget.id}\n id={widget.id}\n name={widget.name}\n description={widget.description}\n templateId={widget.templateId}\n widgetTypeId={widget.widgetId}\n audiences={props.audiences}\n getContentRequest={getWidgetContentRequest}\n setIsEmpty={onSetIsEmpty}\n setFavourite={props.setFavourite}\n canFavourite={props.canFavourite}\n appLinks={props.appLinks}\n yearGroups={props.yearGroups}\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={shouldShowTableOfContents}\n lazyLoad={props.lazyLoad}\n dashboardTarget={DashboardTargetType.Classification}\n widgetIndex={idx}\n hasPermissions={props.hasPermissions}\n hasLocalPermissions={props.hasLocalPermissions}\n isPreviewing={props.isReadonly}\n companyLogoFallbackUrl={props.companyLogoFallbackUrl}\n subTextType={props.subTextType}\n contentType={props.contentType}\n resourceThumbnailFallbackImageUrl={props.resourceThumbnailFallbackImageUrl}\n preferences={widget.preferences}\n />\n );\n })}\n\n {!!videoList?.length && (\n <>\n <WidgetHeader name={LanguageService.getPhrase(namespace, 'videos')} description='' />\n <VideoList\n videos={videoList}\n yearGroups={props.yearGroups}\n getVideoAppLink={(v, opts) => props.appLinks.videoType(v, { ...opts, contextId: videoListWidgetId })}\n getSubTextAppLink={props.appLinks.subText}\n hasPermissions={props.hasPermissions}\n setFavourite={props.setFavourite}\n canFavourite={props.canFavourite}\n presentationAudiences={props.audiences}\n companyLogoFallbackUrl={props.companyLogoFallbackUrl}\n subTextType={props.subTextType}\n getPreviewQuestionsAppLink={props.appLinks.previewQuestions}\n />\n </>\n )}\n </div>\n\n {shouldShowTableOfContents && (\n <aside className='col-3'>\n <TableOfContents\n widgets={widgetsInTableOfContents}\n title={props.classification.name}\n activeId={tableOfContentActiveId}\n clickable={!props.isReadonly}\n analyticsData={props.analyticsData}\n setControlledId={setControlledId}\n />\n </aside>\n )}\n </div>\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}","import React from 'react';\n\nimport { Flight } from 'libs/common/react/index';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\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 widget.widgetId === WidgetTypeId.ClassificationPinnedVideos;\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 => widget.widgetId !== WidgetTypeId.ClassificationPinnedVideos) ?? [],\n videoList: systemGeneratedVideoContent.data?.content ?? [],\n videoListWidgetId: systemGeneratedVideoWidget?.id\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 PartialClassificationDashboard(): 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}","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { ErrorCta, ErrorPageError } from 'libs/shared/errors/primitives/ErrorPageError';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\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.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_ALL\n }\n };\n }\n}","import { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\nimport { ObjectHelper } from 'libs/common/react/utils/ObjectHelper';\nimport { TextHelper } from 'libs/common/react/utils/TextHelper';\n\nimport { ActionOptions } from 'libs/shared/components/actions/Actions';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { WidgetAppLinks } from 'libs/shared/components/widgets/curated-widgets/WidgetProps';\nimport { RelatedVideosContext } from 'libs/shared/enums/RelatedVideosContext';\nimport { Classification, Playlist, PlaylistCollection, Presentation, Resource, Series, SeriesCollection, Video, VideoCollection } from 'libs/shared/interfaces';\nimport { GetVideoAppLinkOptions } from 'libs/shared/interfaces/VideoAppLinkOptions';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\nimport { TopicsHelper } from 'libs/shared/utils/topics-helper/TopicsHelper';\n\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\nimport { VideoAppLinkHelper } from 'shared/utils/VideoAppLinkHelper';\n\nimport { SeriesAppLinkHelper } from 'apps/series/SeriesAppLinkHelper';\nimport { getAllTopicsAppLink } from 'apps/subjects/utils/ClassificationAppLinks';\n\nexport interface ClassificationViewQueryParams {\n a?: string[];\n dashboardId?: string;\n preview?: 'true';\n tocId?: string;\n mtv?: boolean;\n}\n\n/**\n * Checks if the classification would have any content with\n * no filters applied\n */\nexport function hasNoContentUnfiltered(classification: Classification): boolean {\n if (!classification)\n return false;\n\n return (\n classification.series?.count === 0 &&\n classification.pinnedVideos?.count === 0 &&\n classification.playlists?.count === 0\n );\n}\n\ninterface HeroVideoWithVideoList {\n heroVideo: Video;\n videoList: Video[];\n}\n\nexport function extractHeroVideo(\n series: SeriesCollection,\n playlists: PlaylistCollection,\n videos: VideoCollection,\n classification: Classification\n): HeroVideoWithVideoList {\n if (!series || !playlists || !videos || !classification)\n return {\n heroVideo: null,\n videoList: videos && videos.data\n };\n\n // If the subject has no series/playlists, and has only 1 video, that video is displayed as the hero.\n if (!series.data.length && !playlists.data.length && videos.data.length === 1) {\n return {\n heroVideo: ArrayHelper.first(videos.data),\n videoList: []\n };\n }\n\n const pinnedVideoIndex = videos.data.findIndex(video => video.id === classification.pinnedVideoMasterId);\n\n if (pinnedVideoIndex === -1)\n return {\n heroVideo: null,\n videoList: videos.data\n };\n\n return {\n heroVideo: videos.data[pinnedVideoIndex],\n videoList: videos.data.filter(vid => vid.id !== classification.pinnedVideoMasterId)\n };\n}\nconst getPhrase = LanguageService.encloseNamespace('subjects.classification');\n\nexport function getBannerActions(\n classification: Classification,\n canFollowSubjects: boolean,\n onFollow: () => void,\n showFollowButtonSpinner: boolean,\n isSmallScreen: boolean\n): ActionOptions[] {\n if (!canFollowSubjects)\n return [];\n\n const isFollowing = !!classification.followers?.data?.length;\n\n return [{\n label: getPhrase(isFollowing ? 'unfollow' : 'follow'),\n onClick: onFollow,\n svgName: isFollowing ? cvSvgLibrary.Check : cvSvgLibrary.Bell,\n className: `btn follow-btn ${isFollowing ? 'btn-outline-dark' : 'btn-dark'}`,\n button: true,\n tooltip: (isFollowing || isSmallScreen) ? undefined : getPhrase('followBtnTooltip'),\n showSpinner: showFollowButtonSpinner\n }];\n}\n\nexport function getClassificationAppLinks(\n classification: Classification,\n params: ClassificationViewQueryParams\n): WidgetAppLinks {\n return {\n audience: () => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION,\n args: [ classification.id, TextHelper.slugify(classification.name) ],\n params\n }),\n \n classification: (_classification: Classification | null) => {\n const appLinkClassification = _classification || classification;\n\n return {\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION,\n args: [ appLinkClassification.id, TextHelper.slugify(appLinkClassification.name) ],\n params: ObjectHelper.omit(params, [ 'preview', 'dashboardId', 'skipPrompt' ])\n };\n },\n\n classificationTopics: () => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_TOPICS,\n args: classification ? [ classification.id, TextHelper.slugify(classification.name) ] : [],\n params: params || {}\n }),\n\n videoType: (video: Video, opts: GetVideoAppLinkOptions) => (\n VideoAppLinkHelper.getAppLink(video, {\n ...opts,\n context: RelatedVideosContext.Widget,\n moviesAndTv: params.mtv\n })\n ),\n\n allTopics: (presentationId: string) => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION_ALL,\n params: { presentationId }\n }),\n\n series: (series: Series) => {\n return SeriesAppLinkHelper.getSeriesAppLink(series, {\n classificationId: classification.id,\n mtv: params.mtv ? true : undefined\n });\n },\n\n subText: (video: Video) => SeriesAppLinkHelper.getSeriesAppLink(video.series, {\n classificationId: classification.id,\n mtv: params.mtv ? true : undefined\n }),\n\n playlist: (playlist: Playlist) => ({\n application: AppChannels.PLAYLISTS,\n action: Actions.Playlists.PLAYLIST,\n args: [ playlist.id, TextHelper.slugify(playlist.name) ],\n params: {\n classificationId: classification.id,\n mtv: params.mtv ? true : undefined\n }\n }),\n\n resource: (resource: Resource, videoId: string, canViewResources: boolean) => {\n if (!canViewResources) {\n return {\n application: AppChannels.SIGN_UP,\n action: Actions.SignUp.SIGN_UP\n };\n }\n\n return {\n application: AppChannels.VIDEOS,\n action: Actions.Videos.PREVIEW_PDF,\n args: [resource.id],\n params: {\n videoId\n }\n };\n }\n };\n}\n\ninterface GetClassificationBreadcrumbsOptions {\n queryParams: ClassificationViewQueryParams;\n classification: Classification;\n path: Classification[];\n appLinks: WidgetAppLinks;\n presentation: Presentation;\n availablePresentations: Presentation[];\n}\n\nexport function getClassificationBreadcrumbs(\n options: GetClassificationBreadcrumbsOptions\n): Breadcrumb[] {\n const { queryParams, classification, path, presentation, availablePresentations, appLinks } = options;\n\n if (queryParams.mtv) {\n const breadcrumbs: Breadcrumb[] = [{\n name: getPhrase('moviesAndTv'),\n appLink: {\n application: AppChannels.MOVIES_AND_TV,\n action: Actions.MoviesAndTv.HOME\n }\n }];\n\n path.slice(1, path.length).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 \n const breadcrumbs: Breadcrumb[] = [{\n name: TopicsHelper.getExploreAllTopicsTitle(presentation?.name, availablePresentations?.length),\n appLink: getAllTopicsAppLink(presentation?.id)\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}","// extracted by mini-css-extract-plugin\nexport default {\"followButton\":\"HlRXj\"};","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\nimport { TextHelper } from 'libs/common/react/utils/TextHelper';\n\nimport { AnalyticsHelper } from 'libs/analytics/AnalyticsHelper';\nimport { EntityType, LocationContext, ToggleDescriptor, UserAction, WorkflowPhase } from 'libs/analytics/interfaces';\n\nimport { CalendarRequests } from 'libs/shared/apps/calendar/flight-request/CalendarRequests';\nimport { ClassificationDashboard } from 'libs/shared/apps/subjects/components/classification-dashboard/ClassificationDashboard';\nimport { PartialClassificationDashboard } from 'libs/shared/apps/subjects/components/classification-dashboard/partial-loading/PartialClassificationDashboard';\nimport { PreviewBanner } from 'libs/shared/apps/subjects/components/preview-banner/PreviewBanner';\nimport { ActionOptions } from 'libs/shared/components/actions/Actions';\nimport { Breadcrumb } from 'libs/shared/components/breadcrumbs/Breadcrumbs';\nimport { DashboardFeedbackData } from 'libs/shared/components/feedback-form/FeedbackForm';\nimport { VideoActionsContext } from 'libs/shared/context/VideoActionsContext';\nimport { ClassificationStatus } from 'libs/shared/enums/ClassificationStatus';\nimport { MasterType } from 'libs/shared/enums/MasterType';\nimport { MediaQueryStrings } from 'libs/shared/enums/MediaQueries';\nimport { PermissionName } from 'libs/shared/enums/PermissionName';\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 { CustomerRequests } from 'libs/shared/flight-requests/CustomerRequests';\nimport { DashboardRequests } from 'libs/shared/flight-requests/DashboardRequests';\nimport { FollowRequests } from 'libs/shared/flight-requests/FollowRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { useCurationStudio } from 'libs/shared/hooks/useCurationStudio';\nimport { useHandleObjectError } from 'libs/shared/hooks/UseHandleObjectError';\nimport { useMediaQuery } from 'libs/shared/hooks/UseMediaQuery';\nimport { usePermissions } from 'libs/shared/hooks/usePermissions';\nimport { useSetPageMetadata } from 'libs/shared/hooks/useSetPageMetadata';\nimport { CalendarEvent, Classification, Config, CurrentUser, Customer, DashboardTargetType, Presentation, PresentationAudience, RegionAlternative, YearGroup } from 'libs/shared/interfaces';\nimport { AudienceHelper } from 'libs/shared/utils/audience-helper/AudienceHelper';\nimport { PageMetadataHelper } from 'libs/shared/utils/PageMetadataHelper';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport { ImageUrls } from 'shared/constants/ImageUrls';\nimport { Actions } from 'shared/constants/LiteActions';\nimport { AppChannels } from 'shared/constants/LiteRadioChannels';\nimport { ProductboardRequests } from 'shared/flight-requests/ProductboardRequests';\nimport { useVideoActions, VideoActionsLocation } from 'shared/hooks/use-video-actions/useVideoActions';\nimport { useDeepLinks } from 'shared/hooks/useDeepLinks';\nimport { useLiteFavourites } from 'shared/hooks/useLiteFavourites';\nimport { usePresentation } from 'shared/hooks/usePresentation';\nimport { useFetchCuratedDashboard } from 'shared/utils/DashboardHelper';\nimport { SeoHelper } from 'shared/utils/SeoHelper';\n\nimport { TopicNotFoundError } from 'apps/subjects/errors/TopicNotFoundError';\n\nimport { ClassificationViewQueryParams, getClassificationAppLinks, getClassificationBreadcrumbs } from './ClassificationViewUtils';\n\nimport styles from './curated-classification-view.scss';\n\ninterface CuratedClassificationViewProps {\n id: string;\n queryParams?: ClassificationViewQueryParams;\n}\n\nCuratedClassificationView.defaultProps = {\n queryParams: {}\n};\n\nconst namespace = 'subjects.classification';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport function CuratedClassificationView(props: CuratedClassificationViewProps): React.ReactElement {\n const [ showFollowButtonSpinner, setShowFollowButtonSpinner ] = React.useState<boolean>(false);\n\n const fetchAsync = Flight.useGetFetchAsync();\n const { hasPermissions, hasLocalPermissions } = usePermissions();\n\n const config = Flight.useBasicFetch<Config>(ConfigRequests.config());\n const currentUser = Flight.useBasicFetch<CurrentUser>(UserRequests.currentUser());\n const { openInCurationStudioLabel, isUserCurator, getOpenInCurationStudioLink } = useCurationStudio();\n\n const customer = Flight.useBasicFetch<Customer>(\n hasPermissions(PermissionName.CanSubmitFeedback) &&\n currentUser.data &&\n CustomerRequests.customer(currentUser.data.customerId)\n );\n\n const classification = Flight.useBasicFetch<Classification>(\n ClassificationRequests.classification(props.id, currentUser.data?.id)\n );\n\n const presentation = Flight.useBasicFetch<Presentation>(\n classification.data &&\n ClassificationRequests.presentationById(classification.data.presentationId)\n );\n\n const audiences = Flight.useBasicFetch<PresentationAudience[]>(\n classification.data &&\n AudienceRequests.audiencesByPresentationId(classification.data.presentationId)\n );\n\n const specialEvent = Flight.useBasicFetch<CalendarEvent>(\n classification.data &&\n CalendarRequests.nextTopicSpecialEvent(props.id, classification.data.presentationId)\n );\n\n const {\n activePresentation,\n availablePresentations,\n canAccessPresentation\n } = usePresentation();\n\n const yearGroups = Flight.useBasicFetch<YearGroup[]>(\n currentUser.data?.isAuthenticated && CustomerRequests.yearGroups(currentUser.data.customerId)\n );\n\n const path = Flight.useBasicFetch<Classification[]>(ClassificationRequests.path(props.id));\n\n const {\n dashboard,\n isPreviewing,\n isTeacherOnly\n } = useFetchCuratedDashboard({\n classificationId: props.id,\n queryParams: props.queryParams,\n targetType: DashboardTargetType.Classification\n });\n\n const regionAlternatives = Flight.useBasicFetch<RegionAlternative[]>(\n ClassificationRequests.regionAlternatives(props.id)\n );\n\n useSetPageMetadata(PageMetadataHelper.getClassificationMetadata({\n content: classification.data,\n phraseContext: {\n phraseHandler: getPhrase,\n titlePhrase: 'pageTitle',\n descriptionPhrase: 'pageDescription'\n },\n canonicalLink: SeoHelper.getCanonicalLink({ stripPresentationSlug: true }),\n allowIndexing: SeoHelper.allowIndexing(),\n hrefLang: SeoHelper.getContentHrefLang(regionAlternatives.data, (id: string, name: string) => ({\n application: AppChannels.SUBJECT,\n action: Actions.Subjects.CLASSIFICATION,\n args: [ id, TextHelper.slugify(name) ]\n }))\n }));\n\n useHandleObjectError(classification, {\n notFound: TopicNotFoundError\n });\n useDeepLinks({ id: props.id, app: 'topics' });\n\n const isViewCurrentPresentation = activePresentation?.id === presentation.data?.id;\n \n const isSmallScreen = useMediaQuery(MediaQueryStrings.MDDown);\n const isMobile = useMediaQuery(MediaQueryStrings.SMDown);\n\n const { setFavourite, canFavourite } = useLiteFavourites(LocationContext.ExpandableVideoThumbnail);\n const videoActions = useVideoActions({ location: VideoActionsLocation.VideoItem });\n\n const canFollowSubjects = hasPermissions(PermissionName.FollowSubjects);\n const isComingSoon = (\n classification.data?.status === ClassificationStatus.ComingSoon &&\n !isPreviewing\n );\n\n /**\n * We use the current active audiences to re-fetch content for that specific audience set.\n */\n const activeAudiences = AudienceHelper.getActiveAudiencesFromParams(audiences.data, props.queryParams);\n const activeAudienceIds = activeAudiences?.map(a => a.masterId) ?? [];\n\n /**\n * Following\n */\n function onToggleFollow(location: LocationContext) {\n if (!canFollowSubjects)\n return;\n\n setShowFollowButtonSpinner(true);\n\n const isFollowing = !!classification.data.followers?.data?.length;\n\n const request = isFollowing\n ? FollowRequests.unfollow\n : FollowRequests.follow;\n\n fetchAsync(request([classification.data.id]))\n .then(() => {\n AnalyticsHelper.logUserAction(analyticsData, {\n location,\n actionType: UserAction.Follow,\n workflowPhase: WorkflowPhase.Complete,\n descriptor: isFollowing ? ToggleDescriptor.Off : ToggleDescriptor.On,\n entity: EntityType.Classification\n });\n })\n .finally(() => setShowFollowButtonSpinner(false));\n }\n\n function onSubmitFeedback(feedback: DashboardFeedbackData): Promise<void> {\n const promise = fetchAsync<void>(ProductboardRequests.sendTopicFooterFeedback(\n feedback,\n currentUser.data,\n customer.data,\n presentation.data,\n classification.data,\n dashboard.data,\n hasPermissions(PermissionName.StudentExperience)\n ));\n\n AnalyticsHelper.logUserAction({\n feedbackType: feedback.type,\n content: feedback.content,\n presentationId: presentation.data.id,\n classificationId: classification.data.id,\n dashboardId: dashboard.data.id\n }, {\n actionType: UserAction.Submit,\n location: LocationContext.ClassificationFooter,\n entity: EntityType.Feedback,\n workflowPhase: WorkflowPhase.Complete\n });\n\n return promise;\n }\n\n function getBannerActions(): ActionOptions[] {\n const isFollowing = !!classification.data?.followers?.data?.length;\n\n if (!canFollowSubjects || isComingSoon)\n return [];\n\n const actions: ActionOptions[] = [{\n label: isMobile ? '' : getPhrase(isFollowing ? 'unfollow' : 'follow'),\n onClick: () => onToggleFollow(LocationContext.Banner),\n svgName: isFollowing ? cvSvgLibrary.Check : cvSvgLibrary.Bell,\n className: `btn follow-btn me-2 ${isFollowing ? 'btn-outline-dark' : 'btn-dark'} ${styles.followButton}`,\n button: true,\n tooltip: (isFollowing || isSmallScreen) ? undefined : getPhrase('followBtnTooltip'),\n showSpinner: showFollowButtonSpinner\n }];\n\n if (isUserCurator)\n actions.push({\n label: openInCurationStudioLabel,\n href: getOpenInCurationStudioLink(MasterType.Subject, classification.data?.id, presentation.data?.id),\n openInNewTab: true\n });\n \n return actions;\n }\n\n const appLinks = getClassificationAppLinks(classification.data, props.queryParams);\n\n function getBreadcrumbs(): () => Breadcrumb[] {\n if (!canAccessPresentation(presentation.data?.id))\n return;\n\n return () => getClassificationBreadcrumbs({\n appLinks: appLinks,\n availablePresentations,\n classification: classification.data,\n path: path.data,\n presentation: presentation.data,\n queryParams: props.queryParams\n });\n }\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 const dataLoaded = !!config.data\n && dashboard.hasCompleted\n && !!classification.data\n && !!presentation.data\n && !!path.data\n && !!availablePresentations\n && !!audiences.data\n && specialEvent.hasCompleted;\n\n if (!dataLoaded)\n return <PartialClassificationDashboard />;\n\n return (\n <VideoActionsContext.Provider value={videoActions}>\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={hasPermissions}\n hasLocalPermissions={hasLocalPermissions}\n presentation={presentation.data}\n onToggleFollow={onToggleFollow}\n getBannerActions={getBannerActions}\n audiences={props.queryParams.mtv ? null : audiences.data}\n activeAudiences={activeAudiences}\n analyticsData={analyticsData}\n imageCdnUrl={config.data.imageCdnUrl}\n resourceThumbnailFallbackImageUrl={ImageUrls.Fallbacks.RESOURCE_THUMBNAIL}\n emptyImageUrl={isTeacherOnly ? ImageUrls.EmptyStates.Topics.TEACHER_ONLY : ImageUrls.EmptyStates.Topics.TOPIC}\n isComingSoon={isComingSoon}\n appLinks={appLinks}\n isPreviewing={isPreviewing}\n setFavourite={setFavourite}\n canFavourite={canFavourite}\n isViewCurrentPresentation={isViewCurrentPresentation}\n canFollowSubjects={canFollowSubjects}\n onSubmitFeedback={\n hasPermissions(PermissionName.CanSubmitFeedback) &&\n onSubmitFeedback\n }\n tableOfContentsId={props.queryParams.tocId}\n yearGroups={yearGroups.data}\n lazyLoad={!SeoHelper.isBot()}\n moviesAndTv={props.queryParams.mtv}\n isTeacherOnly={isTeacherOnly}\n specialEvent={specialEvent.data}\n isBot={SeoHelper.isBot()}\n // just... one... more.. prop....\n />\n </div>\n </VideoActionsContext.Provider>\n );\n}\n","import { HttpVerbs } from 'libs/common/backbone/enums/HttpVerbs';\nimport { Flight } from 'libs/common/react/index';\n\nimport { DashboardFeedbackData } from 'libs/shared/components/feedback-form/FeedbackForm';\nimport { InstanceRegion } from 'libs/shared/enums/InstanceRegion';\nimport { UserRole } from 'libs/shared/enums/UserRole';\nimport { Classification, CuratedDashboard, CurrentUser, Customer, Presentation } from 'libs/shared/interfaces';\n\nexport const ProductboardRequests = {\n sendDiscoverFooterFeedback(\n feedback: DashboardFeedbackData,\n currentUser: CurrentUser,\n customer: Customer,\n presentation: Presentation,\n dashboard: CuratedDashboard,\n hasStudentExperience: boolean\n ): Flight.Request {\n const userContent = feedback.content.split('\\n').join('<br />');\n\n const content = `\n <b>Type:</b> ${feedback.type === 'positive' ? 'Positive' : 'Negative'}\n <br />\n <b>Location:</b> Discover Footer\n <br />\n <b>Presentation:</b> ${presentation.description} (ID: ${presentation.id})\n <br />\n <b>Dashboard:</b> ${dashboard.name} (ID: ${dashboard.id})\n <br />\n ${getUserInfo(currentUser, customer, hasStudentExperience)}\n <br />\n <b>Feedback:</b>\n <br />\n ${userContent}\n `;\n\n const extraTags = [ 'discover', hasStudentExperience ? 'student' : 'staff' ];\n\n return getRequest('Discover Footer Feedback', content, currentUser, extraTags);\n },\n\n sendTopicFooterFeedback(\n feedback: DashboardFeedbackData,\n currentUser: CurrentUser,\n customer: Customer,\n presentation: Presentation,\n classification: Classification,\n dashboard: CuratedDashboard,\n hasStudentExperience: boolean\n ): Flight.Request {\n const userContent = feedback.content.split('\\n').join('<br />');\n\n const content = `\n <b>Type:</b> ${feedback.type === 'positive' ? 'Positive' : 'Negative'}\n <br />\n <b>Location:</b> Topic Footer\n <br />\n <b>Presentation:</b> ${presentation.description} (ID: ${presentation.id})\n <br />\n <b>Classification:</b> ${classification.name} (ID: ${classification.id})\n <br />\n <b>Dashboard:</b> ${dashboard.name} (ID: ${dashboard.id})\n <br />\n ${getUserInfo(currentUser, customer, hasStudentExperience)}\n <br />\n <b>Feedback:</b>\n <br />\n ${userContent}\n `;\n\n const extraTags = [ 'topics', hasStudentExperience ? 'student' : 'staff' ];\n\n return getRequest('Topic Footer Feedback', content, currentUser, extraTags);\n }\n};\n\nfunction getRequest(\n title: string,\n content: string,\n currentUser: CurrentUser,\n extraTags: string[]\n): Flight.Request {\n const tags = [\n 'new product',\n 'in product feedback',\n ...extraTags\n ];\n\n if (currentUser.role === UserRole.Admin)\n tags.push('administrator');\n\n const regionTag = mapInstanceRegionToTag(currentUser.instanceRegion);\n\n if (regionTag)\n tags.push(regionTag);\n\n return {\n url: '/api/productboard/notes',\n key: 'productboard:feedback',\n data: {\n title,\n content,\n user: {\n email: currentUser.emailVerified ? currentUser.email : ''\n },\n tags\n },\n type: HttpVerbs.POST\n };\n}\n\nfunction mapInstanceRegionToTag(instanceRegion: InstanceRegion): string {\n switch (instanceRegion) {\n case InstanceRegion.AU:\n return 'au';\n case InstanceRegion.NZ:\n return 'nz';\n case InstanceRegion.UK:\n return 'uk';\n case InstanceRegion.US:\n return 'us';\n }\n}\n\nfunction getUserInfo(currentUser: CurrentUser, customer: Customer, hasStudentExperience: boolean): string {\n return `\n <b>User:</b>\n <br />\n <li>ID: ${currentUser.id}</li>\n <li>Username: ${currentUser.username}</li>\n <li>Email: ${currentUser.email}</li>\n <li>User Type / Role: ${getRole(currentUser, hasStudentExperience)}</li>\n <li>Customer ID: ${currentUser.customerId}</li>\n <li>CVC ID: ${customer.crmId}</li>\n <li>Customer Name: ${customer.name}</li>\n <li>Instance Region: ${currentUser.instanceRegion}</li>\n <li>Content Region: ${currentUser.contentRegion}</li>\n `;\n}\n\nfunction getRole(currentUser: CurrentUser, hasStudentExperience: boolean): string {\n if (hasStudentExperience)\n return 'Learner';\n\n return currentUser.role === UserRole.Admin ? 'Admin' : 'Staff';\n}"],"names":["CalendarRequests","calendarEvents","from","to","presentationId","url","publicUrl","key","nextTopicSpecialEvent","classificationId","params","limit","Date","objectType","formatData","events","AudienceItem","props","audience","highlight","setAudience","isDisabled","extraClasses","colourClass","getColourClass","className","onClick","FunctionHelper","role","name","split","map","s","charAt","toUpperCase","substring","join","defaultProps","DashboardStatusConfig","Dashboard","svgName","svgColorClassName","actionName","statusName","getClassName","status","darkMode","wrapperClassName","DashboardStatusBadge","SvgContainer","getPhrase","LanguageService","PreviewBanner","EmojiText","emoji","type","PortalHelper","renderInPortalIfExists","component","portalContainer","createPortal","namespace","BackButton","textShadow","backToName","appLink","color","backPhrase","colorClass","textShadowClass","AppLink","size","S","RATIO","width","height","getSizeClass","heading","length","BannerHeader","banner","imageCdnUrl","actions","sortComponent","blockColourClass","specialEvent","portalContainerContext","BannerPortalContext","imageWidth","useBreakpoints","xxl","specialEventIsToday","showComingSoon","today","DateHelper","endDate","startDate","imageOptions","ratio","resizeType","ImageHelper","fallbackBaseUrl","fallbackCategoryName","containerProps","bannerClassName","style","backgroundImage","DetailsComponent","detailsComponent","backButtonAppLink","backButtonText","backButtonClasses","alignLogoLeft","logo","GenericCalendarDate","body","text","month","theme","calendarTheme","Text","phrase","ComingSoonTag","LazyImage","src","Actions","actionsDropdownClassName","container","prevProps","nextProps","PartialBannerHeader","BreadcrumbItem","breadcrumb","active","withBackIcon","Breadcrumbs","breadcrumbs","isMobile","b","idx","PartialBreadcrumbs","numItems","dangerouslySetInnerHTML","__html","defaultErrors","notFound","forbidden","rating","yearLevel","region","privacy","badRequest","handleHttpError","info","customErrorMap","ignoreMap","statusCode","errorMap","endpoints","ids","id","FollowRequests","follow","success","error","data","invalidationKeys","unfollow","generateCacheKey","flightObjs","obj","useHandleObjectError","_flightObjs","customErrors","ignoreErrors","Array","isArray","useEffect","forEach","usePrevious","value","ref","current","useTableOfContentsScroll","elements","activeId","hasDoneInitialScroll","setHasDoneInitialScroll","previousId","currentId","target","find","rec","getBoundingClientRect","window","scrollBy","top","behavior","getClassificationAppLink","classification","application","action","args","getAllTopicsAppLink","CuratedClassificationEmptyState","isArchived","dashboard","EmptyState","imageUrl","altText","isReadonly","Tooltip","title","spanHack","addWidgetApplink","icon","disabled","TableOfContents","widgets","w","widget","currentAppLink","tocId","appLinkOptions","replace","clickable","ScrollHelper","setControlledId","analyticsData","analyticsOptions","actionType","entity","location","TeacherOnlyEmptyState","ctaAppLink","timer","useTableOfContentsActiveHeading","setActiveId","headingElements","controlledId","scrollPositionRef","observer","IntersectionObserver","headings","setTimeout","isIntersecting","scrollY","isScrollingUp","curIndex","findIndex","h","prevHeading","rootMargin","element","observe","clearTimeout","disconnect","AudienceFilter","audiences","activeAudiences","setActiveAudiences","SharedViewModelKeys","undefined","storage","onToggleAudience","isSelected","otherParams","activeAudienceNames","a","filter","ObjectHelper","Object","assign","disablePersist","masterId","aa","keys","DivButton","PARTIAL_AUDIENCES","PartialLoadingHelper","PartialAudienceFilter","ClassificationDashboardAudiences","isComingSoon","isEmpty","AudienceHelper","isHeadingWidget","widgetId","WidgetTypeId","templateId","WidgetTemplate","ClassificationDashboard","isSystemGeneratedDashboard","systemGeneratedVideoWidget","systemGeneratedVideoContent","DashboardRequests","videoList","content","videoListWidgetId","useGetTopicsWidgets","isSmallScreen","headingRef","Set","initialEmptyWidgets","reduce","acc","emptyWidgets","setEmptyWidgets","hash","slice","tableOfContentActiveId","setTableOfContentActiveId","getWidgetContentRequest","widgetTypeId","template","tableOfContentsId","showEmptyState","isTeacherOnly","isPreviewing","values","every","state","getBreadcrumbs","onSetIsEmpty","newEmptyState","index","currentWidget","isHeadingEmpty","subWidgetIndex","headingSubWidget","hideWidget","widgetsInTableOfContents","metadata","showInTableOfContents","shouldShowTableOfContents","NotFoundError","moviesAndTv","getBannerActions","background","border","appLinks","isViewCurrentPresentation","WidgetContainerView","headingElementRef","description","getContentRequest","setIsEmpty","setFavourite","canFavourite","yearGroups","presentation","isScrollToTargetWidget","scrollToWidgetId","onSubmitFeedback","isBot","hasTableOfContents","lazyLoad","dashboardTarget","widgetIndex","hasPermissions","hasLocalPermissions","companyLogoFallbackUrl","subTextType","contentType","resourceThumbnailFallbackImageUrl","preferences","WidgetHeader","VideoList","videos","getVideoAppLink","v","opts","videoType","contextId","getSubTextAppLink","subText","presentationAudiences","getPreviewQuestionsAppLink","previewQuestions","emptyImageUrl","widgetWizard","allTopics","PartialClassificationDashboard","TopicNotFoundError","ErrorPageError","CuratedClassificationView","queryParams","showFollowButtonSpinner","setShowFollowButtonSpinner","fetchAsync","usePermissions","config","ConfigRequests","currentUser","UserRequests","useCurationStudio","openInCurationStudioLabel","isUserCurator","getOpenInCurationStudioLink","customer","PermissionName","CustomerRequests","customerId","ClassificationRequests","AudienceRequests","usePresentation","activePresentation","availablePresentations","canAccessPresentation","isAuthenticated","path","targetType","regionAlternatives","useSetPageMetadata","PageMetadataHelper","phraseContext","phraseHandler","titlePhrase","descriptionPhrase","canonicalLink","SeoHelper","stripPresentationSlug","allowIndexing","hrefLang","TextHelper","useDeepLinks","app","useLiteFavourites","u","videoActions","useVideoActions","canFollowSubjects","ClassificationStatus","activeAudienceIds","onToggleFollow","isFollowing","followers","request","then","AnalyticsHelper","workflowPhase","descriptor","_classification","appLinkClassification","classificationTopics","video","VideoAppLinkHelper","context","RelatedVideosContext","mtv","series","SeriesAppLinkHelper","playlist","resource","videoId","canViewResources","presentationName","currentClassificationId","currentClassificationName","followingCurrentClassification","hasCompleted","VideoActionsContext","options","item","push","TopicsHelper","getClassificationBreadcrumbs","label","button","tooltip","showSpinner","href","MasterType","openInNewTab","ImageUrls","feedback","promise","ProductboardRequests","feedbackType","dashboardId","sendDiscoverFooterFeedback","hasStudentExperience","userContent","getRequest","getUserInfo","sendTopicFooterFeedback","extraTags","tags","regionTag","instanceRegion","mapInstanceRegionToTag","user","email","emailVerified","username","getRole","crmId","contentRegion"],"sourceRoot":""}
|