@edx/frontend-app-subscription-learner-dashboard 1.53.2 → 1.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/containers/Dashboard/index.js +2 -3
  2. package/dist/containers/Dashboard/index.js.map +1 -1
  3. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressHeader.js +3 -1
  4. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressHeader.js.map +1 -1
  5. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressSidebar/index.js +6 -1
  6. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressSidebar/index.js.map +1 -1
  7. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressSidebar/index.scss +2 -1
  8. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressTabs/index.d.ts +1 -0
  9. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressTabs/index.js +8 -4
  10. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressTabs/index.js.map +1 -1
  11. package/dist/containers/ProgramDashboard/ProgramProgress/ProgramProgressTabs/index.scss +3 -0
  12. package/dist/containers/ProgramDashboard/ProgramProgress/index.scss +7 -0
  13. package/dist/containers/RecommendationsRailsPanel/Recommendations/index.d.ts +4 -0
  14. package/dist/containers/RecommendationsRailsPanel/Recommendations/index.js +7 -0
  15. package/dist/containers/RecommendationsRailsPanel/Recommendations/index.js.map +1 -0
  16. package/dist/containers/RecommendationsRailsPanel/RecommendationsRow.d.ts +5 -0
  17. package/dist/containers/RecommendationsRailsPanel/RecommendationsRow.js +24 -0
  18. package/dist/containers/RecommendationsRailsPanel/RecommendationsRow.js.map +1 -0
  19. package/dist/containers/RecommendationsRailsPanel/index.d.ts +2 -0
  20. package/dist/containers/RecommendationsRailsPanel/index.js +12 -0
  21. package/dist/containers/RecommendationsRailsPanel/index.js.map +1 -0
  22. package/dist/containers/RecommendationsRailsPanel/index.scss +7 -0
  23. package/dist/containers/RecommendationsRailsPanel/messages.d.ts +23 -0
  24. package/dist/containers/RecommendationsRailsPanel/messages.js +25 -0
  25. package/dist/containers/RecommendationsRailsPanel/messages.js.map +1 -0
  26. package/dist/hooks/usePopularCoursesAndPrograms.d.ts +3 -3
  27. package/dist/hooks/usePopularCoursesAndPrograms.js +4 -4
  28. package/dist/hooks/usePopularCoursesAndPrograms.js.map +1 -1
  29. package/dist/types/types.d.ts +1 -0
  30. package/dist/types/types.js.map +1 -1
  31. package/dist/utils/algoliaUtils.d.ts +3 -3
  32. package/dist/utils/algoliaUtils.js +6 -7
  33. package/dist/utils/algoliaUtils.js.map +1 -1
  34. package/dist/widgets/ProgressiveProfilingQuiz/DataRailSelection/index.d.ts +3 -0
  35. package/dist/widgets/ProgressiveProfilingQuiz/DataRailSelection/index.js +21 -0
  36. package/dist/widgets/ProgressiveProfilingQuiz/DataRailSelection/index.js.map +1 -0
  37. package/dist/widgets/ProgressiveProfilingQuiz/app.js +8 -0
  38. package/dist/widgets/ProgressiveProfilingQuiz/app.js.map +1 -1
  39. package/package.json +1 -1
@@ -6,8 +6,6 @@ import { useInitializeSubsCourseDashboard } from '../../data/hooks';
6
6
  import SelectSessionModal from '../../containers/SelectSessionModal';
7
7
  import { DashboardContent } from './DashboardContent';
8
8
  import DashboardModalSlot from '../../slots/DashboardModalSlot';
9
- import PopularCoursePanel from '../PopularCoursePanel';
10
- import PopularProgramsPanel from '../PopularProgramsPanel';
11
9
  import DashboardLayout from './DashboardLayout';
12
10
  import hooks from './hooks';
13
11
  import './index.scss';
@@ -15,6 +13,7 @@ import { SubscriptionBanner } from '../SubscriptionBanner';
15
13
  import { useInitializeSubsDashboard } from '../../data/hooks';
16
14
  import DashboardHeroSlot from '../../slots/DashboardHeroSlot';
17
15
  import { useAnswers } from '../../widgets/ProgressiveProfilingQuiz/data/queryHooks';
16
+ import DataRailSelection from '../../widgets/ProgressiveProfilingQuiz/DataRailSelection';
18
17
  export const Dashboard = () => {
19
18
  const { data, isPending } = useInitializeSubsCourseDashboard();
20
19
  const { data: ProgressiveProfileStatus } = useAnswers();
@@ -25,7 +24,7 @@ export const Dashboard = () => {
25
24
  const learnerSubscriptionData = (learnerData === null || learnerData === void 0 ? void 0 : learnerData.userSubscription) || {};
26
25
  const userSubscriptionStartDate = (learnerSubscriptionData === null || learnerSubscriptionData === void 0 ? void 0 : learnerSubscriptionData.subscriptionStartDate) || '';
27
26
  const hasCourses = useMemo(() => { var _a; return ((_a = data === null || data === void 0 ? void 0 : data.subscriptionCourses) === null || _a === void 0 ? void 0 : _a.length) > 0; }, [data]);
28
- return (_jsx("div", { id: "learnerdashboardroot", children: _jsx("main", { children: _jsxs("div", { id: "dashboard-container", className: "d-flex flex-column p-2 pt-0", children: [_jsx("h1", { className: "sr-only", children: pageTitle }), !isPending && (_jsxs(_Fragment, { children: [_jsx(DashboardModalSlot, {}), (hasCourses && showSelectSessionModal) && _jsx(SelectSessionModal, {})] })), _jsx("div", { id: "dashboard-content", "data-testid": "dashboard-content", children: _jsxs(DashboardLayout, { children: [_jsx(DashboardHeader, { startDate: userSubscriptionStartDate }), _jsx(SubscriptionBanner, { learnerSubscriptionData: learnerSubscriptionData }), _jsx(DashboardHeroSlot, {}), _jsx(DashboardContent, { progressiveProfileStatus: ProgressiveProfileStatus === null || ProgressiveProfileStatus === void 0 ? void 0 : ProgressiveProfileStatus.progressiveProfileStatus }), _jsx(PopularCoursePanel, {}), _jsx(PopularProgramsPanel, {})] }) })] }) }) }));
27
+ return (_jsx("div", { id: "learnerdashboardroot", children: _jsx("main", { children: _jsxs("div", { id: "dashboard-container", className: "d-flex flex-column p-2 pt-0", children: [_jsx("h1", { className: "sr-only", children: pageTitle }), !isPending && (_jsxs(_Fragment, { children: [_jsx(DashboardModalSlot, {}), (hasCourses && showSelectSessionModal) && _jsx(SelectSessionModal, {})] })), _jsx("div", { id: "dashboard-content", "data-testid": "dashboard-content", children: _jsxs(DashboardLayout, { children: [_jsx(DashboardHeader, { startDate: userSubscriptionStartDate }), _jsx(SubscriptionBanner, { learnerSubscriptionData: learnerSubscriptionData }), _jsx(DashboardHeroSlot, {}), _jsx(DashboardContent, { progressiveProfileStatus: ProgressiveProfileStatus === null || ProgressiveProfileStatus === void 0 ? void 0 : ProgressiveProfileStatus.progressiveProfileStatus }), _jsx(DataRailSelection, {})] }) })] }) }) }));
29
28
  };
30
29
  export default Dashboard;
31
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/containers/Dashboard/index.jsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,gCAAgC,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,kBAAkB,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,kBAAkB,MAAM,gCAAgC,CAAC;AAChE,OAAO,kBAAkB,MAAM,uBAAuB,CAAC;AACvD,OAAO,oBAAoB,MAAM,yBAAyB,CAAC;AAE3D,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,iBAAiB,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,uDAAuD,CAAC;AAGnF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE;IAC5B,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,gCAAgC,EAAE,CAAC;IAC/D,MAAM,EAAE,IAAI,EAAE,wBAAwB,EAAE,GAAG,UAAU,EAAE,CAAC;IACxD,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,0BAA0B,EAAE,CAAC;IAC3D,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,oBAAoB,EAAE,CAAC;IACnD,MAAM,EAAE,kBAAkB,EAAE,GAAG,qBAAqB,EAAE,CAAC;IACvD,MAAM,sBAAsB,GAAG,kBAAkB,CAAC,MAAM,KAAK,IAAI,CAAC;IAClE,MAAM,uBAAuB,GAAG,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,gBAAgB,KAAI,EAAE,CAAC;IACpE,MAAM,yBAAyB,GAAG,CAAA,uBAAuB,aAAvB,uBAAuB,uBAAvB,uBAAuB,CAAE,qBAAqB,KAAI,EAAE,CAAC;IACvF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,WAAC,OAAA,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,mBAAmB,0CAAE,MAAM,IAAG,CAAC,CAAA,EAAA,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhF,OAAO,CACL,cAAK,EAAE,EAAC,sBAAsB,YAC5B,yBACE,eAAK,EAAE,EAAC,qBAAqB,EAAC,SAAS,EAAC,6BAA6B,aACnE,aAAI,SAAS,EAAC,SAAS,YAAE,SAAS,GAAM,EACvC,CAAC,SAAS,IAAI,CACb,8BACE,KAAC,kBAAkB,KAAG,EACrB,CAAC,UAAU,IAAI,sBAAsB,CAAC,IAAI,KAAC,kBAAkB,KAAG,IAChE,CACJ,EACD,cAAK,EAAE,EAAC,mBAAmB,iBAAa,mBAAmB,YACzD,MAAC,eAAe,eACd,KAAC,eAAe,IAAC,SAAS,EAAE,yBAAyB,GAAI,EACzD,KAAC,kBAAkB,IAAC,uBAAuB,EAAE,uBAAuB,GAAI,EACxE,KAAC,iBAAiB,KAAG,EACrB,KAAC,gBAAgB,IAAC,wBAAwB,EAAE,wBAAwB,aAAxB,wBAAwB,uBAAxB,wBAAwB,CAAE,wBAAwB,GAAG,EACjG,KAAC,kBAAkB,KAAG,EACtB,KAAC,oBAAoB,KAAG,IACR,GACd,IACF,GACD,GACH,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC","sourcesContent":["import { useMemo } from 'react';\nimport { DashboardHeader } from './DashboardHeader';\n\nimport { useSelectSessionModal } from '@src/data/context';\nimport { useInitializeSubsCourseDashboard } from '@src/data/hooks';\nimport SelectSessionModal from '../../containers/SelectSessionModal';\nimport { DashboardContent } from './DashboardContent';\nimport DashboardModalSlot from '../../slots/DashboardModalSlot';\nimport PopularCoursePanel from '../PopularCoursePanel';\nimport PopularProgramsPanel from '../PopularProgramsPanel';\n\nimport DashboardLayout from './DashboardLayout';\n\nimport hooks from './hooks';\nimport './index.scss';\nimport { SubscriptionBanner } from '../SubscriptionBanner';\nimport { useInitializeSubsDashboard } from '@src/data/hooks';\nimport DashboardHeroSlot from '@src/slots/DashboardHeroSlot';\nimport { useAnswers } from '@src/widgets/ProgressiveProfilingQuiz/data/queryHooks';\n\n\nexport const Dashboard = () => {\n const { data, isPending } = useInitializeSubsCourseDashboard();\n const { data: ProgressiveProfileStatus } = useAnswers();\n const { data: learnerData } = useInitializeSubsDashboard();\n const { pageTitle } = hooks.useDashboardMessages();\n const { selectSessionModal } = useSelectSessionModal();\n const showSelectSessionModal = selectSessionModal.cardId !== null;\n const learnerSubscriptionData = learnerData?.userSubscription || {};\n const userSubscriptionStartDate = learnerSubscriptionData?.subscriptionStartDate || '';\n const hasCourses = useMemo(() => data?.subscriptionCourses?.length > 0, [data]);\n\n return (\n <div id=\"learnerdashboardroot\">\n <main>\n <div id=\"dashboard-container\" className=\"d-flex flex-column p-2 pt-0\">\n <h1 className=\"sr-only\">{pageTitle}</h1>\n {!isPending && (\n <>\n <DashboardModalSlot />\n {(hasCourses && showSelectSessionModal) && <SelectSessionModal />}\n </>\n )}\n <div id=\"dashboard-content\" data-testid=\"dashboard-content\">\n <DashboardLayout>\n <DashboardHeader startDate={userSubscriptionStartDate} />\n <SubscriptionBanner learnerSubscriptionData={learnerSubscriptionData} />\n <DashboardHeroSlot />\n <DashboardContent progressiveProfileStatus={ProgressiveProfileStatus?.progressiveProfileStatus}/>\n <PopularCoursePanel />\n <PopularProgramsPanel />\n </DashboardLayout>\n </div>\n </div>\n </main>\n </div>\n );\n};\n\nexport default Dashboard;\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/containers/Dashboard/index.jsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,gCAAgC,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,kBAAkB,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,kBAAkB,MAAM,gCAAgC,CAAC;AAChE,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,iBAAiB,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,uDAAuD,CAAC;AACnF,OAAO,iBAAiB,MAAM,yDAAyD,CAAC;AAGxF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE;IAC5B,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,gCAAgC,EAAE,CAAC;IAC/D,MAAM,EAAE,IAAI,EAAE,wBAAwB,EAAE,GAAG,UAAU,EAAE,CAAC;IACxD,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,0BAA0B,EAAE,CAAC;IAC3D,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,oBAAoB,EAAE,CAAC;IACnD,MAAM,EAAE,kBAAkB,EAAE,GAAG,qBAAqB,EAAE,CAAC;IACvD,MAAM,sBAAsB,GAAG,kBAAkB,CAAC,MAAM,KAAK,IAAI,CAAC;IAClE,MAAM,uBAAuB,GAAG,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,gBAAgB,KAAI,EAAE,CAAC;IACpE,MAAM,yBAAyB,GAAG,CAAA,uBAAuB,aAAvB,uBAAuB,uBAAvB,uBAAuB,CAAE,qBAAqB,KAAI,EAAE,CAAC;IACvF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,WAAC,OAAA,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,mBAAmB,0CAAE,MAAM,IAAG,CAAC,CAAA,EAAA,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhF,OAAO,CACL,cAAK,EAAE,EAAC,sBAAsB,YAC5B,yBACE,eAAK,EAAE,EAAC,qBAAqB,EAAC,SAAS,EAAC,6BAA6B,aACnE,aAAI,SAAS,EAAC,SAAS,YAAE,SAAS,GAAM,EACvC,CAAC,SAAS,IAAI,CACb,8BACE,KAAC,kBAAkB,KAAG,EACrB,CAAC,UAAU,IAAI,sBAAsB,CAAC,IAAI,KAAC,kBAAkB,KAAG,IAChE,CACJ,EACD,cAAK,EAAE,EAAC,mBAAmB,iBAAa,mBAAmB,YACzD,MAAC,eAAe,eACd,KAAC,eAAe,IAAC,SAAS,EAAE,yBAAyB,GAAI,EACzD,KAAC,kBAAkB,IAAC,uBAAuB,EAAE,uBAAuB,GAAI,EACxE,KAAC,iBAAiB,KAAG,EACrB,KAAC,gBAAgB,IAAC,wBAAwB,EAAE,wBAAwB,aAAxB,wBAAwB,uBAAxB,wBAAwB,CAAE,wBAAwB,GAAG,EACjG,KAAC,iBAAiB,KAAG,IACL,GACd,IACF,GACD,GACH,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC","sourcesContent":["import { useMemo } from 'react';\nimport { DashboardHeader } from './DashboardHeader';\n\nimport { useSelectSessionModal } from '@src/data/context';\nimport { useInitializeSubsCourseDashboard } from '@src/data/hooks';\nimport SelectSessionModal from '../../containers/SelectSessionModal';\nimport { DashboardContent } from './DashboardContent';\nimport DashboardModalSlot from '../../slots/DashboardModalSlot';\nimport DashboardLayout from './DashboardLayout';\nimport hooks from './hooks';\nimport './index.scss';\nimport { SubscriptionBanner } from '../SubscriptionBanner';\nimport { useInitializeSubsDashboard } from '@src/data/hooks';\nimport DashboardHeroSlot from '@src/slots/DashboardHeroSlot';\nimport { useAnswers } from '@src/widgets/ProgressiveProfilingQuiz/data/queryHooks';\nimport DataRailSelection from '@src/widgets/ProgressiveProfilingQuiz/DataRailSelection';\n\n\nexport const Dashboard = () => {\n const { data, isPending } = useInitializeSubsCourseDashboard();\n const { data: ProgressiveProfileStatus } = useAnswers();\n const { data: learnerData } = useInitializeSubsDashboard();\n const { pageTitle } = hooks.useDashboardMessages();\n const { selectSessionModal } = useSelectSessionModal();\n const showSelectSessionModal = selectSessionModal.cardId !== null;\n const learnerSubscriptionData = learnerData?.userSubscription || {};\n const userSubscriptionStartDate = learnerSubscriptionData?.subscriptionStartDate || '';\n const hasCourses = useMemo(() => data?.subscriptionCourses?.length > 0, [data]);\n\n return (\n <div id=\"learnerdashboardroot\">\n <main>\n <div id=\"dashboard-container\" className=\"d-flex flex-column p-2 pt-0\">\n <h1 className=\"sr-only\">{pageTitle}</h1>\n {!isPending && (\n <>\n <DashboardModalSlot />\n {(hasCourses && showSelectSessionModal) && <SelectSessionModal />}\n </>\n )}\n <div id=\"dashboard-content\" data-testid=\"dashboard-content\">\n <DashboardLayout>\n <DashboardHeader startDate={userSubscriptionStartDate} />\n <SubscriptionBanner learnerSubscriptionData={learnerSubscriptionData} />\n <DashboardHeroSlot />\n <DashboardContent progressiveProfileStatus={ProgressiveProfileStatus?.progressiveProfileStatus}/>\n <DataRailSelection />\n </DashboardLayout>\n </div>\n </div>\n </main>\n </div>\n );\n};\n\nexport default Dashboard;\n"]}
@@ -7,7 +7,9 @@ import messages from './messages';
7
7
  const ProgramProgressHeader = ({ programTitle, programType, authoringOrganizations, }) => {
8
8
  const { formatMessage } = useIntl();
9
9
  const programIcon = getProgramIcon(programType);
10
- return (_jsxs(Row, { className: "justify-content-between pb-4.5", children: [_jsxs(Col, { sm: 8, xs: 12, className: "d-flex flex-column align-items-start", children: [_jsxs("div", { className: "d-flex align-items-center", children: [_jsx(Image, { src: programIcon, alt: `${programType} icon`, className: "program-icon mr-1" }), _jsx("h4", { className: "program-type-label font-weight-bold", children: formatMessage(messages.programTypeLabel, { programType }) })] }), _jsx("h2", { className: "program-title font-weight-normal", children: programTitle })] }), authoringOrganizations && (authoringOrganizations === null || authoringOrganizations === void 0 ? void 0 : authoringOrganizations.length) > 0 && (_jsxs(Col, { sm: 4, className: "text-center", children: [_jsx("div", { className: "x-small", children: formatMessage(messages.programProgressInstitutions) }), _jsx("div", { children: authoringOrganizations.map(org => (_jsx(Image, { id: "org-image", src: org.certificateLogoImageUrl || org.logoImageUrl || rwthAachenUniversityLogo, className: "container-mw-md", alt: `${org.name}'s logo` }, org.uuid))) })] }))] }));
10
+ return (_jsxs(Row, { className: "justify-content-between pb-4.5", children: [_jsxs(Col, { sm: 8, xs: 12, className: "d-flex flex-column align-items-start", children: [_jsxs("div", { className: "d-flex align-items-center", children: [_jsx(Image, { src: programIcon, alt: `${programType} icon`, className: "program-icon mr-1" }), _jsx("h4", { className: "program-type-label text-brand-500", children: formatMessage(messages.programTypeLabel, { programType }) })] }), _jsx("h2", { className: "program-title font-weight-bold", children: programTitle })] }), authoringOrganizations && (authoringOrganizations === null || authoringOrganizations === void 0 ? void 0 : authoringOrganizations.length) > 0 && (_jsxs(Col, { sm: 4, className: "text-center", children: [_jsx("div", { className: "x-small mb-2", children: formatMessage(messages.programProgressInstitutions) }), _jsx("div", { children: authoringOrganizations.map((org) => (_jsx(Image, { id: "org-image", src: org.certificateLogoImageUrl
11
+ || org.logoImageUrl
12
+ || rwthAachenUniversityLogo, className: "container-mw-md program-org__logo", alt: `${org.name}'s logo` }, org.uuid))) })] }))] }));
11
13
  };
12
14
  export default ProgramProgressHeader;
13
15
  //# sourceMappingURL=ProgramProgressHeader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProgramProgressHeader.js","sourceRoot":"","sources":["../../../../src/containers/ProgramDashboard/ProgramProgress/ProgramProgressHeader.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,wBAAwB,MAAM,sCAAsC,CAAC;AAE5E,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,qBAAqB,GAAyC,CAAC,EACnE,YAAY,EAAE,WAAW,EAAE,sBAAsB,GAClD,EAAE,EAAE;IACH,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAEhD,OAAO,CACL,MAAC,GAAG,IAAC,SAAS,EAAC,gCAAgC,aAC7C,MAAC,GAAG,IAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,SAAS,EAAC,sCAAsC,aAClE,eAAK,SAAS,EAAC,2BAA2B,aACxC,KAAC,KAAK,IAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,WAAW,OAAO,EAAE,SAAS,EAAC,mBAAmB,GAAG,EACrF,aAAI,SAAS,EAAC,qCAAqC,YAChD,aAAa,CAAC,QAAQ,CAAC,gBAAgB,EAAE,EAAE,WAAW,EAAE,CAAC,GACvD,IACD,EACN,aAAI,SAAS,EAAC,kCAAkC,YAC7C,YAAY,GACV,IACD,EACL,sBAAsB,IAAI,CAAA,sBAAsB,aAAtB,sBAAsB,uBAAtB,sBAAsB,CAAE,MAAM,IAAG,CAAC,IAAI,CAC/D,MAAC,GAAG,IAAC,EAAE,EAAE,CAAC,EAAE,SAAS,EAAC,aAAa,aACjC,cAAK,SAAS,EAAC,SAAS,YACrB,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GAChD,EACN,wBACG,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CACjC,KAAC,KAAK,IAEJ,EAAE,EAAC,WAAW,EACd,GAAG,EAAE,GAAG,CAAC,uBAAuB,IAAI,GAAG,CAAC,YAAY,IAAI,wBAAwB,EAChF,SAAS,EAAC,iBAAiB,EAC3B,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,SAAS,IAJpB,GAAG,CAAC,IAAI,CAKb,CACH,CAAC,GACE,IACF,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,qBAAqB,CAAC","sourcesContent":["import React from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Row, Col, Image } from '@openedx/paragon';\nimport { ProgramProgressHeaderProps } from '../data/types';\nimport { getProgramIcon } from '../data/util';\nimport rwthAachenUniversityLogo from '../assets/rwth-aachen-university.svg';\n\nimport messages from './messages';\n\nconst ProgramProgressHeader: React.FC<ProgramProgressHeaderProps> = ({\n programTitle, programType, authoringOrganizations,\n}) => {\n const { formatMessage } = useIntl();\n const programIcon = getProgramIcon(programType);\n\n return (\n <Row className=\"justify-content-between pb-4.5\">\n <Col sm={8} xs={12} className=\"d-flex flex-column align-items-start\">\n <div className=\"d-flex align-items-center\">\n <Image src={programIcon} alt={`${programType} icon`} className=\"program-icon mr-1\" />\n <h4 className=\"program-type-label font-weight-bold\">\n {formatMessage(messages.programTypeLabel, { programType })}\n </h4>\n </div>\n <h2 className=\"program-title font-weight-normal\">\n {programTitle}\n </h2>\n </Col>\n {authoringOrganizations && authoringOrganizations?.length > 0 && (\n <Col sm={4} className=\"text-center\">\n <div className=\"x-small\">\n {formatMessage(messages.programProgressInstitutions)}\n </div>\n <div>\n {authoringOrganizations.map(org => (\n <Image\n key={org.uuid}\n id=\"org-image\"\n src={org.certificateLogoImageUrl || org.logoImageUrl || rwthAachenUniversityLogo}\n className=\"container-mw-md\"\n alt={`${org.name}'s logo`}\n />\n ))}\n </div>\n </Col>\n )}\n </Row>\n );\n};\n\nexport default ProgramProgressHeader;\n"]}
1
+ {"version":3,"file":"ProgramProgressHeader.js","sourceRoot":"","sources":["../../../../src/containers/ProgramDashboard/ProgramProgress/ProgramProgressHeader.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,wBAAwB,MAAM,sCAAsC,CAAC;AAE5E,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,qBAAqB,GAAyC,CAAC,EACnE,YAAY,EAAE,WAAW,EAAE,sBAAsB,GAClD,EAAE,EAAE;IACH,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAEhD,OAAO,CACL,MAAC,GAAG,IAAC,SAAS,EAAC,gCAAgC,aAC7C,MAAC,GAAG,IAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,SAAS,EAAC,sCAAsC,aAClE,eAAK,SAAS,EAAC,2BAA2B,aACxC,KAAC,KAAK,IACJ,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,GAAG,WAAW,OAAO,EAC1B,SAAS,EAAC,mBAAmB,GAC7B,EACF,aAAI,SAAS,EAAC,mCAAmC,YAC9C,aAAa,CAAC,QAAQ,CAAC,gBAAgB,EAAE,EAAE,WAAW,EAAE,CAAC,GACvD,IACD,EACN,aAAI,SAAS,EAAC,gCAAgC,YAAE,YAAY,GAAM,IAC9D,EACL,sBAAsB,IAAI,CAAA,sBAAsB,aAAtB,sBAAsB,uBAAtB,sBAAsB,CAAE,MAAM,IAAG,CAAC,IAAI,CAC/D,MAAC,GAAG,IAAC,EAAE,EAAE,CAAC,EAAE,SAAS,EAAC,aAAa,aACjC,cAAK,SAAS,EAAC,cAAc,YAC1B,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GAChD,EACN,wBACG,sBAAsB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACnC,KAAC,KAAK,IAEJ,EAAE,EAAC,WAAW,EACd,GAAG,EACD,GAAG,CAAC,uBAAuB;mCACxB,GAAG,CAAC,YAAY;mCAChB,wBAAwB,EAE7B,SAAS,EAAC,mCAAmC,EAC7C,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,SAAS,IARpB,GAAG,CAAC,IAAI,CASb,CACH,CAAC,GACE,IACF,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,qBAAqB,CAAC","sourcesContent":["import React from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Row, Col, Image } from '@openedx/paragon';\nimport { ProgramProgressHeaderProps } from '../data/types';\nimport { getProgramIcon } from '../data/util';\nimport rwthAachenUniversityLogo from '../assets/rwth-aachen-university.svg';\n\nimport messages from './messages';\n\nconst ProgramProgressHeader: React.FC<ProgramProgressHeaderProps> = ({\n programTitle, programType, authoringOrganizations,\n}) => {\n const { formatMessage } = useIntl();\n const programIcon = getProgramIcon(programType);\n\n return (\n <Row className=\"justify-content-between pb-4.5\">\n <Col sm={8} xs={12} className=\"d-flex flex-column align-items-start\">\n <div className=\"d-flex align-items-center\">\n <Image\n src={programIcon}\n alt={`${programType} icon`}\n className=\"program-icon mr-1\"\n />\n <h4 className=\"program-type-label text-brand-500\">\n {formatMessage(messages.programTypeLabel, { programType })}\n </h4>\n </div>\n <h2 className=\"program-title font-weight-bold\">{programTitle}</h2>\n </Col>\n {authoringOrganizations && authoringOrganizations?.length > 0 && (\n <Col sm={4} className=\"text-center\">\n <div className=\"x-small mb-2\">\n {formatMessage(messages.programProgressInstitutions)}\n </div>\n <div>\n {authoringOrganizations.map((org) => (\n <Image\n key={org.uuid}\n id=\"org-image\"\n src={\n org.certificateLogoImageUrl\n || org.logoImageUrl\n || rwthAachenUniversityLogo\n }\n className=\"container-mw-md program-org__logo\"\n alt={`${org.name}'s logo`}\n />\n ))}\n </div>\n </Col>\n )}\n </Row>\n );\n};\n\nexport default ProgramProgressHeader;\n"]}
@@ -27,6 +27,11 @@ export const ProgramProgressSidebar = ({ inProgress, remaining, completed }) =>
27
27
  const price = isLoading ? '' : _jsx(FormattedNumber, { value: (_b = (_a = programProgressData === null || programProgressData === void 0 ? void 0 : programProgressData.programData) === null || _a === void 0 ? void 0 : _a.priceRanges[0]) === null || _b === void 0 ? void 0 : _b.total, style: "currency", currency: (_d = (_c = programProgressData === null || programProgressData === void 0 ? void 0 : programProgressData.programData) === null || _c === void 0 ? void 0 : _c.priceRanges[0]) === null || _d === void 0 ? void 0 : _d.currency });
28
28
  const type = ((_e = programProgressData === null || programProgressData === void 0 ? void 0 : programProgressData.programData) === null || _e === void 0 ? void 0 : _e.type) || '';
29
29
  const programType = getProgramCertificateLabel(type, formatMessage);
30
- return (_jsxs("div", { className: "program-certificate-widget", "data-testid": "program-certificate-progress", children: [_jsx(ProgramProgressCircle, { inProgress: inProgress, remaining: remaining, completed: completed }), _jsx("h6", { className: "progress-heading-circle font-weight-bold mb-4 mt-4", children: formatMessage(messages.programProgressCertificateLabel) }), type.trim().toLowerCase() !== PROGRAM_TYPE_MAP.MICROMASTERS.toLowerCase() && (_jsxs("div", { className: "progress-certificate-content pt-3 px-3", children: [_jsx("p", { children: formatMessage(messages.programProgressCertificateContentOne, { programType: programType }) }), _jsx("p", { children: formatMessage(messages.programProgressCertificateContentTwo, { price }) })] }))] }));
30
+ return (_jsxs("div", { className: "program-certificate-widget", "data-testid": "program-certificate-progress", children: [_jsx(ProgramProgressCircle, { inProgress: inProgress, remaining: remaining, completed: completed }), _jsx("h6", { className: "progress-heading-circle my-5", children: formatMessage(messages.programProgressCertificateLabel) }), type.trim().toLowerCase()
31
+ !== PROGRAM_TYPE_MAP.MICROMASTERS.toLowerCase() && (_jsxs("div", { className: "progress-certificate-content pt-3 px-3", children: [_jsx("p", { className: "text-gray-800", children: formatMessage(messages.programProgressCertificateContentOne, {
32
+ programType: programType,
33
+ }) }), _jsx("p", { className: "text-gray-800", children: formatMessage(messages.programProgressCertificateContentTwo, {
34
+ price,
35
+ }) })] }))] }));
31
36
  };
32
37
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/containers/ProgramDashboard/ProgramProgress/ProgramProgressSidebar/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import { FC } from 'react';\nimport { useIntl, FormattedNumber } from '@openedx/frontend-base';\nimport messages from '../messages';\nimport { ProgramProgressSidebarProps } from '../../data/types';\nimport ProgramProgressCircle from './ProgramProgressCircle';\nimport './index.scss';\nimport { useProgressData } from '@src/hooks';\nimport { PROGRAM_TYPE_MAP } from '../../data/constants';\n\nconst getProgramCertificateLabel = (programType?: string, formatMessage?: (message: typeof messages.programProgressCertificateText) => string) => {\n const normalizedType = programType?.trim();\n\n if (!normalizedType) {\n return formatMessage ? formatMessage(messages.programProgressCertificateText) : 'certificate';\n }\n\n const lowercaseType = normalizedType.toLowerCase();\n\n switch (lowercaseType) {\n case PROGRAM_TYPE_MAP.XSERIES.toLowerCase():\n return formatMessage ? formatMessage(messages.programProgressXSeriesCertificateLabel) : 'XSeries Certificate';\n case PROGRAM_TYPE_MAP.PROFESSIONAL_CERTIFICATE.toLowerCase():\n return normalizedType;\n default:\n return `${normalizedType} ${formatMessage ? formatMessage(messages.programProgressCertificateText) : 'certificate'}`;\n }\n};\n\nexport const ProgramProgressSidebar: FC<ProgramProgressSidebarProps> = ({\n inProgress, remaining, completed\n}) => {\n const { formatMessage } = useIntl();\n const { programProgressData, isLoading } = useProgressData();\n\n const price = isLoading ? '' : <FormattedNumber value={programProgressData?.programData?.priceRanges[0]?.total} style=\"currency\" currency={programProgressData?.programData?.priceRanges[0]?.currency} />;\n const type = programProgressData?.programData?.type || '';\n const programType = getProgramCertificateLabel(type, formatMessage);\n\n return (\n <div\n className=\"program-certificate-widget\"\n data-testid=\"program-certificate-progress\"\n >\n <ProgramProgressCircle inProgress={inProgress} remaining={remaining} completed={completed} />\n <h6 className=\"progress-heading-circle font-weight-bold mb-4 mt-4\">\n {formatMessage(messages.programProgressCertificateLabel)}\n </h6>\n {type.trim().toLowerCase() !== PROGRAM_TYPE_MAP.MICROMASTERS.toLowerCase() && (\n <div className=\"progress-certificate-content pt-3 px-3\">\n <p>\n {formatMessage(messages.programProgressCertificateContentOne, { programType: programType })}\n </p>\n <p>\n {formatMessage(messages.programProgressCertificateContentTwo, { price })}\n </p>\n </div>\n )}\n\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/containers/ProgramDashboard/ProgramProgress/ProgramProgressSidebar/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,QAAQ,MAAM,aAAa,CAAC;AAEnC,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,0BAA0B,GAAG,CAAC,WAAoB,EAAE,aAAmF,EAAE,EAAE;IAC/I,MAAM,cAAc,GAAG,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,IAAI,EAAE,CAAC;IAE3C,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;IAChG,CAAC;IAED,MAAM,aAAa,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;IAEnD,QAAQ,aAAa,EAAE,CAAC;QACtB,KAAK,gBAAgB,CAAC,OAAO,CAAC,WAAW,EAAE;YACzC,OAAO,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,sCAAsC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC;QAChH,KAAK,gBAAgB,CAAC,wBAAwB,CAAC,WAAW,EAAE;YAC1D,OAAO,cAAc,CAAC;QACxB;YACE,OAAO,GAAG,cAAc,IAAI,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACzH,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAoC,CAAC,EACtE,UAAU,EAAE,SAAS,EAAE,SAAS,EACjC,EAAE,EAAE;;IACH,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,EAAE,mBAAmB,EAAE,SAAS,EAAE,GAAG,eAAe,EAAE,CAAC;IAE7D,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAC,eAAe,IAAC,KAAK,EAAE,MAAA,MAAA,mBAAmB,aAAnB,mBAAmB,uBAAnB,mBAAmB,CAAE,WAAW,0CAAE,WAAW,CAAC,CAAC,CAAC,0CAAE,KAAK,EAAE,KAAK,EAAC,UAAU,EAAC,QAAQ,EAAE,MAAA,MAAA,mBAAmB,aAAnB,mBAAmB,uBAAnB,mBAAmB,CAAE,WAAW,0CAAE,WAAW,CAAC,CAAC,CAAC,0CAAE,QAAQ,GAAI,CAAC;IAC1M,MAAM,IAAI,GAAG,CAAA,MAAA,mBAAmB,aAAnB,mBAAmB,uBAAnB,mBAAmB,CAAE,WAAW,0CAAE,IAAI,KAAI,EAAE,CAAC;IAC1D,MAAM,WAAW,GAAG,0BAA0B,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAEpE,OAAO,CACL,eACE,SAAS,EAAC,4BAA4B,iBAC1B,8BAA8B,aAE1C,KAAC,qBAAqB,IAAC,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAI,EAC7F,aAAI,SAAS,EAAC,8BAA8B,YACzC,aAAa,CAAC,QAAQ,CAAC,+BAA+B,CAAC,GACrD,EACJ,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;oBACtB,gBAAgB,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,CACjD,eAAK,SAAS,EAAC,wCAAwC,aACrD,YAAG,SAAS,EAAC,eAAe,YACzB,aAAa,CAAC,QAAQ,CAAC,oCAAoC,EAAE;4BAC5D,WAAW,EAAE,WAAW;yBACzB,CAAC,GACA,EACJ,YAAG,SAAS,EAAC,eAAe,YACzB,aAAa,CAAC,QAAQ,CAAC,oCAAoC,EAAE;4BAC5D,KAAK;yBACN,CAAC,GACA,IACA,CACP,IACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { FC } from 'react';\nimport { useIntl, FormattedNumber } from '@openedx/frontend-base';\nimport messages from '../messages';\nimport { ProgramProgressSidebarProps } from '../../data/types';\nimport ProgramProgressCircle from './ProgramProgressCircle';\nimport './index.scss';\nimport { useProgressData } from '@src/hooks';\nimport { PROGRAM_TYPE_MAP } from '../../data/constants';\n\nconst getProgramCertificateLabel = (programType?: string, formatMessage?: (message: typeof messages.programProgressCertificateText) => string) => {\n const normalizedType = programType?.trim();\n\n if (!normalizedType) {\n return formatMessage ? formatMessage(messages.programProgressCertificateText) : 'certificate';\n }\n\n const lowercaseType = normalizedType.toLowerCase();\n\n switch (lowercaseType) {\n case PROGRAM_TYPE_MAP.XSERIES.toLowerCase():\n return formatMessage ? formatMessage(messages.programProgressXSeriesCertificateLabel) : 'XSeries Certificate';\n case PROGRAM_TYPE_MAP.PROFESSIONAL_CERTIFICATE.toLowerCase():\n return normalizedType;\n default:\n return `${normalizedType} ${formatMessage ? formatMessage(messages.programProgressCertificateText) : 'certificate'}`;\n }\n};\n\nexport const ProgramProgressSidebar: FC<ProgramProgressSidebarProps> = ({\n inProgress, remaining, completed\n}) => {\n const { formatMessage } = useIntl();\n const { programProgressData, isLoading } = useProgressData();\n\n const price = isLoading ? '' : <FormattedNumber value={programProgressData?.programData?.priceRanges[0]?.total} style=\"currency\" currency={programProgressData?.programData?.priceRanges[0]?.currency} />;\n const type = programProgressData?.programData?.type || '';\n const programType = getProgramCertificateLabel(type, formatMessage);\n\n return (\n <div\n className=\"program-certificate-widget\"\n data-testid=\"program-certificate-progress\"\n >\n <ProgramProgressCircle inProgress={inProgress} remaining={remaining} completed={completed} />\n <h6 className=\"progress-heading-circle my-5\">\n {formatMessage(messages.programProgressCertificateLabel)}\n </h6>\n {type.trim().toLowerCase()\n !== PROGRAM_TYPE_MAP.MICROMASTERS.toLowerCase() && (\n <div className=\"progress-certificate-content pt-3 px-3\">\n <p className=\"text-gray-800\">\n {formatMessage(messages.programProgressCertificateContentOne, {\n programType: programType,\n })}\n </p>\n <p className=\"text-gray-800\">\n {formatMessage(messages.programProgressCertificateContentTwo, {\n price,\n })}\n </p>\n </div>\n )}\n </div>\n );\n};\n"]}
@@ -11,7 +11,7 @@ $progress-heading-circle-color: #333333 !default;
11
11
  position: relative;
12
12
  width: 14.375rem;
13
13
  height: 14.375rem;
14
- margin: .5rem auto;
14
+ margin: 0.5rem auto;
15
15
  }
16
16
 
17
17
  .progress-circle {
@@ -55,6 +55,7 @@ $progress-heading-circle-color: #333333 !default;
55
55
  text-align: center;
56
56
  font-size: 0.875rem;
57
57
  line-height: 1.25rem;
58
+ font-weight: 700;
58
59
  }
59
60
 
60
61
  .progress-certificate-content {
@@ -1,3 +1,4 @@
1
1
  import { FC } from 'react';
2
+ import './index.scss';
2
3
  import { ProgramProgressTabsProps } from '../../data/types';
3
4
  export declare const ProgramProgressTabs: FC<ProgramProgressTabsProps>;
@@ -2,6 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { Tabs, Tab } from '@openedx/paragon';
4
4
  import { useIntl } from '@openedx/frontend-base';
5
+ import './index.scss';
5
6
  import messages from '../messages';
6
7
  import { RemainingTabData } from '../RemainingTabData';
7
8
  import { CompletedTabData } from '../CompletedTabData';
@@ -29,12 +30,15 @@ export const ProgramProgressTabs = ({ type, counts }) => {
29
30
  count: completed,
30
31
  panel: _jsx(CompletedTabData, {}),
31
32
  },
32
- ...((type === null || type === void 0 ? void 0 : type.toLowerCase()) === 'micromasters' || (type === null || type === void 0 ? void 0 : type.toLowerCase()) === 'microbachelors'
33
- ? [{
33
+ ...((type === null || type === void 0 ? void 0 : type.toLowerCase()) === 'micromasters'
34
+ || (type === null || type === void 0 ? void 0 : type.toLowerCase()) === 'microbachelors'
35
+ ? [
36
+ {
34
37
  key: 'pathways',
35
38
  title: formatMessage(messages.programProgressPathwaysTab),
36
39
  panel: _jsx(PathwaysTabData, {}),
37
- }]
40
+ },
41
+ ]
38
42
  : []),
39
43
  ];
40
44
  const [activeTab, setActiveTab] = useState(tabsData[0].key);
@@ -42,6 +46,6 @@ export const ProgramProgressTabs = ({ type, counts }) => {
42
46
  if (tabKey)
43
47
  setActiveTab(tabKey);
44
48
  };
45
- return (_jsx(Tabs, { id: "program-progress-tabs", activeKey: activeTab, onSelect: handleTabSelect, className: "mb-4", mountOnEnter: true, children: tabsData.map(tab => (_jsx(Tab, { eventKey: tab.key, title: tab.count !== undefined ? `${tab.title} (${tab.count})` : tab.title, children: tab.panel }, tab.key))) }));
49
+ return (_jsx(Tabs, { id: "program-progress-tabs", activeKey: activeTab, onSelect: handleTabSelect, className: "mb-4", mountOnEnter: true, children: tabsData.map((tab) => (_jsx(Tab, { eventKey: tab.key, title: tab.count !== undefined ? `${tab.title} (${tab.count})` : tab.title, children: tab.panel }, tab.key))) }));
46
50
  };
47
51
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/containers/ProgramDashboard/ProgramProgress/ProgramProgressTabs/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAM,QAAQ,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAGjD,OAAO,QAAQ,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,CAAC,MAAM,mBAAmB,GAAiC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IACpF,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IACpD,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IAEpC,MAAM,QAAQ,GAA8B;QAC1C;YACE,GAAG,EAAE,aAAa;YAClB,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC;YAC3D,KAAK,EAAE,UAAU;YACjB,KAAK,EAAE,KAAC,iBAAiB,KAAG;SAC7B;QACD;YACE,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YAC1D,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,KAAC,gBAAgB,KAAG;SAC5B;QACD;YACE,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YAC1D,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,KAAC,gBAAgB,KAAG;SAC5B;QACD,GAAG,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,EAAE,MAAK,cAAc,IAAI,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,EAAE,MAAK,gBAAgB;YACpF,CAAC,CAAC,CAAC;oBACC,GAAG,EAAE,UAAU;oBACf,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC;oBACzD,KAAK,EAAE,KAAC,eAAe,KAAG;iBAC3B,CAAC;YACJ,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;IAEF,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAS,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEpE,MAAM,eAAe,GAAG,CAAC,MAAqB,EAAE,EAAE;QAChD,IAAI,MAAM;YAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,IAAI,IACH,EAAE,EAAC,uBAAuB,EAC1B,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAC,MAAM,EAChB,YAAY,kBAEX,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CACnB,KAAC,GAAG,IAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,EAAgB,KAAK,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,YAC7G,GAAG,CAAC,KAAK,IADiB,GAAG,CAAC,GAAG,CAE9B,CACP,CAAC,GACG,CACR,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { FC, useState } from 'react';\nimport { Tabs, Tab } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\n\nimport { ProgramProgressTabsProps, ProgramProgressTabItems } from '../../data/types';\nimport messages from '../messages';\nimport { RemainingTabData } from '../RemainingTabData';\nimport { CompletedTabData } from '../CompletedTabData';\nimport { InProgressTabData } from '../InProgressTabData';\nimport { PathwaysTabData } from '../PathwaysTabData';\n\nexport const ProgramProgressTabs: FC<ProgramProgressTabsProps> = ({ type, counts }) => {\n const { inProgress, remaining, completed } = counts;\n const { formatMessage } = useIntl();\n\n const tabsData: ProgramProgressTabItems[] = [\n {\n key: 'in-progress',\n title: formatMessage(messages.programProgressInProgressTab),\n count: inProgress,\n panel: <InProgressTabData />,\n },\n {\n key: 'remaining',\n title: formatMessage(messages.programProgressRemainingTab),\n count: remaining,\n panel: <RemainingTabData />,\n },\n {\n key: 'completed',\n title: formatMessage(messages.programProgressCompletedTab),\n count: completed,\n panel: <CompletedTabData />,\n },\n ...(type?.toLowerCase() === 'micromasters' || type?.toLowerCase() === 'microbachelors'\n ? [{\n key: 'pathways',\n title: formatMessage(messages.programProgressPathwaysTab),\n panel: <PathwaysTabData />,\n }]\n : []),\n ];\n\n const [activeTab, setActiveTab] = useState<string>(tabsData[0].key);\n\n const handleTabSelect = (tabKey: string | null) => {\n if (tabKey) setActiveTab(tabKey);\n };\n\n return (\n <Tabs\n id=\"program-progress-tabs\"\n activeKey={activeTab}\n onSelect={handleTabSelect}\n className=\"mb-4\"\n mountOnEnter\n >\n {tabsData.map(tab => (\n <Tab eventKey={tab.key} key={tab.key} title={tab.count !== undefined ? `${tab.title} (${tab.count})` : tab.title}>\n {tab.panel}\n </Tab>\n ))}\n </Tabs>\n );\n};\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/containers/ProgramDashboard/ProgramProgress/ProgramProgressTabs/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAM,QAAQ,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,cAAc,CAAC;AAGtB,OAAO,QAAQ,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,CAAC,MAAM,mBAAmB,GAAiC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IACpF,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IACpD,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IAEpC,MAAM,QAAQ,GAA8B;QAC1C;YACE,GAAG,EAAE,aAAa;YAClB,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,4BAA4B,CAAC;YAC3D,KAAK,EAAE,UAAU;YACjB,KAAK,EAAE,KAAC,iBAAiB,KAAG;SAC7B;QACD;YACE,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YAC1D,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,KAAC,gBAAgB,KAAG;SAC5B;QACD;YACE,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YAC1D,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,KAAC,gBAAgB,KAAG;SAC5B;QACD,GAAG,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,EAAE,MAAK,cAAc;eACrC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,EAAE,MAAK,gBAAgB;YAC3C,CAAC,CAAC;gBACE;oBACE,GAAG,EAAE,UAAU;oBACf,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC;oBACzD,KAAK,EAAE,KAAC,eAAe,KAAG;iBAC3B;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;IAEF,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAS,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEpE,MAAM,eAAe,GAAG,CAAC,MAAqB,EAAE,EAAE;QAChD,IAAI,MAAM;YAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,IAAI,IACH,EAAE,EAAC,uBAAuB,EAC1B,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAC,MAAM,EAChB,YAAY,kBAEX,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACrB,KAAC,GAAG,IACF,QAAQ,EAAE,GAAG,CAAC,GAAG,EAEjB,KAAK,EACH,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,YAGpE,GAAG,CAAC,KAAK,IALL,GAAG,CAAC,GAAG,CAMR,CACP,CAAC,GACG,CACR,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { FC, useState } from 'react';\nimport { Tabs, Tab } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\nimport './index.scss';\n\nimport { ProgramProgressTabsProps, ProgramProgressTabItems } from '../../data/types';\nimport messages from '../messages';\nimport { RemainingTabData } from '../RemainingTabData';\nimport { CompletedTabData } from '../CompletedTabData';\nimport { InProgressTabData } from '../InProgressTabData';\nimport { PathwaysTabData } from '../PathwaysTabData';\n\nexport const ProgramProgressTabs: FC<ProgramProgressTabsProps> = ({ type, counts }) => {\n const { inProgress, remaining, completed } = counts;\n const { formatMessage } = useIntl();\n\n const tabsData: ProgramProgressTabItems[] = [\n {\n key: 'in-progress',\n title: formatMessage(messages.programProgressInProgressTab),\n count: inProgress,\n panel: <InProgressTabData />,\n },\n {\n key: 'remaining',\n title: formatMessage(messages.programProgressRemainingTab),\n count: remaining,\n panel: <RemainingTabData />,\n },\n {\n key: 'completed',\n title: formatMessage(messages.programProgressCompletedTab),\n count: completed,\n panel: <CompletedTabData />,\n },\n ...(type?.toLowerCase() === 'micromasters'\n || type?.toLowerCase() === 'microbachelors'\n ? [\n {\n key: 'pathways',\n title: formatMessage(messages.programProgressPathwaysTab),\n panel: <PathwaysTabData />,\n },\n ]\n : []),\n ];\n\n const [activeTab, setActiveTab] = useState<string>(tabsData[0].key);\n\n const handleTabSelect = (tabKey: string | null) => {\n if (tabKey) setActiveTab(tabKey);\n };\n\n return (\n <Tabs\n id=\"program-progress-tabs\"\n activeKey={activeTab}\n onSelect={handleTabSelect}\n className=\"mb-4\"\n mountOnEnter\n >\n {tabsData.map((tab) => (\n <Tab\n eventKey={tab.key}\n key={tab.key}\n title={\n tab.count !== undefined ? `${tab.title} (${tab.count})` : tab.title\n }\n >\n {tab.panel}\n </Tab>\n ))}\n </Tabs>\n );\n};\n"]}
@@ -0,0 +1,3 @@
1
+ #program-progress-tabs .nav-link {
2
+ font-weight: 500 !important;
3
+ }
@@ -7,6 +7,7 @@
7
7
  color: var(--pgn-color-info-900);
8
8
  font-size: 22px;
9
9
  margin-bottom: 0.3rem;
10
+ font-weight: 500;
10
11
  }
11
12
 
12
13
  .program-journey-header{
@@ -29,4 +30,10 @@
29
30
  p {
30
31
  margin-bottom: 0;
31
32
  }
33
+ }
34
+
35
+ .program-org__logo {
36
+ max-width: 10.875rem;
37
+ max-height: 5.5rem;
38
+ object-fit: contain;
32
39
  }
@@ -0,0 +1,4 @@
1
+ import { FC } from 'react';
2
+ import { RecommendationsProps } from './data/types';
3
+ export declare const Recommendations: FC<RecommendationsProps>;
4
+ export default Recommendations;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ProductCard } from '../../ProductCard';
3
+ export const Recommendations = ({ items }) => {
4
+ return (_jsx("div", { "data-testid": "popular-courses-items", children: _jsx("div", { className: "row g-3 flex-nowrap flex-md-wrap overflow-auto", children: items.map((item) => (_jsx("div", { className: "col-12 col-md-6 col-xl-3 d-flex mb-2", children: _jsx(ProductCard, { item: item }) }, item.objectID))) }) }));
5
+ };
6
+ export default Recommendations;
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/containers/RecommendationsRailsPanel/Recommendations/index.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,MAAM,CAAC,MAAM,eAAe,GAA6B,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACrE,OAAO,CACL,6BAAiB,uBAAuB,YACtC,cAAK,SAAS,EAAC,gDAAgD,YAC5D,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,cAAyB,SAAS,EAAC,sCAAsC,YACvE,KAAC,WAAW,IAAC,IAAI,EAAE,IAAI,GAAI,IADnB,IAAI,CAAC,QAAQ,CAEjB,CACP,CAAC,GACE,GACF,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,eAAe,CAAC","sourcesContent":["import { FC } from 'react';\n\nimport { ProductCard } from '../../ProductCard';\nimport { RecommendationsProps } from './data/types';\n\nexport const Recommendations: FC<RecommendationsProps> = ({ items }) => {\n return (\n <div data-testid=\"popular-courses-items\">\n <div className=\"row g-3 flex-nowrap flex-md-wrap overflow-auto\">\n {items.map((item) => (\n <div key={item.objectID} className=\"col-12 col-md-6 col-xl-3 d-flex mb-2\">\n <ProductCard item={item} />\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport default Recommendations;\n"]}
@@ -0,0 +1,5 @@
1
+ import { FC } from 'react';
2
+ import './index.scss';
3
+ export declare const RecommendationsRow: FC<{
4
+ skill: string;
5
+ }>;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { useIntl } from '@openedx/frontend-base';
4
+ import { usePopularCoursesAndProgramsData } from '../../hooks/usePopularCoursesAndPrograms';
5
+ import { useAlgoliaSearch } from '../../utils/algoliaUtils';
6
+ import { PRODUCT_TYPE_COURSE } from '../../constants';
7
+ import { Alert } from '@openedx/paragon';
8
+ import messages from './messages';
9
+ import './index.scss';
10
+ import { Recommendations } from './Recommendations';
11
+ export const RecommendationsRow = ({ skill }) => {
12
+ const { formatMessage } = useIntl();
13
+ const [searchClient] = useAlgoliaSearch();
14
+ const { data: recommendationsData = [], isError, isLoading, } = usePopularCoursesAndProgramsData(searchClient, true, PRODUCT_TYPE_COURSE, skill);
15
+ const hasrecommendationsData = useMemo(() => recommendationsData.length > 0, [recommendationsData]);
16
+ if (isError) {
17
+ return (_jsx("div", { className: "recommendation-courses-container mt-5 mb-3", "data-testid": "recommendation-courses-panel", children: _jsx(Alert, { variant: "danger", "data-testid": "recommendation-courses-error", children: formatMessage(messages.recommendationsErrorText) }) }));
18
+ }
19
+ if (isLoading) {
20
+ return (_jsx("p", { "data-testid": "recommendation-courses-loading", role: "status", "aria-live": "polite", children: formatMessage(messages.recommendationsLoadingText) }));
21
+ }
22
+ return (_jsx("div", { className: "recommendation-courses-container mt-3 mb-3", "data-testid": "recommendation-courses-panel", children: hasrecommendationsData && (_jsxs(_Fragment, { children: [_jsxs("h3", { className: "recommendations-header", children: [formatMessage(messages.recommendationsHeader), " ", _jsx("span", { className: "recommendations-skill", children: skill })] }), _jsx(Recommendations, { items: recommendationsData })] })) }));
23
+ };
24
+ //# sourceMappingURL=RecommendationsRow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecommendationsRow.js","sourceRoot":"","sources":["../../../src/containers/RecommendationsRailsPanel/RecommendationsRow.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAM,OAAO,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gCAAgC,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,CAAC,MAAM,kBAAkB,GAA0B,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACrE,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,CAAC,YAAY,CAAC,GAAG,gBAAgB,EAAE,CAAC;IAE1C,MAAM,EACJ,IAAI,EAAE,mBAAmB,GAAG,EAAE,EAC9B,OAAO,EACP,SAAS,GACV,GAAG,gCAAgC,CAAC,YAAY,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,CAAC,CAAC;IAErF,MAAM,sBAAsB,GAAG,OAAO,CACpC,GAAG,EAAE,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,EACpC,CAAC,mBAAmB,CAAC,CACtB,CAAC;IAEF,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CACL,cAAK,SAAS,EAAC,4CAA4C,iBAAa,8BAA8B,YACpG,KAAC,KAAK,IAAC,OAAO,EAAC,QAAQ,iBAAa,8BAA8B,YAC/D,aAAa,CAAC,QAAQ,CAAC,wBAAwB,CAAC,GAC3C,GACJ,CACP,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CACL,2BACc,gCAAgC,EAC5C,IAAI,EAAC,QAAQ,eACH,QAAQ,YAEjB,aAAa,CAAC,QAAQ,CAAC,0BAA0B,CAAC,GACjD,CACL,CAAC;IACJ,CAAC;IAED,OAAO,CACL,cAAK,SAAS,EAAC,4CAA4C,iBAAa,8BAA8B,YACnG,sBAAsB,IAAI,CACzB,8BACE,cAAI,SAAS,EAAC,wBAAwB,aAAE,aAAa,CAAC,QAAQ,CAAC,qBAAqB,CAAC,OAAE,eAAM,SAAS,EAAC,uBAAuB,YAAE,KAAK,GAAQ,IAAK,EAClJ,KAAC,eAAe,IAAC,KAAK,EAAE,mBAAmB,GAAI,IAC9C,CACJ,GACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { FC, useMemo } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { usePopularCoursesAndProgramsData } from '@src/hooks/usePopularCoursesAndPrograms';\nimport { useAlgoliaSearch } from '@src/utils/algoliaUtils';\nimport { PRODUCT_TYPE_COURSE } from '@src/constants';\nimport { Alert } from '@openedx/paragon';\nimport messages from './messages';\nimport './index.scss';\nimport { Recommendations } from './Recommendations';\n\nexport const RecommendationsRow: FC<{ skill: string }> = ({ skill }) => {\n const { formatMessage } = useIntl();\n const [searchClient] = useAlgoliaSearch();\n\n const {\n data: recommendationsData = [],\n isError,\n isLoading,\n } = usePopularCoursesAndProgramsData(searchClient, true, PRODUCT_TYPE_COURSE, skill);\n\n const hasrecommendationsData = useMemo(\n () => recommendationsData.length > 0,\n [recommendationsData]\n );\n\n if (isError) {\n return (\n <div className=\"recommendation-courses-container mt-5 mb-3\" data-testid=\"recommendation-courses-panel\">\n <Alert variant=\"danger\" data-testid=\"recommendation-courses-error\">\n {formatMessage(messages.recommendationsErrorText)}\n </Alert>\n </div>\n );\n }\n\n if (isLoading) {\n return (\n <p\n data-testid=\"recommendation-courses-loading\"\n role=\"status\"\n aria-live=\"polite\"\n >\n {formatMessage(messages.recommendationsLoadingText)}\n </p>\n );\n }\n\n return (\n <div className=\"recommendation-courses-container mt-3 mb-3\" data-testid=\"recommendation-courses-panel\">\n {hasrecommendationsData && (\n <>\n <h3 className=\"recommendations-header\">{formatMessage(messages.recommendationsHeader)} <span className=\"recommendations-skill\">{skill}</span></h3>\n <Recommendations items={recommendationsData} />\n </>\n )}\n </div>\n );\n};\n"]}
@@ -0,0 +1,2 @@
1
+ import { FC } from 'react';
2
+ export declare const RecommendationsRailsPanel: FC;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useProgressiveProfilingQuiz } from '../../widgets/ProgressiveProfilingQuiz/ProgressiveProfilingQuizProvider';
3
+ import { RecommendationsRow } from './RecommendationsRow';
4
+ export const RecommendationsRailsPanel = () => {
5
+ const { answers } = useProgressiveProfilingQuiz();
6
+ const skills = Object.values(answers)
7
+ .filter(answer => answer.questionId === 'interests-declared')
8
+ .map(answer => answer.selectedValues)
9
+ .flat();
10
+ return (_jsx("div", { className: "recommendation-courses-container mt-5 mb-3", "data-testid": "recommendation-courses-panel", children: (skills === null || skills === void 0 ? void 0 : skills.length) > 0 && (skills.slice(0, 4).map(skill => (_jsx("div", { children: _jsx(RecommendationsRow, { skill: skill }) }, skill)))) }));
11
+ };
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/containers/RecommendationsRailsPanel/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,yEAAyE,CAAC;AACtH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,CAAC,MAAM,yBAAyB,GAAO,GAAG,EAAE;IAChD,MAAM,EAAE,OAAO,EAAE,GAAG,2BAA2B,EAAE,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;SAClC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,oBAAoB,CAAC;SAC5D,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;SACpC,IAAI,EAAE,CAAC;IAEV,OAAO,CACL,cAAK,SAAS,EAAC,4CAA4C,iBAAa,8BAA8B,YACnG,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,IAAG,CAAC,IAAI,CACrB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAC9B,wBACE,KAAC,kBAAkB,IAAC,KAAK,EAAE,KAAK,GAAI,IAD5B,KAAK,CAET,CACP,CAAC,CACH,GACG,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { FC } from 'react';\nimport { useProgressiveProfilingQuiz } from '../../widgets/ProgressiveProfilingQuiz/ProgressiveProfilingQuizProvider';\nimport { RecommendationsRow } from './RecommendationsRow';\n\nexport const RecommendationsRailsPanel: FC = () => {\n const { answers } = useProgressiveProfilingQuiz();\n const skills = Object.values(answers)\n .filter(answer => answer.questionId === 'interests-declared')\n .map(answer => answer.selectedValues)\n .flat();\n\n return (\n <div className=\"recommendation-courses-container mt-5 mb-3\" data-testid=\"recommendation-courses-panel\">\n {skills?.length > 0 && (\n skills.slice(0, 4).map(skill => (\n <div key={skill}>\n <RecommendationsRow skill={skill} />\n </div>\n ))\n )}\n </div>\n );\n};\n"]}
@@ -0,0 +1,7 @@
1
+ .recommendations-header {
2
+ color: var(--pgn-color-black);
3
+
4
+ .recommendations-skill {
5
+ text-decoration: underline;
6
+ }
7
+ }
@@ -0,0 +1,23 @@
1
+ declare const messages: {
2
+ recommendationsHeader: {
3
+ id: string;
4
+ defaultMessage: string;
5
+ description: string;
6
+ };
7
+ recommendationsErrorText: {
8
+ id: string;
9
+ defaultMessage: string;
10
+ description: string;
11
+ };
12
+ recommendationsLoadingText: {
13
+ id: string;
14
+ defaultMessage: string;
15
+ description: string;
16
+ };
17
+ recommendationsNoResultsText: {
18
+ id: string;
19
+ defaultMessage: string;
20
+ description: string;
21
+ };
22
+ };
23
+ export default messages;
@@ -0,0 +1,25 @@
1
+ import { defineMessages } from '@openedx/frontend-base';
2
+ const messages = defineMessages({
3
+ recommendationsHeader: {
4
+ id: 'subs-dash.recommendationsPanel.header',
5
+ defaultMessage: 'Because of your interest in',
6
+ description: 'Label for the recommendation courses section',
7
+ },
8
+ recommendationsErrorText: {
9
+ id: 'subs-dash.recommendationsPanel.errorText',
10
+ defaultMessage: 'Failed to load recommendation courses. Please try again later.',
11
+ description: 'Error text for failing to load recommendation courses',
12
+ },
13
+ recommendationsLoadingText: {
14
+ id: 'subs-dash.recommendationsPanel.loadingText',
15
+ defaultMessage: 'Loading course recommendations.',
16
+ description: 'Loading text shown while recommendation courses data is being fetched',
17
+ },
18
+ recommendationsNoResultsText: {
19
+ id: 'subs-dash.recommendationsPanel.noResultsText',
20
+ defaultMessage: 'No course recommendations found.',
21
+ description: 'Text shown when no recommendation courses are found',
22
+ },
23
+ });
24
+ export default messages;
25
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/containers/RecommendationsRailsPanel/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,qBAAqB,EAAE;QACrB,EAAE,EAAE,uCAAuC;QAC3C,cAAc,EAAE,6BAA6B;QAC7C,WAAW,EAAE,8CAA8C;KAC5D;IACD,wBAAwB,EAAE;QACxB,EAAE,EAAE,0CAA0C;QAC9C,cAAc,EAAE,gEAAgE;QAChF,WAAW,EAAE,uDAAuD;KACrE;IACD,0BAA0B,EAAE;QAC1B,EAAE,EAAE,4CAA4C;QAChD,cAAc,EAAE,iCAAiC;QACjD,WAAW,EAAE,uEAAuE;KACrF;IACD,4BAA4B,EAAE;QAC5B,EAAE,EAAE,8CAA8C;QAClD,cAAc,EAAE,kCAAkC;QAClD,WAAW,EAAE,qDAAqD;KACnE;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n recommendationsHeader: {\n id: 'subs-dash.recommendationsPanel.header',\n defaultMessage: 'Because of your interest in',\n description: 'Label for the recommendation courses section',\n },\n recommendationsErrorText: {\n id: 'subs-dash.recommendationsPanel.errorText',\n defaultMessage: 'Failed to load recommendation courses. Please try again later.',\n description: 'Error text for failing to load recommendation courses',\n },\n recommendationsLoadingText: {\n id: 'subs-dash.recommendationsPanel.loadingText',\n defaultMessage: 'Loading course recommendations.',\n description: 'Loading text shown while recommendation courses data is being fetched',\n },\n recommendationsNoResultsText: {\n id: 'subs-dash.recommendationsPanel.noResultsText',\n defaultMessage: 'No course recommendations found.',\n description: 'Text shown when no recommendation courses are found',\n },\n});\n\nexport default messages;\n"]}
@@ -1,11 +1,11 @@
1
1
  import { UseQueryResult } from '@tanstack/react-query';
2
2
  import { SearchClient } from 'algoliasearch';
3
- import { ProductType } from '../types/types';
3
+ import { ProductType, Skill } from '../types/types';
4
4
  import { ProductCardItem } from '@src/containers/ProductCard/data/types';
5
5
  export declare const searchKeys: {
6
6
  all: readonly ["search"];
7
7
  programs: (query: string, tags: string[]) => readonly ["search", "programs", string, string[]];
8
8
  courses: (query: string, tags: string[], page: number) => readonly ["search", "courses", string, string[], number];
9
- popular: (productType: ProductType, limit: number) => readonly ["search", "popular", ProductType, number];
9
+ popular: (productType: ProductType, limit: number, skill?: Skill) => readonly ["search", "popular", ProductType, number, string | null];
10
10
  };
11
- export declare const usePopularCoursesAndProgramsData: (searchClient: SearchClient | null, enabled: boolean, productType?: ProductType) => UseQueryResult<ProductCardItem[]>;
11
+ export declare const usePopularCoursesAndProgramsData: (searchClient: SearchClient | null, enabled: boolean, productType?: ProductType, skill?: Skill) => UseQueryResult<ProductCardItem[]>;
@@ -16,12 +16,12 @@ export const searchKeys = {
16
16
  all: ['search'],
17
17
  programs: (query, tags) => [...searchKeys.all, 'programs', query, tags],
18
18
  courses: (query, tags, page) => [...searchKeys.all, 'courses', query, tags, page],
19
- popular: (productType, limit) => [...searchKeys.all, 'popular', productType, limit],
19
+ popular: (productType, limit, skill) => [...searchKeys.all, 'popular', productType, limit, skill !== null && skill !== void 0 ? skill : null],
20
20
  };
21
- export const usePopularCoursesAndProgramsData = (searchClient, enabled, productType = PRODUCT_TYPE_COURSE) => useQuery({
22
- queryKey: searchKeys.popular(productType, 4),
21
+ export const usePopularCoursesAndProgramsData = (searchClient, enabled, productType = PRODUCT_TYPE_COURSE, skill) => useQuery({
22
+ queryKey: searchKeys.popular(productType, 4, skill),
23
23
  queryFn: () => __awaiter(void 0, void 0, void 0, function* () {
24
- const hits = yield fetchPopularProducts(searchClient, productType, 4);
24
+ const hits = yield fetchPopularProducts(searchClient, productType, 4, skill);
25
25
  return hits.map((hit) => {
26
26
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
27
27
  const hitDetails = hit;
@@ -1 +1 @@
1
- {"version":3,"file":"usePopularCoursesAndPrograms.js","sourceRoot":"","sources":["../../src/hooks/usePopularCoursesAndPrograms.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,QAAQ,EAAkB,MAAM,uBAAuB,CAAC;AAGjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAG/D,iFAAiF;AACjF,oDAAoD;AAEpD,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,GAAG,EAAE,CAAC,QAAQ,CAAU;IACxB,QAAQ,EAAE,CAAC,KAAa,EAAE,IAAc,EAAE,EAAE,CAC1C,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAU;IACvD,OAAO,EAAE,CAAC,KAAa,EAAE,IAAc,EAAE,IAAY,EAAE,EAAE,CACvD,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAU;IAC5D,OAAO,EAAE,CAAC,WAAwB,EAAE,KAAa,EAAE,EAAE,CACnD,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,CAAU;CAC9D,CAAC;AAEF,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,YAAiC,EACjC,OAAgB,EAChB,cAA2B,mBAAmB,EACX,EAAE,CACrC,QAAQ,CAAC;IACP,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5C,OAAO,EAAE,GAAS,EAAE;QAClB,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,YAAa,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;QACvE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAmB,EAAE;;YACvC,MAAM,UAAU,GAAG,GAelB,CAAC;YAEF,OAAO;gBACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,KAAK,EAAE,MAAA,MAAA,GAAG,CAAC,KAAK,mCAAI,GAAG,CAAC,IAAI,mCAAI,UAAU;gBAC1C,mBAAmB,EAAE,MAAA,MAAA,MAAA,UAAU,CAAC,mBAAmB,mCAAI,UAAU,CAAC,iBAAiB,mCAAI,UAAU,CAAC,WAAW,mCAAI,EAAE;gBACnH,GAAG,EAAE,MAAA,MAAA,UAAU,CAAC,cAAc,mCAAI,UAAU,CAAC,SAAS,mCAAI,EAAE;gBAC5D,aAAa,EAAE,MAAA,UAAU,CAAC,aAAa,mCAAI,EAAE;gBAC7C,SAAS,EAAE,MAAA,UAAU,CAAC,0BAA0B,mCAAI,EAAE;gBACtD,YAAY,EAAE,MAAA,MAAA,UAAU,CAAC,YAAY,mCAAI,UAAU,CAAC,OAAO,mCAAI,QAAQ;gBACvE,OAAO,EAAE,WAAW;gBACpB,OAAO,EAAE,MAAA,UAAU,CAAC,OAAO,mCAAI,EAAE;gBACjC,iBAAiB,EAAE,MAAA,UAAU,CAAC,iBAAiB,mCAAI,SAAS;gBAC5D,KAAK,EAAE,MAAA,UAAU,CAAC,KAAK,mCAAI,SAAS;gBACpC,OAAO,EAAE,MAAA,UAAU,CAAC,OAAO,mCAAI,SAAS;aACzC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAA;IACD,OAAO,EAAE,CAAC,CAAC,YAAY,IAAI,OAAO;IAClC,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,EAAE;CAC1B,CAAC,CAAC","sourcesContent":["import { useQuery, UseQueryResult } from '@tanstack/react-query';\nimport { SearchClient } from 'algoliasearch';\nimport { ProductType } from '@src/types/types';\nimport { PRODUCT_TYPE_COURSE } from '@src/constants';\nimport { fetchPopularProducts } from '@src/utils/algoliaUtils';\nimport { ProductCardItem } from '@src/containers/ProductCard/data/types';\n\n// ─── Query key factories ──────────────────────────────────────────────────────\n// Centralised so cache invalidation is never a typo\n\nexport const searchKeys = {\n all: ['search'] as const,\n programs: (query: string, tags: string[]) =>\n [...searchKeys.all, 'programs', query, tags] as const,\n courses: (query: string, tags: string[], page: number) =>\n [...searchKeys.all, 'courses', query, tags, page] as const,\n popular: (productType: ProductType, limit: number) =>\n [...searchKeys.all, 'popular', productType, limit] as const,\n};\n\nexport const usePopularCoursesAndProgramsData = (\n searchClient: SearchClient | null,\n enabled: boolean,\n productType: ProductType = PRODUCT_TYPE_COURSE\n): UseQueryResult<ProductCardItem[]> =>\n useQuery({\n queryKey: searchKeys.popular(productType, 4),\n queryFn: async () => {\n const hits = await fetchPopularProducts(searchClient!, productType, 4);\n return hits.map((hit): ProductCardItem => {\n const hitDetails = hit as {\n short_description?: string,\n primary_description?: string,\n description?: string,\n marketing_url?: string,\n image_url?: string,\n card_image_url?: string,\n organization_logo_override?: string,\n content_type?: string,\n program_type?: string,\n product?: string,\n partner?: string,\n weeks_to_complete?: number,\n level?: string,\n subject?: string,\n };\n\n return {\n objectID: hit.objectID,\n title: hit.title ?? hit.name ?? 'Untitled',\n primary_description: hitDetails.primary_description ?? hitDetails.short_description ?? hitDetails.description ?? '',\n url: hitDetails.card_image_url ?? hitDetails.image_url ?? '',\n marketing_url: hitDetails.marketing_url ?? '',\n thumbnail: hitDetails.organization_logo_override ?? '',\n content_type: hitDetails.program_type ?? hitDetails.product ?? 'Course',\n product: productType,\n partner: hitDetails.partner ?? '',\n weeks_to_complete: hitDetails.weeks_to_complete ?? undefined,\n level: hitDetails.level ?? undefined,\n subject: hitDetails.subject ?? undefined,\n };\n });\n },\n enabled: !!searchClient && enabled,\n staleTime: 1000 * 60 * 10,\n });\n"]}
1
+ {"version":3,"file":"usePopularCoursesAndPrograms.js","sourceRoot":"","sources":["../../src/hooks/usePopularCoursesAndPrograms.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,QAAQ,EAAkB,MAAM,uBAAuB,CAAC;AAGjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAG/D,iFAAiF;AACjF,oDAAoD;AAEpD,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,GAAG,EAAE,CAAC,QAAQ,CAAU;IACxB,QAAQ,EAAE,CAAC,KAAa,EAAE,IAAc,EAAE,EAAE,CAC1C,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAU;IACvD,OAAO,EAAE,CAAC,KAAa,EAAE,IAAc,EAAE,IAAY,EAAE,EAAE,CACvD,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAU;IAC5D,OAAO,EAAE,CAAC,WAAwB,EAAE,KAAa,EAAE,KAAa,EAAE,EAAE,CAClE,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,IAAI,CAAU;CAC7E,CAAC;AAEF,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,YAAiC,EACjC,OAAgB,EAChB,cAA2B,mBAAmB,EAC9C,KAAa,EACsB,EAAE,CACrC,QAAQ,CAAC;IACP,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,KAAK,CAAC;IACnD,OAAO,EAAE,GAAS,EAAE;QAClB,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,YAAa,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAmB,EAAE;;YACvC,MAAM,UAAU,GAAG,GAelB,CAAC;YAEF,OAAO;gBACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,KAAK,EAAE,MAAA,MAAA,GAAG,CAAC,KAAK,mCAAI,GAAG,CAAC,IAAI,mCAAI,UAAU;gBAC1C,mBAAmB,EAAE,MAAA,MAAA,MAAA,UAAU,CAAC,mBAAmB,mCAAI,UAAU,CAAC,iBAAiB,mCAAI,UAAU,CAAC,WAAW,mCAAI,EAAE;gBACnH,GAAG,EAAE,MAAA,MAAA,UAAU,CAAC,cAAc,mCAAI,UAAU,CAAC,SAAS,mCAAI,EAAE;gBAC5D,aAAa,EAAE,MAAA,UAAU,CAAC,aAAa,mCAAI,EAAE;gBAC7C,SAAS,EAAE,MAAA,UAAU,CAAC,0BAA0B,mCAAI,EAAE;gBACtD,YAAY,EAAE,MAAA,MAAA,UAAU,CAAC,YAAY,mCAAI,UAAU,CAAC,OAAO,mCAAI,QAAQ;gBACvE,OAAO,EAAE,WAAW;gBACpB,OAAO,EAAE,MAAA,UAAU,CAAC,OAAO,mCAAI,EAAE;gBACjC,iBAAiB,EAAE,MAAA,UAAU,CAAC,iBAAiB,mCAAI,SAAS;gBAC5D,KAAK,EAAE,MAAA,UAAU,CAAC,KAAK,mCAAI,SAAS;gBACpC,OAAO,EAAE,MAAA,UAAU,CAAC,OAAO,mCAAI,SAAS;aACzC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAA;IACD,OAAO,EAAE,CAAC,CAAC,YAAY,IAAI,OAAO;IAClC,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,EAAE;CAC1B,CAAC,CAAC","sourcesContent":["import { useQuery, UseQueryResult } from '@tanstack/react-query';\nimport { SearchClient } from 'algoliasearch';\nimport { ProductType, Skill } from '@src/types/types';\nimport { PRODUCT_TYPE_COURSE } from '@src/constants';\nimport { fetchPopularProducts } from '@src/utils/algoliaUtils';\nimport { ProductCardItem } from '@src/containers/ProductCard/data/types';\n\n// ─── Query key factories ──────────────────────────────────────────────────────\n// Centralised so cache invalidation is never a typo\n\nexport const searchKeys = {\n all: ['search'] as const,\n programs: (query: string, tags: string[]) =>\n [...searchKeys.all, 'programs', query, tags] as const,\n courses: (query: string, tags: string[], page: number) =>\n [...searchKeys.all, 'courses', query, tags, page] as const,\n popular: (productType: ProductType, limit: number, skill?: Skill) =>\n [...searchKeys.all, 'popular', productType, limit, skill ?? null] as const,\n};\n\nexport const usePopularCoursesAndProgramsData = (\n searchClient: SearchClient | null,\n enabled: boolean,\n productType: ProductType = PRODUCT_TYPE_COURSE,\n skill?: Skill,\n): UseQueryResult<ProductCardItem[]> =>\n useQuery({\n queryKey: searchKeys.popular(productType, 4, skill),\n queryFn: async () => {\n const hits = await fetchPopularProducts(searchClient!, productType, 4, skill);\n return hits.map((hit): ProductCardItem => {\n const hitDetails = hit as {\n short_description?: string,\n primary_description?: string,\n description?: string,\n marketing_url?: string,\n image_url?: string,\n card_image_url?: string,\n organization_logo_override?: string,\n content_type?: string,\n program_type?: string,\n product?: string,\n partner?: string,\n weeks_to_complete?: number,\n level?: string,\n subject?: string,\n };\n\n return {\n objectID: hit.objectID,\n title: hit.title ?? hit.name ?? 'Untitled',\n primary_description: hitDetails.primary_description ?? hitDetails.short_description ?? hitDetails.description ?? '',\n url: hitDetails.card_image_url ?? hitDetails.image_url ?? '',\n marketing_url: hitDetails.marketing_url ?? '',\n thumbnail: hitDetails.organization_logo_override ?? '',\n content_type: hitDetails.program_type ?? hitDetails.product ?? 'Course',\n product: productType,\n partner: hitDetails.partner ?? '',\n weeks_to_complete: hitDetails.weeks_to_complete ?? undefined,\n level: hitDetails.level ?? undefined,\n subject: hitDetails.subject ?? undefined,\n };\n });\n },\n enabled: !!searchClient && enabled,\n staleTime: 1000 * 60 * 10,\n });\n"]}
@@ -30,3 +30,4 @@ export interface AlgoliaSearchResult {
30
30
  nbPages: number;
31
31
  }
32
32
  export type ProductType = 'program' | 'course';
33
+ export type Skill = string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG","sourcesContent":["/**\n * types/index.ts\n *\n * Shared TypeScript interfaces and types for the Search feature.\n */\n\n// ─── Algolia raw hit ──────────────────────────────────────────────────────────\n\n/** Raw shape returned by Algolia for a product hit. Only the fields we access. */\nexport interface AlgoliaProductHit {\n objectID: string,\n title?: string,\n name?: string,\n type?: string,\n content_type?: string,\n institution?: string,\n course_count?: number,\n courseCount?: number,\n card_image_url?: string,\n image_url?: string,\n authoring_organizations?: { name: string }[],\n partners?: { name: string }[],\n [key: string]: unknown, // allow arbitrary extra fields\n}\n\n/** Result shape returned by searchProducts / fetchPopularProducts */\nexport interface AlgoliaSearchResult {\n hits: AlgoliaProductHit[],\n nbHits: number,\n nbPages: number,\n}\n\n// ─── Product type union ───────────────────────────────────────────────────────\n\nexport type ProductType = 'program' | 'course';\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG","sourcesContent":["/**\n * types/index.ts\n *\n * Shared TypeScript interfaces and types for the Search feature.\n */\n\n// ─── Algolia raw hit ──────────────────────────────────────────────────────────\n\n/** Raw shape returned by Algolia for a product hit. Only the fields we access. */\nexport interface AlgoliaProductHit {\n objectID: string,\n title?: string,\n name?: string,\n type?: string,\n content_type?: string,\n institution?: string,\n course_count?: number,\n courseCount?: number,\n card_image_url?: string,\n image_url?: string,\n authoring_organizations?: { name: string }[],\n partners?: { name: string }[],\n [key: string]: unknown, // allow arbitrary extra fields\n}\n\n/** Result shape returned by searchProducts / fetchPopularProducts */\nexport interface AlgoliaSearchResult {\n hits: AlgoliaProductHit[],\n nbHits: number,\n nbPages: number,\n}\n\n// ─── Product type union ───────────────────────────────────────────────────────\n\nexport type ProductType = 'program' | 'course';\n\nexport type Skill = string; // e.g., 'Leadership', 'Communication', etc.\n"]}
@@ -5,7 +5,7 @@
5
5
  * Mirrors the pattern used by the Skills Builder feature, with full TypeScript types.
6
6
  */
7
7
  import { SearchClient } from 'algoliasearch';
8
- import { AlgoliaProductHit, AlgoliaSearchResult, ProductType } from '../types/types';
8
+ import { AlgoliaProductHit, AlgoliaSearchResult, ProductType, Skill } from '../types/types';
9
9
  /**
10
10
  * Creates and memoises an Algolia search client using app config.
11
11
  * Matches the pattern used by the Skills Builder feature.
@@ -45,7 +45,7 @@ export declare const formatFacetFilterData: (facetFilterType: string, data: stri
45
45
  * @param page 0-indexed page number (Algolia convention)
46
46
  * @param staticFacetFilters Additional 'attribute:value' filters always AND-ed in, e.g. ['b2c_subscription_inclusion:true']
47
47
  */
48
- export declare const searchProducts: (searchClient: SearchClient, productType: ProductType, query: string, activeTags: string[], facetField?: string, hitsPerPage?: number, page?: number, staticFacetFilters?: string[]) => Promise<AlgoliaSearchResult>;
48
+ export declare const searchProducts: (searchClient: SearchClient, productType: ProductType, query: string, activeTags: string[], facetField?: string, hitsPerPage?: number, page?: number, staticFacetFilters?: string[], skill?: Skill) => Promise<AlgoliaSearchResult>;
49
49
  /**
50
50
  * Fetches top-ranked products with no query or tag filters.
51
51
  * Used for the "Popular programs / courses" fallback in the no-results state.
@@ -55,4 +55,4 @@ export declare const searchProducts: (searchClient: SearchClient, productType: P
55
55
  * @param hitsPerPage Number of items to fetch
56
56
  * @returns Raw Algolia hit objects
57
57
  */
58
- export declare const fetchPopularProducts: (searchClient: SearchClient, productType: ProductType, hitsPerPage: number) => Promise<AlgoliaProductHit[]>;
58
+ export declare const fetchPopularProducts: (searchClient: SearchClient, productType: ProductType, hitsPerPage: number, skill?: Skill) => Promise<AlgoliaProductHit[]>;
@@ -79,24 +79,23 @@ export const formatFacetFilterData = (facetFilterType, data) => {
79
79
  * @param page 0-indexed page number (Algolia convention)
80
80
  * @param staticFacetFilters Additional 'attribute:value' filters always AND-ed in, e.g. ['b2c_subscription_inclusion:true']
81
81
  */
82
- export const searchProducts = (searchClient_1, productType_1, query_1, activeTags_1, ...args_1) => __awaiter(void 0, [searchClient_1, productType_1, query_1, activeTags_1, ...args_1], void 0, function* (searchClient, productType, query, activeTags, facetField = FACET_SUBJECTS, hitsPerPage = HITS_PER_PAGE_COURSES, page = 0, staticFacetFilters = []) {
82
+ export const searchProducts = (searchClient_1, productType_1, query_1, activeTags_1, ...args_1) => __awaiter(void 0, [searchClient_1, productType_1, query_1, activeTags_1, ...args_1], void 0, function* (searchClient, productType, query, activeTags, facetField = FACET_SUBJECTS, hitsPerPage = HITS_PER_PAGE_COURSES, page = 0, staticFacetFilters = [], skill) {
83
83
  const indexName = getAppConfig(appId).ALGOLIA_PRODUCT_INDEX_NAME;
84
84
  const tagFilters = formatFacetFilterData(facetField, activeTags);
85
85
  // Nested arrays = AND between outer elements, OR within inner arrays
86
86
  const facetFilters = [
87
87
  [`product:${productType}`],
88
+ ...(skill ? [[`skills.skill:${skill}`]] : []),
88
89
  ...(tagFilters.length > 0 ? [tagFilters] : []),
89
90
  ...staticFacetFilters.map((filter) => [filter]),
90
91
  ];
91
92
  try {
92
93
  const { hits, nbHits, nbPages } = yield searchClient.searchSingleIndex({
93
94
  indexName,
94
- searchParams: {
95
- query,
95
+ searchParams: Object.assign({ query,
96
96
  facetFilters,
97
97
  hitsPerPage,
98
- page,
99
- },
98
+ page }, (skill ? { facets: ['skills.skill'] } : {})),
100
99
  });
101
100
  return {
102
101
  hits: hits,
@@ -120,10 +119,10 @@ export const searchProducts = (searchClient_1, productType_1, query_1, activeTag
120
119
  * @param hitsPerPage Number of items to fetch
121
120
  * @returns Raw Algolia hit objects
122
121
  */
123
- export const fetchPopularProducts = (searchClient, productType, hitsPerPage) => __awaiter(void 0, void 0, void 0, function* () {
122
+ export const fetchPopularProducts = (searchClient, productType, hitsPerPage, skill) => __awaiter(void 0, void 0, void 0, function* () {
124
123
  const { hits } = yield searchProducts(searchClient, productType, '', // empty query → Algolia ranks by popularity
125
124
  [], // no tag filters
126
- FACET_SUBJECTS, hitsPerPage, 0, ['b2c_subscription_inclusion:true']);
125
+ FACET_SUBJECTS, hitsPerPage, 0, ['b2c_subscription_inclusion:true'], skill);
127
126
  return hits;
128
127
  });
129
128
  //# sourceMappingURL=algoliaUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"algoliaUtils.js","sourceRoot":"","sources":["../../src/utils/algoliaUtils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * utils/algoliaUtils.ts\n *\n * Algolia utility functions for the Search feature.\n * Mirrors the pattern used by the Skills Builder feature, with full TypeScript types.\n */\n\nimport { useMemo } from 'react';\nimport { getAppConfig, logError } from '@openedx/frontend-base';\nimport { algoliasearch, SearchClient } from 'algoliasearch';\nimport { FACET_SUBJECTS, HITS_PER_PAGE_COURSES } from '@src/constants';\n\nimport {\n AlgoliaProductHit,\n AlgoliaSearchResult,\n ProductType,\n} from '../types/types';\n\nimport { appId } from '@src/constants';\n\n// ─── useAlgoliaSearch ─────────────────────────────────────────────────────────\n\n/**\n * Creates and memoises an Algolia search client using app config.\n * Matches the pattern used by the Skills Builder feature.\n *\n * @returns [SearchClient | null] tuple — destructure as: const [searchClient] = useAlgoliaSearch()\n */\nexport const useAlgoliaSearch = (): [SearchClient | null] => {\n const config = getAppConfig(appId);\n const algoliaAppId = config.ALGOLIA_APP_ID as string | undefined;\n const algoliaSearchApiKey = config.ALGOLIA_SEARCH_API_KEY as string | undefined;\n\n const [searchClient] = useMemo<[SearchClient | null]>(\n () => {\n if (!algoliaAppId || !algoliaSearchApiKey) {\n logError(new Error('Missing Algolia configuration: ALGOLIA_APP_ID or ALGOLIA_SEARCH_API_KEY'));\n return [null];\n }\n\n const client = algoliasearch(algoliaAppId, algoliaSearchApiKey);\n return [client];\n },\n [algoliaAppId, algoliaSearchApiKey],\n );\n\n return [searchClient];\n};\n\n// ─── formatFacetFilterData ────────────────────────────────────────────────────\n\n/**\n * Formats an array of values into Algolia facet filter strings.\n *\n * @param facetFilterType Facet attribute name, e.g. 'subjects'\n * @param data Array of values, e.g. ['Leadership', 'AI']\n * @returns e.g. ['subjects:Leadership', 'subjects:AI']\n *\n * @example\n * formatFacetFilterData('subjects', ['Leadership', 'AI'])\n * // → ['subjects:Leadership', 'subjects:AI']\n */\nexport const formatFacetFilterData = (\n facetFilterType: string,\n data: string[],\n): string[] => {\n const formattedData: string[] = [];\n if (data) {\n data.forEach((item) => formattedData.push(`${facetFilterType}:${item}`));\n }\n return formattedData;\n};\n\n// ─── searchProducts ───────────────────────────────────────────────────────────\n\n/**\n * Searches programs or courses from the shared product index.\n *\n * Both product types live in ALGOLIA_PRODUCT_INDEX_NAME, distinguished by the\n * `product` facet. Active tags are OR-ed within their facet and AND-ed with\n * the product-type filter — standard Algolia multi-select pattern.\n *\n * Algolia facetFilters format used here:\n * [ ['product:program'], ['subjects:Leadership', 'subjects:AI'] ]\n * → product = \"program\" AND (subjects = \"Leadership\" OR subjects = \"AI\")\n *\n * @param searchClient Algolia client from useAlgoliaSearch()\n * @param productType 'program' | 'course'\n * @param query Free-text query ('' = browse / rank by popularity)\n * @param activeTags Selected tag values from the filter chips\n * @param facetField Facet attribute to filter tags on (default: 'subjects')\n * @param hitsPerPage Page size\n * @param page 0-indexed page number (Algolia convention)\n * @param staticFacetFilters Additional 'attribute:value' filters always AND-ed in, e.g. ['b2c_subscription_inclusion:true']\n */\nexport const searchProducts = async (\n searchClient: SearchClient,\n productType: ProductType,\n query: string,\n activeTags: string[],\n facetField: string = FACET_SUBJECTS,\n hitsPerPage: number = HITS_PER_PAGE_COURSES,\n page = 0,\n staticFacetFilters: string[] = [],\n): Promise<AlgoliaSearchResult> => {\n const indexName = getAppConfig(appId).ALGOLIA_PRODUCT_INDEX_NAME as string;\n const tagFilters = formatFacetFilterData(facetField, activeTags);\n\n // Nested arrays = AND between outer elements, OR within inner arrays\n const facetFilters: string[][] = [\n [`product:${productType}`],\n ...(tagFilters.length > 0 ? [tagFilters] : []),\n ...staticFacetFilters.map((filter) => [filter]),\n ];\n\n try {\n const { hits, nbHits, nbPages } = await searchClient.searchSingleIndex({\n indexName,\n searchParams: {\n query,\n facetFilters,\n hitsPerPage,\n page,\n },\n });\n\n return {\n hits: hits as AlgoliaProductHit[],\n nbHits: nbHits ?? 0,\n nbPages: nbPages ?? 0,\n };\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n logError(err);\n return { hits: [], nbHits: 0, nbPages: 0 };\n }\n};\n\n// ─── fetchPopularProducts ─────────────────────────────────────────────────────\n\n/**\n * Fetches top-ranked products with no query or tag filters.\n * Used for the \"Popular programs / courses\" fallback in the no-results state.\n *\n * @param searchClient Algolia client\n * @param productType 'program' | 'course'\n * @param hitsPerPage Number of items to fetch\n * @returns Raw Algolia hit objects\n */\nexport const fetchPopularProducts = async (\n searchClient: SearchClient,\n productType: ProductType,\n hitsPerPage: number,\n): Promise<AlgoliaProductHit[]> => {\n const { hits } = await searchProducts(\n searchClient,\n productType,\n '', // empty query → Algolia ranks by popularity\n [], // no tag filters\n FACET_SUBJECTS,\n hitsPerPage,\n 0,\n ['b2c_subscription_inclusion:true'],\n );\n return hits;\n};\n"]}
1
+ {"version":3,"file":"algoliaUtils.js","sourceRoot":"","sources":["../../src/utils/algoliaUtils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * utils/algoliaUtils.ts\n *\n * Algolia utility functions for the Search feature.\n * Mirrors the pattern used by the Skills Builder feature, with full TypeScript types.\n */\n\nimport { useMemo } from 'react';\nimport { getAppConfig, logError } from '@openedx/frontend-base';\nimport { algoliasearch, SearchClient } from 'algoliasearch';\nimport { FACET_SUBJECTS, HITS_PER_PAGE_COURSES } from '@src/constants';\n\nimport {\n AlgoliaProductHit,\n AlgoliaSearchResult,\n ProductType,\n Skill,\n} from '../types/types';\n\nimport { appId } from '@src/constants';\n\n// ─── useAlgoliaSearch ─────────────────────────────────────────────────────────\n\n/**\n * Creates and memoises an Algolia search client using app config.\n * Matches the pattern used by the Skills Builder feature.\n *\n * @returns [SearchClient | null] tuple — destructure as: const [searchClient] = useAlgoliaSearch()\n */\nexport const useAlgoliaSearch = (): [SearchClient | null] => {\n const config = getAppConfig(appId);\n const algoliaAppId = config.ALGOLIA_APP_ID as string | undefined;\n const algoliaSearchApiKey = config.ALGOLIA_SEARCH_API_KEY as string | undefined;\n\n const [searchClient] = useMemo<[SearchClient | null]>(\n () => {\n if (!algoliaAppId || !algoliaSearchApiKey) {\n logError(new Error('Missing Algolia configuration: ALGOLIA_APP_ID or ALGOLIA_SEARCH_API_KEY'));\n return [null];\n }\n\n const client = algoliasearch(algoliaAppId, algoliaSearchApiKey);\n return [client];\n },\n [algoliaAppId, algoliaSearchApiKey],\n );\n\n return [searchClient];\n};\n\n// ─── formatFacetFilterData ────────────────────────────────────────────────────\n\n/**\n * Formats an array of values into Algolia facet filter strings.\n *\n * @param facetFilterType Facet attribute name, e.g. 'subjects'\n * @param data Array of values, e.g. ['Leadership', 'AI']\n * @returns e.g. ['subjects:Leadership', 'subjects:AI']\n *\n * @example\n * formatFacetFilterData('subjects', ['Leadership', 'AI'])\n * // → ['subjects:Leadership', 'subjects:AI']\n */\nexport const formatFacetFilterData = (\n facetFilterType: string,\n data: string[],\n): string[] => {\n const formattedData: string[] = [];\n if (data) {\n data.forEach((item) => formattedData.push(`${facetFilterType}:${item}`));\n }\n return formattedData;\n};\n\n// ─── searchProducts ───────────────────────────────────────────────────────────\n\n/**\n * Searches programs or courses from the shared product index.\n *\n * Both product types live in ALGOLIA_PRODUCT_INDEX_NAME, distinguished by the\n * `product` facet. Active tags are OR-ed within their facet and AND-ed with\n * the product-type filter — standard Algolia multi-select pattern.\n *\n * Algolia facetFilters format used here:\n * [ ['product:program'], ['subjects:Leadership', 'subjects:AI'] ]\n * → product = \"program\" AND (subjects = \"Leadership\" OR subjects = \"AI\")\n *\n * @param searchClient Algolia client from useAlgoliaSearch()\n * @param productType 'program' | 'course'\n * @param query Free-text query ('' = browse / rank by popularity)\n * @param activeTags Selected tag values from the filter chips\n * @param facetField Facet attribute to filter tags on (default: 'subjects')\n * @param hitsPerPage Page size\n * @param page 0-indexed page number (Algolia convention)\n * @param staticFacetFilters Additional 'attribute:value' filters always AND-ed in, e.g. ['b2c_subscription_inclusion:true']\n */\nexport const searchProducts = async (\n searchClient: SearchClient,\n productType: ProductType,\n query: string,\n activeTags: string[],\n facetField: string = FACET_SUBJECTS,\n hitsPerPage: number = HITS_PER_PAGE_COURSES,\n page = 0,\n staticFacetFilters: string[] = [],\n skill?: Skill,\n): Promise<AlgoliaSearchResult> => {\n const indexName = getAppConfig(appId).ALGOLIA_PRODUCT_INDEX_NAME as string;\n const tagFilters = formatFacetFilterData(facetField, activeTags);\n\n // Nested arrays = AND between outer elements, OR within inner arrays\n const facetFilters: string[][] = [\n [`product:${productType}`],\n ...(skill ? [[`skills.skill:${skill}`]] : []),\n ...(tagFilters.length > 0 ? [tagFilters] : []),\n ...staticFacetFilters.map((filter) => [filter]),\n ];\n\n try {\n const { hits, nbHits, nbPages } = await searchClient.searchSingleIndex({\n indexName,\n searchParams: {\n query,\n facetFilters,\n hitsPerPage,\n page,\n ...(skill ? { facets: ['skills.skill'] } : {}), // \"facets\" param sent to fetch Recommendations row courses\n },\n });\n\n return {\n hits: hits as AlgoliaProductHit[],\n nbHits: nbHits ?? 0,\n nbPages: nbPages ?? 0,\n };\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n logError(err);\n return { hits: [], nbHits: 0, nbPages: 0 };\n }\n};\n\n// ─── fetchPopularProducts ─────────────────────────────────────────────────────\n\n/**\n * Fetches top-ranked products with no query or tag filters.\n * Used for the \"Popular programs / courses\" fallback in the no-results state.\n *\n * @param searchClient Algolia client\n * @param productType 'program' | 'course'\n * @param hitsPerPage Number of items to fetch\n * @returns Raw Algolia hit objects\n */\nexport const fetchPopularProducts = async (\n searchClient: SearchClient,\n productType: ProductType,\n hitsPerPage: number,\n skill?: Skill,\n): Promise<AlgoliaProductHit[]> => {\n const { hits } = await searchProducts(\n searchClient,\n productType,\n '', // empty query → Algolia ranks by popularity\n [], // no tag filters\n FACET_SUBJECTS,\n hitsPerPage,\n 0,\n ['b2c_subscription_inclusion:true'],\n skill,\n );\n return hits;\n};\n"]}
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const DataRailSelection: React.FC;
3
+ export default DataRailSelection;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PROGRESSIVE_PROFILING_USER_STATUS } from '../../../widgets/ProgressiveProfilingQuiz/data/constants';
3
+ import { RecommendationsRailsPanel } from '../../../containers/RecommendationsRailsPanel';
4
+ import PopularCoursePanel from '../../../containers/PopularCoursePanel';
5
+ import PopularProgramsPanel from '../../../containers/PopularProgramsPanel';
6
+ import { useProgressiveProfilingQuiz } from '../ProgressiveProfilingQuizProvider';
7
+ const DataRailSelection = () => {
8
+ const { progressiveProfileStatus, } = useProgressiveProfilingQuiz();
9
+ if (!progressiveProfileStatus)
10
+ return null;
11
+ const { status } = progressiveProfileStatus || {};
12
+ if (status === PROGRESSIVE_PROFILING_USER_STATUS.COMPLETE) {
13
+ return _jsx(RecommendationsRailsPanel, {});
14
+ }
15
+ if (status !== PROGRESSIVE_PROFILING_USER_STATUS.COMPLETE) {
16
+ return (_jsxs(_Fragment, { children: [_jsx(PopularCoursePanel, {}), _jsx(PopularProgramsPanel, {})] }));
17
+ }
18
+ return null;
19
+ };
20
+ export default DataRailSelection;
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/widgets/ProgressiveProfilingQuiz/DataRailSelection/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,iCAAiC,EAAE,MAAM,sDAAsD,CAAC;AACzG,OAAO,EAAE,yBAAyB,EAAE,MAAM,+CAA+C,CAAC;AAC1F,OAAO,kBAAkB,MAAM,oCAAoC,CAAC;AACpE,OAAO,oBAAoB,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAElF,MAAM,iBAAiB,GAAa,GAAG,EAAE;IACvC,MAAM,EACJ,wBAAwB,GACzB,GAAG,2BAA2B,EAAE,CAAC;IAElC,IAAI,CAAC,wBAAwB;QAAE,OAAO,IAAI,CAAC;IAE3C,MAAM,EAAE,MAAM,EAAE,GAAG,wBAAwB,IAAI,EAAE,CAAC;IAElD,IAAI,MAAM,KAAK,iCAAiC,CAAC,QAAQ,EAAE,CAAC;QAC1D,OAAO,KAAC,yBAAyB,KAAG,CAAC;IACvC,CAAC;IAED,IAAI,MAAM,KAAK,iCAAiC,CAAC,QAAQ,EAAE,CAAC;QAC1D,OAAO,CACL,8BACE,KAAC,kBAAkB,KAAG,EACtB,KAAC,oBAAoB,KAAG,IACvB,CACJ,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,eAAe,iBAAiB,CAAC","sourcesContent":["import React from 'react';\nimport { PROGRESSIVE_PROFILING_USER_STATUS } from '@src/widgets/ProgressiveProfilingQuiz/data/constants';\nimport { RecommendationsRailsPanel } from '../../../containers/RecommendationsRailsPanel';\nimport PopularCoursePanel from '@src/containers/PopularCoursePanel';\nimport PopularProgramsPanel from '@src/containers/PopularProgramsPanel';\nimport { useProgressiveProfilingQuiz } from '../ProgressiveProfilingQuizProvider';\n\nconst DataRailSelection: React.FC = () => {\n const {\n progressiveProfileStatus,\n } = useProgressiveProfilingQuiz();\n\n if (!progressiveProfileStatus) return null;\n\n const { status } = progressiveProfileStatus || {};\n\n if (status === PROGRESSIVE_PROFILING_USER_STATUS.COMPLETE) {\n return <RecommendationsRailsPanel />;\n }\n\n if (status !== PROGRESSIVE_PROFILING_USER_STATUS.COMPLETE) {\n return (\n <>\n <PopularCoursePanel />\n <PopularProgramsPanel />\n </>\n );\n }\n return null;\n};\n\nexport default DataRailSelection;\n"]}
@@ -2,6 +2,7 @@ import { WidgetOperationTypes } from '@openedx/frontend-base';
2
2
  import { ProgressiveProfilingQuizProvider } from './ProgressiveProfilingQuizProvider';
3
3
  import ProgressiveProfilingQuizModal from './modal';
4
4
  import { BannerEntry } from './SearchPageBanners';
5
+ import DataRailSelection from './DataRailSelection';
5
6
  const app = {
6
7
  appId: 'org.2u-edx.frontend.app.progressiveProfiling',
7
8
  providers: [
@@ -21,6 +22,13 @@ const app = {
21
22
  op: WidgetOperationTypes.APPEND,
22
23
  component: BannerEntry,
23
24
  },
25
+ {
26
+ // This is for recommendations row slot, which is used in the search page also.
27
+ slotId: 'org.edx.frontend.widget.recommendations.v1',
28
+ id: 'org.edx.frontend.widget.progressiveProfiling.recommendations.v1',
29
+ op: WidgetOperationTypes.PREPEND,
30
+ component: DataRailSelection,
31
+ },
24
32
  ]
25
33
  };
26
34
  export default app;
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/widgets/ProgressiveProfilingQuiz/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,gCAAgC,EAAE,MAAM,oCAAoC,CAAC;AACtF,OAAO,6BAA6B,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,GAAG,GAAQ;IACf,KAAK,EAAE,8CAA8C;IACrD,SAAS,EAAE;QACT,gCAAgC;KACjC;IACD,KAAK,EAAE;QACL;YACE,MAAM,EAAE,0CAA0C;YAClD,EAAE,EAAE,uDAAuD;YAC3D,EAAE,EAAE,oBAAoB,CAAC,OAAO;YAChC,SAAS,EAAE,6BAA6B;SACzC;QACD;YACE,6DAA6D;YAC7D,MAAM,EAAE,4DAA4D;YACpE,EAAE,EAAE,kEAAkE;YACtE,EAAE,EAAE,oBAAoB,CAAC,MAAM;YAC/B,SAAS,EAAE,WAAW;SACvB;KACF;CACF,CAAC;AAEF,eAAe,GAAG,CAAC","sourcesContent":["import { App, WidgetOperationTypes } from '@openedx/frontend-base';\nimport { ProgressiveProfilingQuizProvider } from './ProgressiveProfilingQuizProvider';\nimport ProgressiveProfilingQuizModal from './modal';\nimport { BannerEntry } from './SearchPageBanners';\n\nconst app: App = {\n appId: 'org.2u-edx.frontend.app.progressiveProfiling',\n providers: [\n ProgressiveProfilingQuizProvider,\n ],\n slots: [\n {\n slotId: 'org.openedx.frontend.slot.header.main.v1',\n id: 'org.edx.frontend.widget.progressiveProfiling.modal.v1',\n op: WidgetOperationTypes.PREPEND,\n component: ProgressiveProfilingQuizModal,\n },\n {\n // This is the entry-point CTA injected into search page slot\n slotId: 'org.edx.frontend.widget.progressiveProfiling.search.cta.v1',\n id: 'org.edx.frontend.widget.progressiveProfiling.search.cta.entry.v1',\n op: WidgetOperationTypes.APPEND,\n component: BannerEntry,\n },\n ]\n};\n\nexport default app;\n"]}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/widgets/ProgressiveProfilingQuiz/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,gCAAgC,EAAE,MAAM,oCAAoC,CAAC;AACtF,OAAO,6BAA6B,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAEpD,MAAM,GAAG,GAAQ;IACf,KAAK,EAAE,8CAA8C;IACrD,SAAS,EAAE;QACT,gCAAgC;KACjC;IACD,KAAK,EAAE;QACL;YACE,MAAM,EAAE,0CAA0C;YAClD,EAAE,EAAE,uDAAuD;YAC3D,EAAE,EAAE,oBAAoB,CAAC,OAAO;YAChC,SAAS,EAAE,6BAA6B;SACzC;QACD;YACE,6DAA6D;YAC7D,MAAM,EAAE,4DAA4D;YACpE,EAAE,EAAE,kEAAkE;YACtE,EAAE,EAAE,oBAAoB,CAAC,MAAM;YAC/B,SAAS,EAAE,WAAW;SACvB;QACD;YACE,+EAA+E;YAC/E,MAAM,EAAE,4CAA4C;YACpD,EAAE,EAAE,iEAAiE;YACrE,EAAE,EAAE,oBAAoB,CAAC,OAAO;YAChC,SAAS,EAAE,iBAAiB;SAC7B;KACF;CACF,CAAC;AAEF,eAAe,GAAG,CAAC","sourcesContent":["import { App, WidgetOperationTypes } from '@openedx/frontend-base';\nimport { ProgressiveProfilingQuizProvider } from './ProgressiveProfilingQuizProvider';\nimport ProgressiveProfilingQuizModal from './modal';\nimport { BannerEntry } from './SearchPageBanners';\nimport DataRailSelection from './DataRailSelection';\n\nconst app: App = {\n appId: 'org.2u-edx.frontend.app.progressiveProfiling',\n providers: [\n ProgressiveProfilingQuizProvider,\n ],\n slots: [\n {\n slotId: 'org.openedx.frontend.slot.header.main.v1',\n id: 'org.edx.frontend.widget.progressiveProfiling.modal.v1',\n op: WidgetOperationTypes.PREPEND,\n component: ProgressiveProfilingQuizModal,\n },\n {\n // This is the entry-point CTA injected into search page slot\n slotId: 'org.edx.frontend.widget.progressiveProfiling.search.cta.v1',\n id: 'org.edx.frontend.widget.progressiveProfiling.search.cta.entry.v1',\n op: WidgetOperationTypes.APPEND,\n component: BannerEntry,\n },\n {\n // This is for recommendations row slot, which is used in the search page also.\n slotId: 'org.edx.frontend.widget.recommendations.v1',\n id: 'org.edx.frontend.widget.progressiveProfiling.recommendations.v1',\n op: WidgetOperationTypes.PREPEND,\n component: DataRailSelection,\n },\n ]\n};\n\nexport default app;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edx/frontend-app-subscription-learner-dashboard",
3
- "version": "1.53.2",
3
+ "version": "1.55.0",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",