@edx/frontend-app-subscription-learner-dashboard 1.17.0 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/containers/Dashboard/DashboardHeader.d.ts +3 -0
- package/dist/containers/Dashboard/DashboardHeader.js +10 -0
- package/dist/containers/Dashboard/DashboardHeader.js.map +1 -0
- package/dist/containers/Dashboard/index.js +8 -4
- package/dist/containers/Dashboard/index.js.map +1 -1
- package/dist/containers/Dashboard/index.scss +12 -1
- package/dist/containers/Dashboard/messages.d.ts +10 -0
- package/dist/containers/Dashboard/messages.js +10 -0
- package/dist/containers/Dashboard/messages.js.map +1 -1
- package/dist/containers/PopularCoursePanel/NoPopularCourseItems/index.d.ts +3 -0
- package/dist/containers/PopularCoursePanel/NoPopularCourseItems/index.js +9 -0
- package/dist/containers/PopularCoursePanel/NoPopularCourseItems/index.js.map +1 -0
- package/dist/containers/{RecentlyViewedPanel/NoRecentlyViewedItems → PopularCoursePanel/NoPopularCourseItems}/messages.d.ts +1 -1
- package/dist/containers/PopularCoursePanel/NoPopularCourseItems/messages.js +10 -0
- package/dist/containers/PopularCoursePanel/NoPopularCourseItems/messages.js.map +1 -0
- package/dist/containers/PopularCoursePanel/PopularCourses/index.d.ts +4 -0
- package/dist/containers/{RecentlyViewedPanel/RecentlyViewedCourseProgram → PopularCoursePanel/PopularCourses}/index.js +3 -3
- package/dist/containers/PopularCoursePanel/PopularCourses/index.js.map +1 -0
- package/dist/containers/PopularCoursePanel/index.d.ts +3 -0
- package/dist/containers/PopularCoursePanel/index.js +21 -0
- package/dist/containers/PopularCoursePanel/index.js.map +1 -0
- package/dist/containers/{RecentlyViewedPanel → PopularCoursePanel}/messages.d.ts +2 -2
- package/dist/containers/PopularCoursePanel/messages.js +15 -0
- package/dist/containers/PopularCoursePanel/messages.js.map +1 -0
- package/dist/containers/ProductCard/index.d.ts +1 -1
- package/dist/containers/ProductCard/index.js +7 -6
- package/dist/containers/ProductCard/index.js.map +1 -1
- package/dist/containers/ProductCard/index.scss +17 -6
- package/dist/containers/ProductCard/messages.d.ts +13 -0
- package/dist/containers/ProductCard/messages.js +15 -0
- package/dist/containers/ProductCard/messages.js.map +1 -0
- package/dist/hooks/{useRecentlyViewedCoursesAndProgramsData.d.ts → usePopularCourses.d.ts} +1 -1
- package/dist/hooks/{useRecentlyViewedCoursesAndProgramsData.js → usePopularCourses.js} +7 -4
- package/dist/hooks/usePopularCourses.js.map +1 -0
- package/package.json +1 -1
- package/dist/containers/RecentlyViewedPanel/NoRecentlyViewedItems/index.d.ts +0 -3
- package/dist/containers/RecentlyViewedPanel/NoRecentlyViewedItems/index.js +0 -9
- package/dist/containers/RecentlyViewedPanel/NoRecentlyViewedItems/index.js.map +0 -1
- package/dist/containers/RecentlyViewedPanel/NoRecentlyViewedItems/messages.js +0 -10
- package/dist/containers/RecentlyViewedPanel/NoRecentlyViewedItems/messages.js.map +0 -1
- package/dist/containers/RecentlyViewedPanel/RecentlyViewedCourseProgram/index.d.ts +0 -4
- package/dist/containers/RecentlyViewedPanel/RecentlyViewedCourseProgram/index.js.map +0 -1
- package/dist/containers/RecentlyViewedPanel/index.d.ts +0 -3
- package/dist/containers/RecentlyViewedPanel/index.js +0 -21
- package/dist/containers/RecentlyViewedPanel/index.js.map +0 -1
- package/dist/containers/RecentlyViewedPanel/messages.js +0 -15
- package/dist/containers/RecentlyViewedPanel/messages.js.map +0 -1
- package/dist/hooks/useRecentlyViewedCoursesAndProgramsData.js.map +0 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
3
|
+
import messages from './messages';
|
|
4
|
+
import { dateFormatter } from '../../utils/dateFormatter';
|
|
5
|
+
export const DashboardHeader = ({ startDate }) => {
|
|
6
|
+
const { formatMessage, formatDate } = useIntl();
|
|
7
|
+
const formattedDate = startDate ? dateFormatter(formatDate, startDate, 'long') : '';
|
|
8
|
+
return (_jsxs("div", { className: "my-4.5", children: [_jsx("h2", { className: "font-weight-bold mb-3 dashboard-header-title", "data-testid": "dashboard-header-title", children: formatMessage(messages.dashboardHeaderWelcomeTitle) }), startDate ? (_jsx("p", { className: "mb-0 text-body dashboard-header-subtitle", "data-testid": "dashboard-header-subtitle", children: formatMessage(messages.dashboardHeaderWelcomeMessage, { startDate: formattedDate || '' }) })) : null] }));
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=DashboardHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardHeader.js","sourceRoot":"","sources":["../../../src/containers/Dashboard/DashboardHeader.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,MAAM,CAAC,MAAM,eAAe,GAA6B,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;IACzE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAAC;IAChD,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEpF,OAAO,CACL,eAAK,SAAS,EAAC,QAAQ,aACrB,aAAI,SAAS,EAAC,8CAA8C,iBAAa,wBAAwB,YAC9F,aAAa,CAAC,QAAQ,CAAC,2BAA2B,CAAC,GACjD,EACJ,SAAS,CAAC,CAAC,CAAC,CACX,YAAG,SAAS,EAAC,0CAA0C,iBAAa,2BAA2B,YAC5F,aAAa,CAAC,QAAQ,CAAC,6BAA6B,EAAE,EAAE,SAAS,EAAE,aAAa,IAAI,EAAE,EAAE,CAAC,GACxF,CACL,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { FC } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport messages from './messages';\nimport type { DashboardHeaderProps } from './data/types';\nimport { dateFormatter } from '@src/utils/dateFormatter';\n\nexport const DashboardHeader: FC<DashboardHeaderProps> = ({ startDate }) => {\n const { formatMessage, formatDate } = useIntl();\n const formattedDate = startDate ? dateFormatter(formatDate, startDate, 'long') : '';\n\n return (\n <div className=\"my-4.5\">\n <h2 className=\"font-weight-bold mb-3 dashboard-header-title\" data-testid=\"dashboard-header-title\">\n {formatMessage(messages.dashboardHeaderWelcomeTitle)}\n </h2>\n {startDate ? (\n <p className=\"mb-0 text-body dashboard-header-subtitle\" data-testid=\"dashboard-header-subtitle\">\n {formatMessage(messages.dashboardHeaderWelcomeMessage, { startDate: formattedDate || '' })}\n </p>\n ) : null}\n </div>\n );\n};\n"]}
|
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
|
+
import { DashboardHeader } from './DashboardHeader';
|
|
3
4
|
import { useSelectSessionModal } from '../../data/context';
|
|
4
5
|
import { useInitializeSubsCourseDashboard } from '../../data/hooks';
|
|
5
6
|
import SelectSessionModal from '../../containers/SelectSessionModal';
|
|
6
7
|
import { DashboardContent } from './DashboardContent';
|
|
7
8
|
import DashboardModalSlot from '../../slots/DashboardModalSlot';
|
|
8
|
-
import
|
|
9
|
+
import PopularCoursePanel from '../PopularCoursePanel';
|
|
9
10
|
import LoadingView from './LoadingView';
|
|
10
11
|
import DashboardLayout from './DashboardLayout';
|
|
11
12
|
import hooks from './hooks';
|
|
12
13
|
import './index.scss';
|
|
13
14
|
import { SubscriptionBanner } from '../SubscriptionBanner';
|
|
14
15
|
import { DashboardTitle } from './DashboardTitle';
|
|
16
|
+
import { useInitializeSubsDashboard } from '../../data/hooks';
|
|
15
17
|
export const Dashboard = () => {
|
|
16
|
-
var _a, _b;
|
|
18
|
+
var _a, _b, _c;
|
|
17
19
|
const { data, isPending } = useInitializeSubsCourseDashboard();
|
|
20
|
+
const { data: learnerData } = useInitializeSubsDashboard();
|
|
18
21
|
const { pageTitle } = hooks.useDashboardMessages();
|
|
19
22
|
const { selectSessionModal } = useSelectSessionModal();
|
|
20
23
|
const showSelectSessionModal = selectSessionModal.cardId !== null;
|
|
24
|
+
const userSubscriptionStartDate = ((_a = learnerData === null || learnerData === void 0 ? void 0 : learnerData.userSubscription) === null || _a === void 0 ? void 0 : _a.subscriptionStartDate) || '';
|
|
21
25
|
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]);
|
|
22
|
-
const hasCourseHistory = ((
|
|
26
|
+
const hasCourseHistory = ((_c = (_b = data === null || data === void 0 ? void 0 : data.nonUpgradeableCourses) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 0;
|
|
23
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: isPending
|
|
24
28
|
? (_jsx(LoadingView, {}))
|
|
25
|
-
: (_jsxs(DashboardLayout, { children: [_jsx(SubscriptionBanner, {}), _jsx(DashboardTitle, {}), _jsx(DashboardContent, { hasCourseHistory: hasCourseHistory }), _jsx(
|
|
29
|
+
: (_jsxs(DashboardLayout, { children: [_jsx(DashboardHeader, { startDate: userSubscriptionStartDate }), _jsx(SubscriptionBanner, {}), _jsx(DashboardTitle, {}), _jsx(DashboardContent, { hasCourseHistory: hasCourseHistory }), _jsx(PopularCoursePanel, {})] })) })] }) }) }));
|
|
26
30
|
};
|
|
27
31
|
export default Dashboard;
|
|
28
32
|
//# 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;
|
|
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;AAEvD,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,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,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE7D,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE;;IAC5B,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,gCAAgC,EAAE,CAAC;IAC/D,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,yBAAyB,GAAG,CAAA,MAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,gBAAgB,0CAAE,qBAAqB,KAAI,EAAE,CAAC;IAE7F,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;IAChF,MAAM,gBAAgB,GAAG,CAAC,MAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,qBAAqB,0CAAE,MAAM,mCAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAExE,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,YACxD,SAAS;4BACR,CAAC,CAAC,CAAC,KAAC,WAAW,KAAG,CAAC;4BACnB,CAAC,CAAC,CACA,MAAC,eAAe,eACd,KAAC,eAAe,IAAC,SAAS,EAAE,yBAAyB,GAAI,EACzD,KAAC,kBAAkB,KAAG,EACtB,KAAC,cAAc,KAAG,EAClB,KAAC,gBAAgB,IAAC,gBAAgB,EAAE,gBAAgB,GAAI,EACxD,KAAC,kBAAkB,KAAG,IACN,CACnB,GACC,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';\n\nimport LoadingView from './LoadingView';\nimport DashboardLayout from './DashboardLayout';\n\nimport hooks from './hooks';\nimport './index.scss';\nimport { SubscriptionBanner } from '../SubscriptionBanner';\nimport { DashboardTitle } from './DashboardTitle';\nimport { useInitializeSubsDashboard } from '@src/data/hooks';\n\nexport const Dashboard = () => {\n const { data, isPending } = useInitializeSubsCourseDashboard();\n const { data: learnerData } = useInitializeSubsDashboard();\n const { pageTitle } = hooks.useDashboardMessages();\n const { selectSessionModal } = useSelectSessionModal();\n const showSelectSessionModal = selectSessionModal.cardId !== null;\n const userSubscriptionStartDate = learnerData?.userSubscription?.subscriptionStartDate || '';\n\n const hasCourses = useMemo(() => data?.subscriptionCourses?.length > 0, [data]);\n const hasCourseHistory = (data?.nonUpgradeableCourses?.length ?? 0) > 0;\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 {isPending\n ? (<LoadingView />)\n : (\n <DashboardLayout>\n <DashboardHeader startDate={userSubscriptionStartDate} />\n <SubscriptionBanner />\n <DashboardTitle />\n <DashboardContent hasCourseHistory={hasCourseHistory} />\n <PopularCoursePanel />\n </DashboardLayout>\n )}\n </div>\n </div>\n </main>\n </div>\n );\n};\n\nexport default Dashboard;\n"]}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
@use "@openedx/paragon/styles/css/core/custom-media-breakpoints.css";
|
|
2
|
+
$title-color: #002B2B !default;
|
|
3
|
+
$subtitle-color: #454545 !default;
|
|
2
4
|
|
|
3
5
|
.course-list-column {
|
|
4
6
|
padding: 0 var(--pgn-spacing-spacer-4);
|
|
5
|
-
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.dashboard-header-title {
|
|
10
|
+
color: $title-color;
|
|
11
|
+
font-size: var(--pgn-typography-font-size-h3-base);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.dashboard-header-subtitle {
|
|
15
|
+
color: $subtitle-color;
|
|
16
|
+
}
|
|
@@ -9,5 +9,15 @@ declare const messages: {
|
|
|
9
9
|
defaultMessage: string;
|
|
10
10
|
description: string;
|
|
11
11
|
};
|
|
12
|
+
dashboardHeaderWelcomeTitle: {
|
|
13
|
+
id: string;
|
|
14
|
+
defaultMessage: string;
|
|
15
|
+
description: string;
|
|
16
|
+
};
|
|
17
|
+
dashboardHeaderWelcomeMessage: {
|
|
18
|
+
id: string;
|
|
19
|
+
defaultMessage: string;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
12
22
|
};
|
|
13
23
|
export default messages;
|
|
@@ -10,6 +10,16 @@ const messages = defineMessages({
|
|
|
10
10
|
defaultMessage: 'Your home for all of your future learning with edX Unlimited.',
|
|
11
11
|
description: 'Subtitle for the subscriber dashboard',
|
|
12
12
|
},
|
|
13
|
+
dashboardHeaderWelcomeTitle: {
|
|
14
|
+
id: 'Dashboard.Header.Welcome.Title',
|
|
15
|
+
defaultMessage: 'Welcome to your learning home.',
|
|
16
|
+
description: 'Welcome message for the subscriber dashboard',
|
|
17
|
+
},
|
|
18
|
+
dashboardHeaderWelcomeMessage: {
|
|
19
|
+
id: 'Dashboard.Header.Welcome.Message',
|
|
20
|
+
defaultMessage: 'Subscriber since {startDate}.',
|
|
21
|
+
description: 'Additional content for the subscriber dashboard',
|
|
22
|
+
},
|
|
13
23
|
});
|
|
14
24
|
export default messages;
|
|
15
25
|
//# sourceMappingURL=messages.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/containers/Dashboard/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,cAAc,EAAE;QACd,EAAE,EAAE,iBAAiB;QACrB,cAAc,EAAE,sBAAsB;QACtC,WAAW,EAAE,oCAAoC;KAClD;IACD,iBAAiB,EAAE;QACjB,EAAE,EAAE,oBAAoB;QACxB,cAAc,EAAE,+DAA+D;QAC/E,WAAW,EAAE,uCAAuC;KACrD;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n dashboardTitle: {\n id: 'Dashboard.Title',\n defaultMessage: 'Subscriber Dashboard',\n description: 'Title for the subscriber dashboard',\n },\n dashboardSubtitle: {\n id: 'Dashboard.Subtitle',\n defaultMessage: 'Your home for all of your future learning with edX Unlimited.',\n description: 'Subtitle for the subscriber dashboard',\n },\n});\n\nexport default messages;\n"]}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/containers/Dashboard/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,cAAc,EAAE;QACd,EAAE,EAAE,iBAAiB;QACrB,cAAc,EAAE,sBAAsB;QACtC,WAAW,EAAE,oCAAoC;KAClD;IACD,iBAAiB,EAAE;QACjB,EAAE,EAAE,oBAAoB;QACxB,cAAc,EAAE,+DAA+D;QAC/E,WAAW,EAAE,uCAAuC;KACrD;IACD,2BAA2B,EAAE;QAC3B,EAAE,EAAE,gCAAgC;QACpC,cAAc,EAAE,gCAAgC;QAChD,WAAW,EAAE,8CAA8C;KAC5D;IACD,6BAA6B,EAAE;QAC7B,EAAE,EAAE,kCAAkC;QACtC,cAAc,EAAE,+BAA+B;QAC/C,WAAW,EAAE,iDAAiD;KAC/D;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n dashboardTitle: {\n id: 'Dashboard.Title',\n defaultMessage: 'Subscriber Dashboard',\n description: 'Title for the subscriber dashboard',\n },\n dashboardSubtitle: {\n id: 'Dashboard.Subtitle',\n defaultMessage: 'Your home for all of your future learning with edX Unlimited.',\n description: 'Subtitle for the subscriber dashboard',\n },\n dashboardHeaderWelcomeTitle: {\n id: 'Dashboard.Header.Welcome.Title',\n defaultMessage: 'Welcome to your learning home.',\n description: 'Welcome message for the subscriber dashboard',\n },\n dashboardHeaderWelcomeMessage: {\n id: 'Dashboard.Header.Welcome.Message',\n defaultMessage: 'Subscriber since {startDate}.',\n description: 'Additional content for the subscriber dashboard',\n },\n});\n\nexport default messages;\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
3
|
+
import messages from './messages';
|
|
4
|
+
const NoPopularCourseItems = () => {
|
|
5
|
+
const { formatMessage } = useIntl();
|
|
6
|
+
return (_jsx("div", { "data-testid": "no-popular-course-items", children: _jsx("p", { className: "mb-0", children: formatMessage(messages.popularCourseEmptyState) }) }));
|
|
7
|
+
};
|
|
8
|
+
export default NoPopularCourseItems;
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/containers/PopularCoursePanel/NoPopularCourseItems/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,oBAAoB,GAAO,GAAG,EAAE;IACpC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IAEpC,OAAO,CACL,6BAAiB,yBAAyB,YACxC,YAAG,SAAS,EAAC,MAAM,YAAE,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC,GAAK,GACrE,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,oBAAoB,CAAC","sourcesContent":["import { FC } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\n\nimport messages from './messages';\n\nconst NoPopularCourseItems: FC = () => {\n const { formatMessage } = useIntl();\n\n return (\n <div data-testid=\"no-popular-course-items\">\n <p className=\"mb-0\">{formatMessage(messages.popularCourseEmptyState)}</p>\n </div>\n );\n};\n\nexport default NoPopularCourseItems;\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineMessages } from '@openedx/frontend-base';
|
|
2
|
+
const messages = defineMessages({
|
|
3
|
+
popularCourseEmptyState: {
|
|
4
|
+
id: 'subs-dash.popularCoursePanel.emptyState',
|
|
5
|
+
defaultMessage: 'When you browse the edX Unlimited catalog, we\'ll show popular courses here.',
|
|
6
|
+
description: 'Placeholder text for popular courses section',
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
export default messages;
|
|
10
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../../src/containers/PopularCoursePanel/NoPopularCourseItems/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,uBAAuB,EAAE;QACvB,EAAE,EAAE,yCAAyC;QAC7C,cAAc,EAAE,8EAA8E;QAC9F,WAAW,EAAE,8CAA8C;KAC5D;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n popularCourseEmptyState: {\n id: 'subs-dash.popularCoursePanel.emptyState',\n defaultMessage: 'When you browse the edX Unlimited catalog, we\\'ll show popular courses here.',\n description: 'Placeholder text for popular courses section',\n }\n});\n\nexport default messages;\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { ProductCard } from '../../ProductCard';
|
|
3
|
-
export const
|
|
4
|
-
return (_jsx("div", { "data-testid": "
|
|
3
|
+
export const PopularCourses = ({ items, isLoading }) => {
|
|
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, isLoading: isLoading }) }, item.objectID))) }) }));
|
|
5
5
|
};
|
|
6
|
-
export default
|
|
6
|
+
export default PopularCourses;
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/containers/PopularCoursePanel/PopularCourses/index.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,MAAM,CAAC,MAAM,cAAc,GAA4B,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE;IAC9E,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,EAAE,SAAS,EAAE,SAAS,GAAI,IADzC,IAAI,CAAC,QAAQ,CAEjB,CACP,CAAC,GACE,GACF,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["import { FC } from 'react';\n\nimport { ProductCard } from '../../ProductCard';\nimport { PopularCoursesProps } from './data/types';\n\nexport const PopularCourses: FC<PopularCoursesProps> = ({ items, isLoading }) => {\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} isLoading={isLoading} />\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport default PopularCourses;\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { Alert } from '@openedx/paragon';
|
|
4
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
+
import { usePopularCoursesData } from '../../hooks/usePopularCourses';
|
|
6
|
+
import { useAlgoliaSearch } from '../../utils/algoliaUtils';
|
|
7
|
+
import messages from './messages';
|
|
8
|
+
import NoPopularCourseItems from './NoPopularCourseItems';
|
|
9
|
+
import PopularCourses from './PopularCourses';
|
|
10
|
+
export const PopularCoursePanel = () => {
|
|
11
|
+
const { formatMessage } = useIntl();
|
|
12
|
+
const [searchClient] = useAlgoliaSearch();
|
|
13
|
+
const { data: popularCoursesData = [], isError, isLoading, } = usePopularCoursesData(searchClient, true);
|
|
14
|
+
const hasPopularCoursesData = useMemo(() => popularCoursesData.length > 0, [popularCoursesData]);
|
|
15
|
+
if (isError) {
|
|
16
|
+
return (_jsx("div", { className: "popular-courses-container mt-5 mb-3", "data-testid": "popular-courses-panel", children: _jsx(Alert, { variant: "danger", "data-testid": "popular-courses-error", children: formatMessage(messages.popularCoursesErrorText) }) }));
|
|
17
|
+
}
|
|
18
|
+
return (_jsxs("div", { className: "popular-courses-container mt-5 mb-3", "data-testid": "popular-courses-panel", children: [_jsx("div", { className: "popular-courses-heading-container mb-4", children: _jsx("h2", { children: formatMessage(messages.popularCoursesHeader) }) }), (isLoading || hasPopularCoursesData) ? (_jsx(PopularCourses, { items: popularCoursesData, isLoading: isLoading })) : (_jsx(NoPopularCourseItems, {}))] }));
|
|
19
|
+
};
|
|
20
|
+
export default PopularCoursePanel;
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/containers/PopularCoursePanel/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAM,OAAO,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,oBAAoB,MAAM,wBAAwB,CAAC;AAC1D,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C,MAAM,CAAC,MAAM,kBAAkB,GAAO,GAAG,EAAE;IACzC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,CAAC,YAAY,CAAC,GAAG,gBAAgB,EAAE,CAAC;IAC1C,MAAM,EACJ,IAAI,EAAE,kBAAkB,GAAG,EAAE,EAC7B,OAAO,EACP,SAAS,GACV,GAAG,qBAAqB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,qBAAqB,GAAG,OAAO,CACnC,GAAG,EAAE,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,EACnC,CAAC,kBAAkB,CAAC,CACrB,CAAC;IAEF,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CACL,cAAK,SAAS,EAAC,qCAAqC,iBAAa,uBAAuB,YACtF,KAAC,KAAK,IAAC,OAAO,EAAC,QAAQ,iBAAa,uBAAuB,YACxD,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC,GAC1C,GACJ,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAC,qCAAqC,iBAAa,uBAAuB,aACtF,cAAK,SAAS,EAAC,wCAAwC,YACrD,uBAAK,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,GAAM,GACnD,EACL,CAAC,SAAS,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAC,CACtC,KAAC,cAAc,IACb,KAAK,EAAE,kBAAkB,EACzB,SAAS,EAAE,SAAS,GACpB,CACH,CAAC,CAAC,CAAC,CACF,KAAC,oBAAoB,KAAG,CACzB,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,kBAAkB,CAAC","sourcesContent":["import { FC, useMemo } from 'react';\nimport { Alert } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\n\nimport { usePopularCoursesData } from '@src/hooks/usePopularCourses';\nimport { useAlgoliaSearch } from '@src/utils/algoliaUtils';\nimport messages from './messages';\nimport NoPopularCourseItems from './NoPopularCourseItems';\nimport PopularCourses from './PopularCourses';\n\nexport const PopularCoursePanel: FC = () => {\n const { formatMessage } = useIntl();\n const [searchClient] = useAlgoliaSearch();\n const {\n data: popularCoursesData = [],\n isError,\n isLoading,\n } = usePopularCoursesData(searchClient, true);\n const hasPopularCoursesData = useMemo(\n () => popularCoursesData.length > 0,\n [popularCoursesData]\n );\n\n if (isError) {\n return (\n <div className=\"popular-courses-container mt-5 mb-3\" data-testid=\"popular-courses-panel\">\n <Alert variant=\"danger\" data-testid=\"popular-courses-error\">\n {formatMessage(messages.popularCoursesErrorText)}\n </Alert>\n </div>\n );\n }\n\n return (\n <div className=\"popular-courses-container mt-5 mb-3\" data-testid=\"popular-courses-panel\">\n <div className=\"popular-courses-heading-container mb-4\">\n <h2>{formatMessage(messages.popularCoursesHeader)}</h2>\n </div>\n {(isLoading || hasPopularCoursesData) ? (\n <PopularCourses\n items={popularCoursesData}\n isLoading={isLoading}\n />\n ) : (\n <NoPopularCourseItems />\n )}\n </div>\n );\n};\n\nexport default PopularCoursePanel;\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
declare const messages: {
|
|
2
|
-
|
|
2
|
+
popularCoursesHeader: {
|
|
3
3
|
id: string;
|
|
4
4
|
defaultMessage: string;
|
|
5
5
|
description: string;
|
|
6
6
|
};
|
|
7
|
-
|
|
7
|
+
popularCoursesErrorText: {
|
|
8
8
|
id: string;
|
|
9
9
|
defaultMessage: string;
|
|
10
10
|
description: string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineMessages } from '@openedx/frontend-base';
|
|
2
|
+
const messages = defineMessages({
|
|
3
|
+
popularCoursesHeader: {
|
|
4
|
+
id: 'subs-dash.popularCoursesPanel.header',
|
|
5
|
+
defaultMessage: 'Popular courses',
|
|
6
|
+
description: 'Label for the popular courses section',
|
|
7
|
+
},
|
|
8
|
+
popularCoursesErrorText: {
|
|
9
|
+
id: 'subs-dash.popularCoursesPanel.errorText',
|
|
10
|
+
defaultMessage: 'Failed to load popular courses. Please try again later.',
|
|
11
|
+
description: 'Error text for failing to load popular courses',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
export default messages;
|
|
15
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/containers/PopularCoursePanel/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,oBAAoB,EAAE;QACpB,EAAE,EAAE,sCAAsC;QAC1C,cAAc,EAAE,iBAAiB;QACjC,WAAW,EAAE,uCAAuC;KACrD;IACD,uBAAuB,EAAE;QACvB,EAAE,EAAE,yCAAyC;QAC7C,cAAc,EAAE,yDAAyD;QACzE,WAAW,EAAE,gDAAgD;KAC9D;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n popularCoursesHeader: {\n id: 'subs-dash.popularCoursesPanel.header',\n defaultMessage: 'Popular courses',\n description: 'Label for the popular courses section',\n },\n popularCoursesErrorText: {\n id: 'subs-dash.popularCoursesPanel.errorText',\n defaultMessage: 'Failed to load popular courses. Please try again later.',\n description: 'Error text for failing to load popular courses',\n },\n});\n\nexport default messages;\n"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { useIntl } from '@openedx/frontend-base';
|
|
3
|
+
import { Card, Icon } from '@openedx/paragon';
|
|
4
|
+
import { Timelapse, Speed } from '@openedx/paragon/icons';
|
|
4
5
|
import './index.scss';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const truncateText = (value, maxLength) => (value.length > maxLength ? `${value.slice(0, maxLength).trimEnd()}...` : value);
|
|
6
|
+
import cardFallbackImg from '@openedx/brand-openedx/paragon/images/card-imagecap-fallback.png';
|
|
7
|
+
import messages from './messages';
|
|
8
8
|
export const ProductCard = ({ item, isLoading }) => {
|
|
9
|
-
|
|
9
|
+
const { formatMessage } = useIntl();
|
|
10
|
+
return (_jsxs(Card, { className: "shadow-sm d-flex flex-column rounded w-100 overflow-hidden card-container", variant: item.product === 'Course' ? 'light' : 'dark', "data-testid": "product-card", isLoading: isLoading, children: [_jsx(Card.Header, { title: item.content_type, className: "pb-2 pt-2 bg-light-500 text-primary-500 content-type", size: "xs" }), _jsx("div", { className: "position-relative image-container", children: _jsx(Card.ImageCap, { src: item.url || cardFallbackImg, srcAlt: `${item.title} main-image`, "data-testid": "product-card-image", logoSrc: item.thumbnail || '', logoAlt: `${item.title} thumbnail-image` }) }), _jsx(Card.Header, { title: item.title, size: "sm", className: "product-card-title" }), item.partner ? (_jsx(Card.Header, { title: item.partner, className: "d-flex justify-content-between align-items-center", size: "xs" })) : null, _jsxs(Card.Section, { className: "d-flex flex-column flex-grow-1 overflow-hidden mt-5", children: [typeof item.weeks_to_complete === 'number' && (_jsxs("span", { className: "d-flex align-items-center", children: [_jsx(Icon, { src: Timelapse, className: "mr-2" }), _jsx("span", { children: formatMessage(messages.weeksToComplete, { count: item.weeks_to_complete }) })] })), item.level ? (_jsxs("span", { className: `d-flex align-items-center${typeof item.weeks_to_complete === 'number' ? ' mt-3' : ''}`, children: [_jsx(Icon, { src: Speed, className: "mr-2" }), _jsx("span", { children: formatMessage(messages.level, { level: item.level }) })] })) : null] })] }));
|
|
10
11
|
};
|
|
11
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/containers/ProductCard/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/containers/ProductCard/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,cAAc,CAAC;AACtB,OAAO,eAAe,MAAM,kEAAkE,CAAC;AAE/F,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,CAAC,MAAM,WAAW,GAAyB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;IACvE,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,OAAO,CACL,MAAC,IAAI,IACH,SAAS,EAAC,2EAA2E,EACrF,OAAO,EAAE,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,iBACzC,cAAc,EAC1B,SAAS,EAAE,SAAS,aAEpB,KAAC,IAAI,CAAC,MAAM,IAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,EAAC,sDAAsD,EAAC,IAAI,EAAC,IAAI,GAAG,EAEpH,cAAK,SAAS,EAAC,mCAAmC,YAChD,KAAC,IAAI,CAAC,QAAQ,IACZ,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,eAAe,EAChC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,aAAa,iBACtB,oBAAoB,EAChC,OAAO,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE,EAC7B,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,kBAAkB,GACxC,GACE,EAEN,KAAC,IAAI,CAAC,MAAM,IAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAC,IAAI,EAAC,SAAS,EAAC,oBAAoB,GAAG,EAE1E,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CACd,KAAC,IAAI,CAAC,MAAM,IAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,EAAC,mDAAmD,EAAC,IAAI,EAAC,IAAI,GAAG,CAC7G,CAAC,CAAC,CAAC,IAAI,EAER,MAAC,IAAI,CAAC,OAAO,IAAC,SAAS,EAAC,qDAAqD,aAC1E,OAAO,IAAI,CAAC,iBAAiB,KAAK,QAAQ,IAAI,CAC7C,gBAAM,SAAS,EAAC,2BAA2B,aACzC,KAAC,IAAI,IAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAC,MAAM,GAAG,EACzC,yBAAO,aAAa,CAAC,QAAQ,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC,GAAQ,IACpF,CACR,EACA,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CACZ,gBAAM,SAAS,EAAE,4BAA4B,OAAO,IAAI,CAAC,iBAAiB,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,aACtG,KAAC,IAAI,IAAC,GAAG,EAAE,KAAK,EAAE,SAAS,EAAC,MAAM,GAAG,EACrC,yBAAO,aAAa,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,GAAQ,IAC9D,CACR,CAAC,CAAC,CAAC,IAAI,IACK,IAEV,CACR,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { FC } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Card, Icon } from '@openedx/paragon';\nimport { Timelapse, Speed } from '@openedx/paragon/icons';\nimport './index.scss';\nimport cardFallbackImg from '@openedx/brand-openedx/paragon/images/card-imagecap-fallback.png';\nimport { ProductCardProps } from './data/types';\nimport messages from './messages';\n\nexport const ProductCard: FC<ProductCardProps> = ({ item, isLoading }) => {\n const { formatMessage } = useIntl();\n return (\n <Card\n className=\"shadow-sm d-flex flex-column rounded w-100 overflow-hidden card-container\"\n variant={item.product === 'Course' ? 'light' : 'dark'}\n data-testid=\"product-card\"\n isLoading={isLoading}\n >\n <Card.Header title={item.content_type} className=\"pb-2 pt-2 bg-light-500 text-primary-500 content-type\" size=\"xs\" />\n\n <div className=\"position-relative image-container\">\n <Card.ImageCap\n src={item.url || cardFallbackImg}\n srcAlt={`${item.title} main-image`}\n data-testid=\"product-card-image\"\n logoSrc={item.thumbnail || ''}\n logoAlt={`${item.title} thumbnail-image`}\n />\n </div>\n\n <Card.Header title={item.title} size=\"sm\" className=\"product-card-title\" />\n\n {item.partner ? (\n <Card.Header title={item.partner} className=\"d-flex justify-content-between align-items-center\" size=\"xs\" />\n ) : null}\n\n <Card.Section className=\"d-flex flex-column flex-grow-1 overflow-hidden mt-5\">\n {typeof item.weeks_to_complete === 'number' && (\n <span className=\"d-flex align-items-center\">\n <Icon src={Timelapse} className=\"mr-2\" />\n <span>{formatMessage(messages.weeksToComplete, { count: item.weeks_to_complete })}</span>\n </span>\n )}\n {item.level ? (\n <span className={`d-flex align-items-center${typeof item.weeks_to_complete === 'number' ? ' mt-3' : ''}`}>\n <Icon src={Speed} className=\"mr-2\" />\n <span>{formatMessage(messages.level, { level: item.level })}</span>\n </span>\n ) : null}\n </Card.Section>\n\n </Card>\n );\n};\n"]}
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
.product-card-title {
|
|
2
|
+
min-height: 6.4rem;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.card-container > .content-type > .pgn__card-header-content {
|
|
6
|
+
margin-top: 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.card-container .pgn__card-logo-cap {
|
|
10
|
+
position: absolute;
|
|
11
|
+
top: 50%;
|
|
12
|
+
transform: translateY(-50%);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.card-container .pgn__card-image-cap {
|
|
16
|
+
border-radius: 0 !important;
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineMessages } from '@openedx/frontend-base';
|
|
2
|
+
const messages = defineMessages({
|
|
3
|
+
weeksToComplete: {
|
|
4
|
+
id: 'subs-dash.weeksToComplete.label',
|
|
5
|
+
defaultMessage: '{count, plural, one {# week to complete} other {# weeks to complete}}',
|
|
6
|
+
description: 'Label for the weeks to complete field',
|
|
7
|
+
},
|
|
8
|
+
level: {
|
|
9
|
+
id: 'subs-dash.level.label',
|
|
10
|
+
defaultMessage: '{level} level',
|
|
11
|
+
description: 'Label for the level field',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
export default messages;
|
|
15
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/containers/ProductCard/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,eAAe,EAAE;QACf,EAAE,EAAE,iCAAiC;QACrC,cAAc,EAAE,uEAAuE;QACvF,WAAW,EAAE,uCAAuC;KACrD;IACD,KAAK,EAAE;QACL,EAAE,EAAE,uBAAuB;QAC3B,cAAc,EAAE,eAAe;QAC/B,WAAW,EAAE,2BAA2B;KACzC;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n weeksToComplete: {\n id: 'subs-dash.weeksToComplete.label',\n defaultMessage: '{count, plural, one {# week to complete} other {# weeks to complete}}',\n description: 'Label for the weeks to complete field',\n },\n level: {\n id: 'subs-dash.level.label',\n defaultMessage: '{level} level',\n description: 'Label for the level field',\n },\n});\n\nexport default messages;\n"]}
|
|
@@ -8,4 +8,4 @@ export declare const searchKeys: {
|
|
|
8
8
|
courses: (query: string, tags: string[], page: number) => readonly ["search", "courses", string, string[], number];
|
|
9
9
|
popular: (productType: ProductType, limit: number) => readonly ["search", "popular", ProductType, number];
|
|
10
10
|
};
|
|
11
|
-
export declare const
|
|
11
|
+
export declare const usePopularCoursesData: (searchClient: SearchClient | null, enabled: boolean) => UseQueryResult<ProductCardItem[]>;
|
|
@@ -18,12 +18,12 @@ export const searchKeys = {
|
|
|
18
18
|
courses: (query, tags, page) => [...searchKeys.all, 'courses', query, tags, page],
|
|
19
19
|
popular: (productType, limit) => [...searchKeys.all, 'popular', productType, limit],
|
|
20
20
|
};
|
|
21
|
-
export const
|
|
21
|
+
export const usePopularCoursesData = (searchClient, enabled) => useQuery({
|
|
22
22
|
queryKey: searchKeys.popular(PRODUCT_TYPE_COURSE, 4),
|
|
23
23
|
queryFn: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
24
|
const hits = yield fetchPopularProducts(searchClient, PRODUCT_TYPE_COURSE, 4);
|
|
25
25
|
return hits.map((hit) => {
|
|
26
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
26
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
27
27
|
const hitDetails = hit;
|
|
28
28
|
return {
|
|
29
29
|
objectID: hit.objectID,
|
|
@@ -31,12 +31,15 @@ export const useRecentlyViewedCoursesAndProgramsData = (searchClient, enabled) =
|
|
|
31
31
|
primary_description: (_e = (_d = (_c = hitDetails.primary_description) !== null && _c !== void 0 ? _c : hitDetails.short_description) !== null && _d !== void 0 ? _d : hitDetails.description) !== null && _e !== void 0 ? _e : '',
|
|
32
32
|
url: (_h = (_g = (_f = hitDetails.card_image_url) !== null && _f !== void 0 ? _f : hitDetails.image_url) !== null && _g !== void 0 ? _g : hitDetails.marketing_url) !== null && _h !== void 0 ? _h : '',
|
|
33
33
|
thumbnail: (_j = hitDetails.organization_logo_override) !== null && _j !== void 0 ? _j : '',
|
|
34
|
-
|
|
34
|
+
content_type: (_l = (_k = hitDetails.content_type) !== null && _k !== void 0 ? _k : hitDetails.type) !== null && _l !== void 0 ? _l : 'Course',
|
|
35
35
|
product: 'Course',
|
|
36
|
+
partner: (_m = hitDetails.partner) !== null && _m !== void 0 ? _m : '',
|
|
37
|
+
weeks_to_complete: (_o = hitDetails.weeks_to_complete) !== null && _o !== void 0 ? _o : undefined,
|
|
38
|
+
level: (_p = hitDetails.level) !== null && _p !== void 0 ? _p : undefined,
|
|
36
39
|
};
|
|
37
40
|
});
|
|
38
41
|
}),
|
|
39
42
|
enabled: !!searchClient && enabled,
|
|
40
43
|
staleTime: 1000 * 60 * 10,
|
|
41
44
|
});
|
|
42
|
-
//# sourceMappingURL=
|
|
45
|
+
//# sourceMappingURL=usePopularCourses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePopularCourses.js","sourceRoot":"","sources":["../../src/hooks/usePopularCourses.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,qBAAqB,GAAG,CACnC,YAAiC,EACjC,OAAgB,EACmB,EAAE,CACrC,QAAQ,CAAC;IACP,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACpD,OAAO,EAAE,GAAS,EAAE;QAClB,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,YAAa,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAmB,EAAE;;YACvC,MAAM,UAAU,GAAG,GAalB,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,MAAA,UAAU,CAAC,cAAc,mCAAI,UAAU,CAAC,SAAS,mCAAI,UAAU,CAAC,aAAa,mCAAI,EAAE;gBACxF,SAAS,EAAE,MAAA,UAAU,CAAC,0BAA0B,mCAAI,EAAE;gBACtD,YAAY,EAAE,MAAA,MAAA,UAAU,CAAC,YAAY,mCAAI,UAAU,CAAC,IAAI,mCAAI,QAAQ;gBACpE,OAAO,EAAE,QAAQ;gBACjB,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;aACrC,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 usePopularCoursesData = (\n searchClient: SearchClient | null,\n enabled: boolean,\n): UseQueryResult<ProductCardItem[]> =>\n useQuery({\n queryKey: searchKeys.popular(PRODUCT_TYPE_COURSE, 4),\n queryFn: async () => {\n const hits = await fetchPopularProducts(searchClient!, PRODUCT_TYPE_COURSE, 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 type?: string,\n partner?: string,\n weeks_to_complete?: number,\n level?: 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 ?? hitDetails.marketing_url ?? '',\n thumbnail: hitDetails.organization_logo_override ?? '',\n content_type: hitDetails.content_type ?? hitDetails.type ?? 'Course',\n product: 'Course',\n partner: hitDetails.partner ?? '',\n weeks_to_complete: hitDetails.weeks_to_complete ?? undefined,\n level: hitDetails.level ?? undefined,\n };\n });\n },\n enabled: !!searchClient && enabled,\n staleTime: 1000 * 60 * 10,\n });\n"]}
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useIntl } from '@openedx/frontend-base';
|
|
3
|
-
import messages from './messages';
|
|
4
|
-
const NoRecentlyViewedItems = () => {
|
|
5
|
-
const { formatMessage } = useIntl();
|
|
6
|
-
return (_jsx("div", { "data-testid": "no-recently-viewed-items", children: _jsx("p", { className: "mb-0", children: formatMessage(messages.recentlyViewedEmptyState) }) }));
|
|
7
|
-
};
|
|
8
|
-
export default NoRecentlyViewedItems;
|
|
9
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/containers/RecentlyViewedPanel/NoRecentlyViewedItems/index.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,qBAAqB,GAAO,GAAG,EAAE;IACrC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IAEpC,OAAO,CACL,6BAAiB,0BAA0B,YACzC,YAAG,SAAS,EAAC,MAAM,YAAE,aAAa,CAAC,QAAQ,CAAC,wBAAwB,CAAC,GAAK,GACtE,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,qBAAqB,CAAC","sourcesContent":["import { FC } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\n\nimport messages from './messages';\n\nconst NoRecentlyViewedItems: FC = () => {\n const { formatMessage } = useIntl();\n\n return (\n <div data-testid=\"no-recently-viewed-items\">\n <p className=\"mb-0\">{formatMessage(messages.recentlyViewedEmptyState)}</p>\n </div>\n );\n};\n\nexport default NoRecentlyViewedItems;\n"]}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from '@openedx/frontend-base';
|
|
2
|
-
const messages = defineMessages({
|
|
3
|
-
recentlyViewedEmptyState: {
|
|
4
|
-
id: 'subs-dash.recentlyViewedPanel.emptyState',
|
|
5
|
-
defaultMessage: 'When you browse the edX Unlimited catalog, we\'ll show the courses and programs you viewed here.',
|
|
6
|
-
description: 'Placeholder text for recently viewed courses and programs section',
|
|
7
|
-
},
|
|
8
|
-
});
|
|
9
|
-
export default messages;
|
|
10
|
-
//# sourceMappingURL=messages.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../../src/containers/RecentlyViewedPanel/NoRecentlyViewedItems/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,wBAAwB,EAAE;QACxB,EAAE,EAAE,0CAA0C;QAC9C,cAAc,EAAE,kGAAkG;QAClH,WAAW,EAAE,mEAAmE;KACjF;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n recentlyViewedEmptyState: {\n id: 'subs-dash.recentlyViewedPanel.emptyState',\n defaultMessage: 'When you browse the edX Unlimited catalog, we\\'ll show the courses and programs you viewed here.',\n description: 'Placeholder text for recently viewed courses and programs section',\n },\n});\n\nexport default messages;\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/containers/RecentlyViewedPanel/RecentlyViewedCourseProgram/index.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,MAAM,CAAC,MAAM,2BAA2B,GAAyC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE;IACxG,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,EAAE,SAAS,EAAE,SAAS,GAAI,IADzC,IAAI,CAAC,QAAQ,CAEjB,CACP,CAAC,GACE,GACF,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,2BAA2B,CAAC","sourcesContent":["import { FC } from 'react';\n\nimport { ProductCard } from '../../ProductCard';\nimport { RecentlyViewedCourseProgramProps } from './data/types';\n\nexport const RecentlyViewedCourseProgram: FC<RecentlyViewedCourseProgramProps> = ({ items, isLoading }) => {\n return (\n <div data-testid=\"recently-viewed-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} isLoading={isLoading} />\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport default RecentlyViewedCourseProgram;\n"]}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo } from 'react';
|
|
3
|
-
import { Alert } from '@openedx/paragon';
|
|
4
|
-
import { useIntl } from '@openedx/frontend-base';
|
|
5
|
-
import { useRecentlyViewedCoursesAndProgramsData } from '../../hooks/useRecentlyViewedCoursesAndProgramsData';
|
|
6
|
-
import { useAlgoliaSearch } from '../../utils/algoliaUtils';
|
|
7
|
-
import messages from './messages';
|
|
8
|
-
import NoRecentlyViewedItems from './NoRecentlyViewedItems';
|
|
9
|
-
import RecentlyViewedCourseProgram from './RecentlyViewedCourseProgram';
|
|
10
|
-
export const RecentlyViewedPanel = () => {
|
|
11
|
-
const { formatMessage } = useIntl();
|
|
12
|
-
const [searchClient] = useAlgoliaSearch();
|
|
13
|
-
const { data: recentlyViewedCoursesAndProgramsData = [], isError, isLoading, } = useRecentlyViewedCoursesAndProgramsData(searchClient, true);
|
|
14
|
-
const hasRecentlyViewedData = useMemo(() => recentlyViewedCoursesAndProgramsData.length > 0, [recentlyViewedCoursesAndProgramsData]);
|
|
15
|
-
if (isError) {
|
|
16
|
-
return (_jsx("div", { className: "recently-viewed-container mt-5 mb-3", "data-testid": "recently-viewed-panel", children: _jsx(Alert, { variant: "danger", "data-testid": "recently-viewed-error", children: formatMessage(messages.recentlyViewedErrorText) }) }));
|
|
17
|
-
}
|
|
18
|
-
return (_jsxs("div", { className: "recently-viewed-container mt-5 mb-3", "data-testid": "recently-viewed-panel", children: [_jsx("div", { className: "recently-viewed-heading-container mb-4", children: _jsx("h2", { children: formatMessage(messages.recentlyViewedHeader) }) }), (isLoading || hasRecentlyViewedData) ? (_jsx(RecentlyViewedCourseProgram, { items: recentlyViewedCoursesAndProgramsData, isLoading: isLoading })) : (_jsx(NoRecentlyViewedItems, {}))] }));
|
|
19
|
-
};
|
|
20
|
-
export default RecentlyViewedPanel;
|
|
21
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/containers/RecentlyViewedPanel/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAM,OAAO,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,uCAAuC,EAAE,MAAM,oDAAoD,CAAC;AAC7G,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,2BAA2B,MAAM,+BAA+B,CAAC;AAExE,MAAM,CAAC,MAAM,mBAAmB,GAAO,GAAG,EAAE;IAC1C,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;IACpC,MAAM,CAAC,YAAY,CAAC,GAAG,gBAAgB,EAAE,CAAC;IAC1C,MAAM,EACJ,IAAI,EAAE,oCAAoC,GAAG,EAAE,EAC/C,OAAO,EACP,SAAS,GACV,GAAG,uCAAuC,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAChE,MAAM,qBAAqB,GAAG,OAAO,CACnC,GAAG,EAAE,CAAC,oCAAoC,CAAC,MAAM,GAAG,CAAC,EACrD,CAAC,oCAAoC,CAAC,CACvC,CAAC;IAEF,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CACL,cAAK,SAAS,EAAC,qCAAqC,iBAAa,uBAAuB,YACtF,KAAC,KAAK,IAAC,OAAO,EAAC,QAAQ,iBAAa,uBAAuB,YACxD,aAAa,CAAC,QAAQ,CAAC,uBAAuB,CAAC,GAC1C,GACJ,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAC,qCAAqC,iBAAa,uBAAuB,aACtF,cAAK,SAAS,EAAC,wCAAwC,YACrD,uBAAK,aAAa,CAAC,QAAQ,CAAC,oBAAoB,CAAC,GAAM,GACnD,EACL,CAAC,SAAS,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAC,CACtC,KAAC,2BAA2B,IAC1B,KAAK,EAAE,oCAAoC,EAC3C,SAAS,EAAE,SAAS,GACpB,CACH,CAAC,CAAC,CAAC,CACF,KAAC,qBAAqB,KAAG,CAC1B,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,mBAAmB,CAAC","sourcesContent":["import { FC, useMemo } from 'react';\nimport { Alert } from '@openedx/paragon';\nimport { useIntl } from '@openedx/frontend-base';\n\nimport { useRecentlyViewedCoursesAndProgramsData } from '@src/hooks/useRecentlyViewedCoursesAndProgramsData';\nimport { useAlgoliaSearch } from '@src/utils/algoliaUtils';\nimport messages from './messages';\nimport NoRecentlyViewedItems from './NoRecentlyViewedItems';\nimport RecentlyViewedCourseProgram from './RecentlyViewedCourseProgram';\n\nexport const RecentlyViewedPanel: FC = () => {\n const { formatMessage } = useIntl();\n const [searchClient] = useAlgoliaSearch();\n const {\n data: recentlyViewedCoursesAndProgramsData = [],\n isError,\n isLoading,\n } = useRecentlyViewedCoursesAndProgramsData(searchClient, true);\n const hasRecentlyViewedData = useMemo(\n () => recentlyViewedCoursesAndProgramsData.length > 0,\n [recentlyViewedCoursesAndProgramsData]\n );\n\n if (isError) {\n return (\n <div className=\"recently-viewed-container mt-5 mb-3\" data-testid=\"recently-viewed-panel\">\n <Alert variant=\"danger\" data-testid=\"recently-viewed-error\">\n {formatMessage(messages.recentlyViewedErrorText)}\n </Alert>\n </div>\n );\n }\n\n return (\n <div className=\"recently-viewed-container mt-5 mb-3\" data-testid=\"recently-viewed-panel\">\n <div className=\"recently-viewed-heading-container mb-4\">\n <h2>{formatMessage(messages.recentlyViewedHeader)}</h2>\n </div>\n {(isLoading || hasRecentlyViewedData) ? (\n <RecentlyViewedCourseProgram\n items={recentlyViewedCoursesAndProgramsData}\n isLoading={isLoading}\n />\n ) : (\n <NoRecentlyViewedItems />\n )}\n </div>\n );\n};\n\nexport default RecentlyViewedPanel;\n"]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from '@openedx/frontend-base';
|
|
2
|
-
const messages = defineMessages({
|
|
3
|
-
recentlyViewedHeader: {
|
|
4
|
-
id: 'subs-dash.recentlyViewedPanel.header',
|
|
5
|
-
defaultMessage: 'Recently viewed courses and programs',
|
|
6
|
-
description: 'Label for the recently viewed courses and programs section',
|
|
7
|
-
},
|
|
8
|
-
recentlyViewedErrorText: {
|
|
9
|
-
id: 'subs-dash.recentlyViewedPanel.errorText',
|
|
10
|
-
defaultMessage: 'Failed to load recently viewed courses and programs. Please try again later.',
|
|
11
|
-
description: 'Error text for failing to load recently viewed courses and programs',
|
|
12
|
-
},
|
|
13
|
-
});
|
|
14
|
-
export default messages;
|
|
15
|
-
//# sourceMappingURL=messages.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/containers/RecentlyViewedPanel/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,oBAAoB,EAAE;QACpB,EAAE,EAAE,sCAAsC;QAC1C,cAAc,EAAE,sCAAsC;QACtD,WAAW,EAAE,4DAA4D;KAC1E;IACD,uBAAuB,EAAE;QACvB,EAAE,EAAE,yCAAyC;QAC7C,cAAc,EAAE,8EAA8E;QAC9F,WAAW,EAAE,qEAAqE;KACnF;CACF,CAAC,CAAC;AAEH,eAAe,QAAQ,CAAC","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n recentlyViewedHeader: {\n id: 'subs-dash.recentlyViewedPanel.header',\n defaultMessage: 'Recently viewed courses and programs',\n description: 'Label for the recently viewed courses and programs section',\n },\n recentlyViewedErrorText: {\n id: 'subs-dash.recentlyViewedPanel.errorText',\n defaultMessage: 'Failed to load recently viewed courses and programs. Please try again later.',\n description: 'Error text for failing to load recently viewed courses and programs',\n },\n});\n\nexport default messages;\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useRecentlyViewedCoursesAndProgramsData.js","sourceRoot":"","sources":["../../src/hooks/useRecentlyViewedCoursesAndProgramsData.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,uCAAuC,GAAG,CACrD,YAAiC,EACjC,OAAgB,EACmB,EAAE,CACrC,QAAQ,CAAC;IACP,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACpD,OAAO,EAAE,GAAS,EAAE;QAClB,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,YAAa,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC;QAC/E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAmB,EAAE;;YACvC,MAAM,UAAU,GAAG,GAUlB,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,MAAA,UAAU,CAAC,cAAc,mCAAI,UAAU,CAAC,SAAS,mCAAI,UAAU,CAAC,aAAa,mCAAI,EAAE;gBACxF,SAAS,EAAE,MAAA,UAAU,CAAC,0BAA0B,mCAAI,EAAE;gBACtD,WAAW,EAAE,MAAA,MAAA,UAAU,CAAC,YAAY,mCAAI,UAAU,CAAC,IAAI,mCAAI,QAAQ;gBACnE,OAAO,EAAE,QAAQ;aAClB,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 useRecentlyViewedCoursesAndProgramsData = (\n searchClient: SearchClient | null,\n enabled: boolean,\n): UseQueryResult<ProductCardItem[]> =>\n useQuery({\n queryKey: searchKeys.popular(PRODUCT_TYPE_COURSE, 4),\n queryFn: async () => {\n const hits = await fetchPopularProducts(searchClient!, PRODUCT_TYPE_COURSE, 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 type?: 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 ?? hitDetails.marketing_url ?? '',\n thumbnail: hitDetails.organization_logo_override ?? '',\n footerLabel: hitDetails.content_type ?? hitDetails.type ?? 'Course',\n product: 'Course',\n };\n });\n },\n enabled: !!searchClient && enabled,\n staleTime: 1000 * 60 * 10,\n });\n"]}
|