@openedx/frontend-app-catalog 1.0.0-alpha.2 → 1.0.0-alpha.4

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/app.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { appId } from './constants';
2
2
  import routes from './routes';
3
3
  import slots from './slots';
4
+ import { DEFAULT_COURSES_COUNT } from './home/constants';
4
5
  const app = {
5
6
  appId,
6
7
  routes,
7
8
  slots,
8
9
  defaultConfig: {
9
- HOMEPAGE_COURSE_MAX: 9,
10
+ HOMEPAGE_COURSE_MAX: DEFAULT_COURSES_COUNT,
10
11
  },
11
12
  };
12
13
  export default app;
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,GAAG,GAAQ;IACf,KAAK;IACL,MAAM;IACN,KAAK;IACL,aAAa,EAAE;QACb,mBAAmB,EAAE,CAAC;KACvB;CACF,CAAC;AAEF,eAAe,GAAG,CAAC","sourcesContent":["import { App } from '@openedx/frontend-base';\nimport { appId } from '@src/constants';\nimport routes from '@src/routes';\nimport slots from '@src/slots';\n\nconst app: App = {\n appId,\n routes,\n slots,\n defaultConfig: {\n HOMEPAGE_COURSE_MAX: 9,\n },\n};\n\nexport default app;\n"]}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,GAAG,GAAQ;IACf,KAAK;IACL,MAAM;IACN,KAAK;IACL,aAAa,EAAE;QACb,mBAAmB,EAAE,qBAAqB;KAC3C;CACF,CAAC;AAEF,eAAe,GAAG,CAAC","sourcesContent":["import { App } from '@openedx/frontend-base';\nimport { appId } from '@src/constants';\nimport routes from '@src/routes';\nimport slots from '@src/slots';\nimport { DEFAULT_COURSES_COUNT } from '@src/home/constants';\n\nconst app: App = {\n appId,\n routes,\n slots,\n defaultConfig: {\n HOMEPAGE_COURSE_MAX: DEFAULT_COURSES_COUNT,\n },\n};\n\nexport default app;\n"]}
package/dist/config.d.ts CHANGED
@@ -3,3 +3,8 @@
3
3
  * absent or holds a non-string value.
4
4
  */
5
5
  export declare const getStringConfig: (key: string, fallback?: string) => string;
6
+ /**
7
+ * Reads a count setting out of the app config, falling back when the key is
8
+ * absent or holds anything that does not read as a whole number.
9
+ */
10
+ export declare const getCountConfig: (key: string, fallback: number) => number;
package/dist/config.js CHANGED
@@ -8,4 +8,16 @@ export const getStringConfig = (key, fallback = '') => {
8
8
  const value = getAppConfig(appId)[key];
9
9
  return typeof value === 'string' ? value : fallback;
10
10
  };
11
+ /**
12
+ * Reads a count setting out of the app config, falling back when the key is
13
+ * absent or holds anything that does not read as a whole number.
14
+ */
15
+ export const getCountConfig = (key, fallback) => {
16
+ const value = getAppConfig(appId)[key];
17
+ const count = typeof value === 'string' ? Number(value) : value;
18
+ if (typeof count === 'number' && Number.isInteger(count) && count >= 1) {
19
+ return count;
20
+ }
21
+ return fallback;
22
+ };
11
23
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,QAAQ,GAAG,EAAE,EAAU,EAAE;IACpE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtD,CAAC,CAAC","sourcesContent":["import { getAppConfig } from '@openedx/frontend-base';\n\nimport { appId } from './constants';\n\n/**\n * Reads a string setting out of the app config, falling back when the key is\n * absent or holds a non-string value.\n */\nexport const getStringConfig = (key: string, fallback = ''): string => {\n const value = getAppConfig(appId)[key];\n return typeof value === 'string' ? value : fallback;\n};\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,QAAQ,GAAG,EAAE,EAAU,EAAE;IACpE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtD,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,QAAgB,EAAU,EAAE;IACtE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAEhE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACvE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC","sourcesContent":["import { getAppConfig } from '@openedx/frontend-base';\n\nimport { appId } from './constants';\n\n/**\n * Reads a string setting out of the app config, falling back when the key is\n * absent or holds a non-string value.\n */\nexport const getStringConfig = (key: string, fallback = ''): string => {\n const value = getAppConfig(appId)[key];\n return typeof value === 'string' ? value : fallback;\n};\n\n/**\n * Reads a count setting out of the app config, falling back when the key is\n * absent or holds anything that does not read as a whole number.\n */\nexport const getCountConfig = (key: string, fallback: number): number => {\n const value = getAppConfig(appId)[key];\n const count = typeof value === 'string' ? Number(value) : value;\n\n if (typeof count === 'number' && Number.isInteger(count) && count >= 1) {\n return count;\n }\n\n return fallback;\n};\n"]}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Stack, Container, Card } from '@openedx/paragon';
3
3
  import { ListView as ListViewIcon } from '@openedx/paragon/icons';
4
- import { getUrlByRouteRole, useIntl } from '@openedx/frontend-base';
4
+ import { resolveRouteByRole, useIntl } from '@openedx/frontend-base';
5
5
  import { Link } from 'react-router-dom';
6
6
  import CourseAboutSidebarCoursePriceSlot from '../../../slots/CourseAboutSidebarCoursePriceSlot';
7
7
  import { courseAboutRole } from '../../../constants';
@@ -16,7 +16,7 @@ const SidebarDetails = ({ courseAboutData }) => {
16
16
  return null;
17
17
  }
18
18
  const prerequisite = courseAboutData.preRequisiteCourses[0];
19
- const prerequisiteUrl = (_b = getUrlByRouteRole(courseAboutRole)) === null || _b === void 0 ? void 0 : _b.replace(':courseId', prerequisite.key);
19
+ const prerequisiteUrl = (_b = resolveRouteByRole(courseAboutRole, { courseId: prerequisite.key })) === null || _b === void 0 ? void 0 : _b.url;
20
20
  if (!prerequisiteUrl) {
21
21
  return null;
22
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SidebarDetails.js","sourceRoot":"","sources":["../../../../src/course-about/course-sidebar/sidebar-details/SidebarDetails.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,OAAO,iCAAiC,MAAM,8CAA8C,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,cAAc,GAAG,CAAC,EAAE,eAAe,EAAwC,EAAE,EAAE;IACnF,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,mBAAmB,GAAG,GAAG,EAAE;;QAC/B,IAAI,CAAC,CAAA,MAAA,eAAe,CAAC,mBAAmB,0CAAE,MAAM,CAAA,EAAE,CAAC;YACjD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,YAAY,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,eAAe,GAAG,MAAA,iBAAiB,CAAC,eAAe,CAAC,0CAAE,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;QAEnG,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CACL,8BACE,KAAC,kBAAkB,IAEjB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,EACjD,KAAK,EAAE,KAAC,IAAI,IAAC,EAAE,EAAE,eAAe,YAAG,YAAY,CAAC,OAAO,GAAQ,IAH3D,eAAe,CAInB,EACF,KAAC,SAAS,IAAC,SAAS,EAAC,KAAK,YACvB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uBAAuB,EAAE;wBACpD,YAAY,EAAE,KAAC,IAAI,IAAC,EAAE,EAAE,eAAe,YAAG,YAAY,CAAC,OAAO,GAAQ;qBACvE,CAAC,GACQ,EACZ,KAAC,IAAI,CAAC,OAAO,KAAG,IACf,CACJ,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,sBAAsB,GAAG,GAAG,EAAE;QAClC,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CACL,KAAC,SAAS,IAAC,SAAS,EAAC,KAAK,YAExB,cAAK,uBAAuB,EAAE,EAAE,MAAM,EAAE,eAAe,CAAC,gBAAgB,EAAE,GAAI,GACpE,CACb,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,KAAK,eACH,iBAAiB,CAAC,IAAI,EAAE,eAAe,CAAC;iBACtC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;iBAC7B,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CACb,KAAC,kBAAkB,IAEjB,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAHd,MAAM,CAAC,GAAG,CAIf,CACH,CAAC,EACH,eAAe,CAAC,WAAW,IAAI,CAC9B,KAAC,iCAAiC,IAAC,WAAW,EAAE,eAAe,CAAC,WAAW,GAAI,CAChF,EACA,mBAAmB,EAAE,EACrB,sBAAsB,EAAE,IACnB,CACT,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["import { Stack, Container, Card } from '@openedx/paragon';\nimport { ListView as ListViewIcon } from '@openedx/paragon/icons';\nimport { getUrlByRouteRole, useIntl } from '@openedx/frontend-base';\nimport { Link } from 'react-router-dom';\n\nimport CourseAboutSidebarCoursePriceSlot from '@src/slots/CourseAboutSidebarCoursePriceSlot';\nimport { courseAboutRole } from '@src/constants';\nimport type { CourseAboutData } from '../../types';\nimport SidebarDetailsItem from './SidebarDetailsItem';\nimport { getSidebarDetails } from './utils';\nimport messages from './messages';\n\nconst SidebarDetails = ({ courseAboutData }: { courseAboutData: CourseAboutData }) => {\n const intl = useIntl();\n\n const renderPrerequisites = () => {\n if (!courseAboutData.preRequisiteCourses?.length) {\n return null;\n }\n\n const prerequisite = courseAboutData.preRequisiteCourses[0];\n const prerequisiteUrl = getUrlByRouteRole(courseAboutRole)?.replace(':courseId', prerequisite.key);\n\n if (!prerequisiteUrl) {\n return null;\n }\n\n return (\n <>\n <SidebarDetailsItem\n key=\"prerequisites\"\n icon={ListViewIcon}\n label={intl.formatMessage(messages.prerequisites)}\n value={<Link to={prerequisiteUrl}>{prerequisite.display}</Link>}\n />\n <Container className=\"p-3\">\n {intl.formatMessage(messages.prerequisitesCompletion, {\n prerequisite: <Link to={prerequisiteUrl}>{prerequisite.display}</Link>,\n })}\n </Container>\n <Card.Divider />\n </>\n );\n };\n\n const renderAboutSidebarHtml = () => {\n if (!courseAboutData.aboutSidebarHtml) {\n return null;\n }\n\n return (\n <Container className=\"p-3\">\n { }\n <div dangerouslySetInnerHTML={{ __html: courseAboutData.aboutSidebarHtml }} />\n </Container>\n );\n };\n\n return (\n <Stack>\n {getSidebarDetails(intl, courseAboutData)\n .filter(detail => detail.show)\n .map(detail => (\n <SidebarDetailsItem\n key={detail.key}\n icon={detail.icon}\n label={detail.label}\n value={detail.value}\n />\n ))}\n {courseAboutData.coursePrice && (\n <CourseAboutSidebarCoursePriceSlot coursePrice={courseAboutData.coursePrice} />\n )}\n {renderPrerequisites()}\n {renderAboutSidebarHtml()}\n </Stack>\n );\n};\n\nexport default SidebarDetails;\n"]}
1
+ {"version":3,"file":"SidebarDetails.js","sourceRoot":"","sources":["../../../../src/course-about/course-sidebar/sidebar-details/SidebarDetails.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,OAAO,iCAAiC,MAAM,8CAA8C,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,cAAc,GAAG,CAAC,EAAE,eAAe,EAAwC,EAAE,EAAE;IACnF,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,mBAAmB,GAAG,GAAG,EAAE;;QAC/B,IAAI,CAAC,CAAA,MAAA,eAAe,CAAC,mBAAmB,0CAAE,MAAM,CAAA,EAAE,CAAC;YACjD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,YAAY,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,eAAe,GAAG,MAAA,kBAAkB,CAAC,eAAe,EAAE,EAAE,QAAQ,EAAE,YAAY,CAAC,GAAG,EAAE,CAAC,0CAAE,GAAG,CAAC;QAEjG,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CACL,8BACE,KAAC,kBAAkB,IAEjB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,EACjD,KAAK,EAAE,KAAC,IAAI,IAAC,EAAE,EAAE,eAAe,YAAG,YAAY,CAAC,OAAO,GAAQ,IAH3D,eAAe,CAInB,EACF,KAAC,SAAS,IAAC,SAAS,EAAC,KAAK,YACvB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,uBAAuB,EAAE;wBACpD,YAAY,EAAE,KAAC,IAAI,IAAC,EAAE,EAAE,eAAe,YAAG,YAAY,CAAC,OAAO,GAAQ;qBACvE,CAAC,GACQ,EACZ,KAAC,IAAI,CAAC,OAAO,KAAG,IACf,CACJ,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,sBAAsB,GAAG,GAAG,EAAE;QAClC,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CACL,KAAC,SAAS,IAAC,SAAS,EAAC,KAAK,YAExB,cAAK,uBAAuB,EAAE,EAAE,MAAM,EAAE,eAAe,CAAC,gBAAgB,EAAE,GAAI,GACpE,CACb,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,KAAK,eACH,iBAAiB,CAAC,IAAI,EAAE,eAAe,CAAC;iBACtC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;iBAC7B,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CACb,KAAC,kBAAkB,IAEjB,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAHd,MAAM,CAAC,GAAG,CAIf,CACH,CAAC,EACH,eAAe,CAAC,WAAW,IAAI,CAC9B,KAAC,iCAAiC,IAAC,WAAW,EAAE,eAAe,CAAC,WAAW,GAAI,CAChF,EACA,mBAAmB,EAAE,EACrB,sBAAsB,EAAE,IACnB,CACT,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["import { Stack, Container, Card } from '@openedx/paragon';\nimport { ListView as ListViewIcon } from '@openedx/paragon/icons';\nimport { resolveRouteByRole, useIntl } from '@openedx/frontend-base';\nimport { Link } from 'react-router-dom';\n\nimport CourseAboutSidebarCoursePriceSlot from '@src/slots/CourseAboutSidebarCoursePriceSlot';\nimport { courseAboutRole } from '@src/constants';\nimport type { CourseAboutData } from '../../types';\nimport SidebarDetailsItem from './SidebarDetailsItem';\nimport { getSidebarDetails } from './utils';\nimport messages from './messages';\n\nconst SidebarDetails = ({ courseAboutData }: { courseAboutData: CourseAboutData }) => {\n const intl = useIntl();\n\n const renderPrerequisites = () => {\n if (!courseAboutData.preRequisiteCourses?.length) {\n return null;\n }\n\n const prerequisite = courseAboutData.preRequisiteCourses[0];\n const prerequisiteUrl = resolveRouteByRole(courseAboutRole, { courseId: prerequisite.key })?.url;\n\n if (!prerequisiteUrl) {\n return null;\n }\n\n return (\n <>\n <SidebarDetailsItem\n key=\"prerequisites\"\n icon={ListViewIcon}\n label={intl.formatMessage(messages.prerequisites)}\n value={<Link to={prerequisiteUrl}>{prerequisite.display}</Link>}\n />\n <Container className=\"p-3\">\n {intl.formatMessage(messages.prerequisitesCompletion, {\n prerequisite: <Link to={prerequisiteUrl}>{prerequisite.display}</Link>,\n })}\n </Container>\n <Card.Divider />\n </>\n );\n };\n\n const renderAboutSidebarHtml = () => {\n if (!courseAboutData.aboutSidebarHtml) {\n return null;\n }\n\n return (\n <Container className=\"p-3\">\n { }\n <div dangerouslySetInnerHTML={{ __html: courseAboutData.aboutSidebarHtml }} />\n </Container>\n );\n };\n\n return (\n <Stack>\n {getSidebarDetails(intl, courseAboutData)\n .filter(detail => detail.show)\n .map(detail => (\n <SidebarDetailsItem\n key={detail.key}\n icon={detail.icon}\n label={detail.label}\n value={detail.value}\n />\n ))}\n {courseAboutData.coursePrice && (\n <CourseAboutSidebarCoursePriceSlot coursePrice={courseAboutData.coursePrice} />\n )}\n {renderPrerequisites()}\n {renderAboutSidebarHtml()}\n </Stack>\n );\n};\n\nexport default SidebarDetails;\n"]}
@@ -12,12 +12,23 @@ import { getAuthenticatedHttpClient } from '@openedx/frontend-base';
12
12
  import { DEFAULT_PAGE_SIZE, DEFAULT_PAGE_INDEX } from './constants';
13
13
  import { getCourseListSearchUrl } from './urls';
14
14
  import { addFiltersToFormData } from './utils';
15
+ /**
16
+ * Coerces a pagination value into an integer the search API can parse.
17
+ */
18
+ const toPaginationValue = (value, fallback, minimum) => {
19
+ if (typeof value === 'number' && Number.isInteger(value) && value >= minimum) {
20
+ return value;
21
+ }
22
+ return fallback;
23
+ };
15
24
  /**
16
25
  * Fetches course list search data from the API.
17
26
  * @async
18
27
  */
19
28
  export const fetchCourseListSearch = (params) => __awaiter(void 0, void 0, void 0, function* () {
20
- const { pageSize = DEFAULT_PAGE_SIZE, pageIndex = DEFAULT_PAGE_INDEX, enableCourseSortingByStartDate = false, filters = {}, searchString = '', } = params;
29
+ const { enableCourseSortingByStartDate = false, filters = {}, searchString = '', } = params;
30
+ const pageSize = toPaginationValue(params.pageSize, DEFAULT_PAGE_SIZE, 1);
31
+ const pageIndex = toPaginationValue(params.pageIndex, DEFAULT_PAGE_INDEX, 0);
21
32
  const formData = new FormData();
22
33
  formData.append('page_size', String(pageSize));
23
34
  formData.append('page_index', String(pageIndex));
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/data/course-list-search/api.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAI/C;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAO,MAAM,EAAqC,EAAE;IACvF,MAAM,EACJ,QAAQ,GAAG,iBAAiB,EAC5B,SAAS,GAAG,kBAAkB,EAC9B,8BAA8B,GAAG,KAAK,EACtC,OAAO,GAAG,EAAE,EACZ,YAAY,GAAG,EAAE,GAClB,GAAG,MAAM,CAAC;IAEX,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAEhC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,qCAAqC,EAAE,MAAM,CAAC,8BAA8B,CAAC,CAAC,CAAC;IAE/F,IAAI,YAAY,EAAE,CAAC;QACjB,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC;IAED,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAExC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE;SAChD,IAAI,CAAC,sBAAsB,EAAE,EAAE,QAAQ,CAAC,CAAC;IAE5C,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC","sourcesContent":["import { camelCaseObject } from '@openedx/frontend-base';\nimport { getAuthenticatedHttpClient } from '@openedx/frontend-base';\n\nimport { DEFAULT_PAGE_SIZE, DEFAULT_PAGE_INDEX } from './constants';\nimport { getCourseListSearchUrl } from './urls';\nimport { addFiltersToFormData } from './utils';\n\nimport type { CourseListSearchResponse } from './types';\n\n/**\n * Fetches course list search data from the API.\n * @async\n */\nexport const fetchCourseListSearch = async (params): Promise<CourseListSearchResponse> => {\n const {\n pageSize = DEFAULT_PAGE_SIZE,\n pageIndex = DEFAULT_PAGE_INDEX,\n enableCourseSortingByStartDate = false,\n filters = {},\n searchString = '',\n } = params;\n\n const formData = new FormData();\n\n formData.append('page_size', String(pageSize));\n formData.append('page_index', String(pageIndex));\n formData.append('enable_course_sorting_by_start_date', String(enableCourseSortingByStartDate));\n\n if (searchString) {\n formData.append('search_string', searchString);\n }\n\n addFiltersToFormData(formData, filters);\n\n const { data } = await getAuthenticatedHttpClient()\n .post(getCourseListSearchUrl(), formData);\n\n return camelCaseObject(data);\n};\n"]}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/data/course-list-search/api.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAI/C;;GAEG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAAE,QAAgB,EAAE,OAAe,EAAU,EAAE;IACtF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAO,MAAM,EAAqC,EAAE;IACvF,MAAM,EACJ,8BAA8B,GAAG,KAAK,EACtC,OAAO,GAAG,EAAE,EACZ,YAAY,GAAG,EAAE,GAClB,GAAG,MAAM,CAAC;IAEX,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC;IAC1E,MAAM,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC;IAE7E,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAEhC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,qCAAqC,EAAE,MAAM,CAAC,8BAA8B,CAAC,CAAC,CAAC;IAE/F,IAAI,YAAY,EAAE,CAAC;QACjB,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC;IAED,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAExC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,0BAA0B,EAAE;SAChD,IAAI,CAAC,sBAAsB,EAAE,EAAE,QAAQ,CAAC,CAAC;IAE5C,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC,CAAA,CAAC","sourcesContent":["import { camelCaseObject } from '@openedx/frontend-base';\nimport { getAuthenticatedHttpClient } from '@openedx/frontend-base';\n\nimport { DEFAULT_PAGE_SIZE, DEFAULT_PAGE_INDEX } from './constants';\nimport { getCourseListSearchUrl } from './urls';\nimport { addFiltersToFormData } from './utils';\n\nimport type { CourseListSearchResponse } from './types';\n\n/**\n * Coerces a pagination value into an integer the search API can parse.\n */\nconst toPaginationValue = (value: unknown, fallback: number, minimum: number): number => {\n if (typeof value === 'number' && Number.isInteger(value) && value >= minimum) {\n return value;\n }\n\n return fallback;\n};\n\n/**\n * Fetches course list search data from the API.\n * @async\n */\nexport const fetchCourseListSearch = async (params): Promise<CourseListSearchResponse> => {\n const {\n enableCourseSortingByStartDate = false,\n filters = {},\n searchString = '',\n } = params;\n\n const pageSize = toPaginationValue(params.pageSize, DEFAULT_PAGE_SIZE, 1);\n const pageIndex = toPaginationValue(params.pageIndex, DEFAULT_PAGE_INDEX, 0);\n\n const formData = new FormData();\n\n formData.append('page_size', String(pageSize));\n formData.append('page_index', String(pageIndex));\n formData.append('enable_course_sorting_by_start_date', String(enableCourseSortingByStartDate));\n\n if (searchString) {\n formData.append('search_string', searchString);\n }\n\n addFiltersToFormData(formData, filters);\n\n const { data } = await getAuthenticatedHttpClient()\n .post(getCourseListSearchUrl(), formData);\n\n return camelCaseObject(data);\n};\n"]}
@@ -24,13 +24,14 @@ export const useCourseListSearch = ({ pageSize = DEFAULT_PAGE_SIZE, pageIndex =
24
24
  */
25
25
  const fetchData = useCallback((newParams) => {
26
26
  const transformedFilters = transformDataTableFilters(newParams.filters);
27
- const transformedParams = {
28
- pageSize: newParams.pageSize,
29
- pageIndex: newParams.pageIndex,
30
- filters: transformedFilters,
31
- searchString: newParams.searchString || '',
32
- };
33
27
  setParams(prevParams => {
28
+ const transformedParams = {
29
+ pageSize: newParams.pageSize,
30
+ pageIndex: newParams.pageIndex,
31
+ enableCourseSortingByStartDate: prevParams.enableCourseSortingByStartDate,
32
+ filters: transformedFilters,
33
+ searchString: newParams.searchString || '',
34
+ };
34
35
  const hasChanged = JSON.stringify(prevParams) !== JSON.stringify(transformedParams);
35
36
  return hasChanged ? transformedParams : prevParams;
36
37
  });
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/data/course-list-search/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAEpD;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAClC,QAAQ,GAAG,iBAAiB,EAC5B,SAAS,GAAG,kBAAkB,EAC9B,8BAA8B,GAAG,KAAK,EACtC,OAAO,GAAG,EAAE,EACZ,YAAY,GAAG,EAAE,MACkB,EAAE,EAAwB,EAAE;IAC/D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAyB;QAC3D,QAAQ;QACR,SAAS;QACT,8BAA8B;QAC9B,OAAO;QACP,YAAY;KACb,CAAC,CAAC;IAEH,MAAM,EACJ,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,GAC5C,GAAG,QAAQ,CAAkC;QAC5C,QAAQ,EAAE,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACtC,OAAO,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,MAAM,CAAC;QAC5C,eAAe,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY;KAChD,CAAC,CAAC;IAEH;;OAEG;IACH,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,SAAsD,EAAE,EAAE;QACvF,MAAM,kBAAkB,GAAG,yBAAyB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAExE,MAAM,iBAAiB,GAA2B;YAChD,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,SAAS,EAAE,SAAS,CAAC,SAAS;YAC9B,OAAO,EAAE,kBAAkB;YAC3B,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,EAAE;SAC3C,CAAC;QAEF,SAAS,CAAC,UAAU,CAAC,EAAE;YACrB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;YACpF,OAAO,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,UAAU,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,IAAI;QACJ,SAAS;QACT,OAAO;QACP,KAAK;QACL,SAAS;QACT,UAAU;KACX,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { useState, useCallback } from 'react';\n\nimport { fetchCourseListSearch } from './api';\nimport { DEFAULT_PAGE_SIZE, DEFAULT_PAGE_INDEX } from './constants';\nimport type {\n CourseListSearchResponse, CourseListSearchParams, CourseListSearchHook, DataTableParams,\n} from './types';\nimport { transformDataTableFilters } from './utils';\n\n/**\n * A React Query hook that fetches course list search data.\n */\nexport const useCourseListSearch = ({\n pageSize = DEFAULT_PAGE_SIZE,\n pageIndex = DEFAULT_PAGE_INDEX,\n enableCourseSortingByStartDate = false,\n filters = {},\n searchString = '',\n}: Partial<CourseListSearchParams> = {}): CourseListSearchHook => {\n const [params, setParams] = useState<CourseListSearchParams>({\n pageSize,\n pageIndex,\n enableCourseSortingByStartDate,\n filters,\n searchString,\n });\n\n const {\n data, isLoading, isError, error, isFetching,\n } = useQuery<CourseListSearchResponse, Error>({\n queryKey: ['courseListSearch', params],\n queryFn: () => fetchCourseListSearch(params),\n placeholderData: (previousData) => previousData,\n });\n\n /**\n * Updates query params and triggers data refetch if params have changed.\n */\n const fetchData = useCallback((newParams: DataTableParams & { searchString?: string }) => {\n const transformedFilters = transformDataTableFilters(newParams.filters);\n\n const transformedParams: CourseListSearchParams = {\n pageSize: newParams.pageSize,\n pageIndex: newParams.pageIndex,\n filters: transformedFilters,\n searchString: newParams.searchString || '',\n };\n\n setParams(prevParams => {\n const hasChanged = JSON.stringify(prevParams) !== JSON.stringify(transformedParams);\n return hasChanged ? transformedParams : prevParams;\n });\n }, []);\n\n return {\n data,\n isLoading,\n isError,\n error,\n fetchData,\n isFetching,\n };\n};\n"]}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/data/course-list-search/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAEpD;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAClC,QAAQ,GAAG,iBAAiB,EAC5B,SAAS,GAAG,kBAAkB,EAC9B,8BAA8B,GAAG,KAAK,EACtC,OAAO,GAAG,EAAE,EACZ,YAAY,GAAG,EAAE,MACkB,EAAE,EAAwB,EAAE;IAC/D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAyB;QAC3D,QAAQ;QACR,SAAS;QACT,8BAA8B;QAC9B,OAAO;QACP,YAAY;KACb,CAAC,CAAC;IAEH,MAAM,EACJ,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,GAC5C,GAAG,QAAQ,CAAkC;QAC5C,QAAQ,EAAE,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACtC,OAAO,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,MAAM,CAAC;QAC5C,eAAe,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY;KAChD,CAAC,CAAC;IAEH;;OAEG;IACH,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,SAAsD,EAAE,EAAE;QACvF,MAAM,kBAAkB,GAAG,yBAAyB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAExE,SAAS,CAAC,UAAU,CAAC,EAAE;YACrB,MAAM,iBAAiB,GAA2B;gBAChD,QAAQ,EAAE,SAAS,CAAC,QAAQ;gBAC5B,SAAS,EAAE,SAAS,CAAC,SAAS;gBAC9B,8BAA8B,EAAE,UAAU,CAAC,8BAA8B;gBACzE,OAAO,EAAE,kBAAkB;gBAC3B,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,EAAE;aAC3C,CAAC;YAEF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;YACpF,OAAO,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,UAAU,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,IAAI;QACJ,SAAS;QACT,OAAO;QACP,KAAK;QACL,SAAS;QACT,UAAU;KACX,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { useQuery } from '@tanstack/react-query';\nimport { useState, useCallback } from 'react';\n\nimport { fetchCourseListSearch } from './api';\nimport { DEFAULT_PAGE_SIZE, DEFAULT_PAGE_INDEX } from './constants';\nimport type {\n CourseListSearchResponse, CourseListSearchParams, CourseListSearchHook, DataTableParams,\n} from './types';\nimport { transformDataTableFilters } from './utils';\n\n/**\n * A React Query hook that fetches course list search data.\n */\nexport const useCourseListSearch = ({\n pageSize = DEFAULT_PAGE_SIZE,\n pageIndex = DEFAULT_PAGE_INDEX,\n enableCourseSortingByStartDate = false,\n filters = {},\n searchString = '',\n}: Partial<CourseListSearchParams> = {}): CourseListSearchHook => {\n const [params, setParams] = useState<CourseListSearchParams>({\n pageSize,\n pageIndex,\n enableCourseSortingByStartDate,\n filters,\n searchString,\n });\n\n const {\n data, isLoading, isError, error, isFetching,\n } = useQuery<CourseListSearchResponse, Error>({\n queryKey: ['courseListSearch', params],\n queryFn: () => fetchCourseListSearch(params),\n placeholderData: (previousData) => previousData,\n });\n\n /**\n * Updates query params and triggers data refetch if params have changed.\n */\n const fetchData = useCallback((newParams: DataTableParams & { searchString?: string }) => {\n const transformedFilters = transformDataTableFilters(newParams.filters);\n\n setParams(prevParams => {\n const transformedParams: CourseListSearchParams = {\n pageSize: newParams.pageSize,\n pageIndex: newParams.pageIndex,\n enableCourseSortingByStartDate: prevParams.enableCourseSortingByStartDate,\n filters: transformedFilters,\n searchString: newParams.searchString || '',\n };\n\n const hasChanged = JSON.stringify(prevParams) !== JSON.stringify(transformedParams);\n return hasChanged ? transformedParams : prevParams;\n });\n }, []);\n\n return {\n data,\n isLoading,\n isError,\n error,\n fetchData,\n isFetching,\n };\n};\n"]}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Link } from 'react-router-dom';
3
3
  import { Card, useMediaQuery, breakpoints, Badge, } from '@openedx/paragon';
4
- import { getUrlByRouteRole, useIntl } from '@openedx/frontend-base';
4
+ import { resolveRouteByRole, useIntl } from '@openedx/frontend-base';
5
5
  import noCourseImg from '../../assets/images/no-course-image.svg';
6
6
  import { courseAboutRole } from '../../constants';
7
7
  import messages from './messages';
@@ -15,7 +15,7 @@ export const CourseCard = ({ isLoading, courseId, courseOrg, courseName, courseN
15
15
  advertisedStart: courseAdvertisedStart,
16
16
  }, intl) : null;
17
17
  const courseAboutUrl = courseId
18
- ? (_a = getUrlByRouteRole(courseAboutRole)) === null || _a === void 0 ? void 0 : _a.replace(':courseId', courseId)
18
+ ? (_a = resolveRouteByRole(courseAboutRole, { courseId })) === null || _a === void 0 ? void 0 : _a.url
19
19
  : undefined;
20
20
  return (_jsxs(Card, { as: courseAboutUrl ? Link : 'div', to: courseAboutUrl,
21
21
  // TODO: Temporary use of `d-flex` to fix alignment. Remove once the related Paragon issue
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/generic/course-card/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EACL,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,GACxC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,WAAW,MAAM,wCAAwC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE/D,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EACzB,SAAS,EACT,QAAQ,EACR,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,eAAe,EACf,qBAAqB,GACL,EAAE,EAAE;;IACpB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,YAAY,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE7E,MAAM,gBAAgB,GAAG,CAAC,eAAe,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC;QACxF,KAAK,EAAE,eAAe;QACtB,eAAe,EAAE,qBAAqB;KACvC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEhB,MAAM,cAAc,GAAG,QAAQ;QAC7B,CAAC,CAAC,MAAA,iBAAiB,CAAC,eAAe,CAAC,0CAAE,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC;QACpE,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO,CACL,MAAC,IAAI,IACH,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EACjC,EAAE,EAAE,cAAc;QAClB,0FAA0F;QAC1F,gEAAgE;QAChE,SAAS,EAAE,sBAAsB,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,EAAE,EACjF,WAAW,EAAE,CAAC,SAAS,EACvB,SAAS,EAAE,SAAS,iBACR,aAAa,aAEzB,KAAC,IAAI,CAAC,QAAQ,IACZ,GAAG,EAAE,eAAe,CAAC,cAAc,CAAC,EACpC,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,GAAG,UAAU,IAAI,YAAY,EAAE,EACvC,uBAAuB,SACvB,EACF,KAAC,IAAI,CAAC,MAAM,IACV,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,CACR,8BACE,wBAAM,YAAY,GAAO,EACzB,KAAC,KAAK,IAAC,OAAO,EAAC,OAAO,YAAE,SAAS,GAAS,IACzC,CACJ,EACD,IAAI,EAAC,IAAI,GACT,EACF,KAAC,IAAI,CAAC,OAAO,KAAG,EAChB,KAAC,IAAI,CAAC,MAAM,IAAC,WAAW,EAAE,gBAAgB,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,EAAE;oBACnF,SAAS,EAAE,gBAAgB;iBAC5B,CAAC,GACA,IACG,CACR,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { Link } from 'react-router-dom';\nimport {\n Card, useMediaQuery, breakpoints, Badge,\n} from '@openedx/paragon';\nimport { getUrlByRouteRole, useIntl } from '@openedx/frontend-base';\n\nimport noCourseImg from '@src/assets/images/no-course-image.svg';\nimport { courseAboutRole } from '@src/constants';\n\nimport type { CourseCardProps } from './types';\nimport messages from './messages';\nimport { getFullImageUrl, getStartDateDisplay } from './utils';\n\nexport const CourseCard = ({\n isLoading,\n courseId,\n courseOrg,\n courseName,\n courseNumber,\n courseImageUrl,\n courseStartDate,\n courseAdvertisedStart,\n}: CourseCardProps) => {\n const intl = useIntl();\n const isExtraSmall = useMediaQuery({ maxWidth: breakpoints.small.maxWidth });\n\n const startDateDisplay = (courseStartDate || courseAdvertisedStart) ? getStartDateDisplay({\n start: courseStartDate,\n advertisedStart: courseAdvertisedStart,\n }, intl) : null;\n\n const courseAboutUrl = courseId\n ? getUrlByRouteRole(courseAboutRole)?.replace(':courseId', courseId)\n : undefined;\n\n return (\n <Card\n as={courseAboutUrl ? Link : 'div'}\n to={courseAboutUrl}\n // TODO: Temporary use of `d-flex` to fix alignment. Remove once the related Paragon issue\n // (https://github.com/openedx/paragon/issues/3792) is resolved.\n className={`course-card d-flex ${isExtraSmall ? 'w-100' : 'course-card-desktop'}`}\n isClickable={!isLoading}\n isLoading={isLoading}\n data-testid=\"course-card\"\n >\n <Card.ImageCap\n src={getFullImageUrl(courseImageUrl)}\n fallbackSrc={noCourseImg}\n srcAlt={`${courseName} ${courseNumber}`}\n skeletonDuringImageLoad\n />\n <Card.Header\n title={courseName}\n subtitle={(\n <>\n <div>{courseNumber}</div>\n <Badge variant=\"light\">{courseOrg}</Badge>\n </>\n )}\n size=\"sm\"\n />\n <Card.Section />\n <Card.Footer textElement={startDateDisplay && intl.formatMessage(messages.startDate, {\n startDate: startDateDisplay,\n })}\n />\n </Card>\n );\n};\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/generic/course-card/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EACL,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,GACxC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,WAAW,MAAM,wCAAwC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE/D,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EACzB,SAAS,EACT,QAAQ,EACR,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,eAAe,EACf,qBAAqB,GACL,EAAE,EAAE;;IACpB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,YAAY,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE7E,MAAM,gBAAgB,GAAG,CAAC,eAAe,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC;QACxF,KAAK,EAAE,eAAe;QACtB,eAAe,EAAE,qBAAqB;KACvC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEhB,MAAM,cAAc,GAAG,QAAQ;QAC7B,CAAC,CAAC,MAAA,kBAAkB,CAAC,eAAe,EAAE,EAAE,QAAQ,EAAE,CAAC,0CAAE,GAAG;QACxD,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO,CACL,MAAC,IAAI,IACH,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EACjC,EAAE,EAAE,cAAc;QAClB,0FAA0F;QAC1F,gEAAgE;QAChE,SAAS,EAAE,sBAAsB,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,EAAE,EACjF,WAAW,EAAE,CAAC,SAAS,EACvB,SAAS,EAAE,SAAS,iBACR,aAAa,aAEzB,KAAC,IAAI,CAAC,QAAQ,IACZ,GAAG,EAAE,eAAe,CAAC,cAAc,CAAC,EACpC,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,GAAG,UAAU,IAAI,YAAY,EAAE,EACvC,uBAAuB,SACvB,EACF,KAAC,IAAI,CAAC,MAAM,IACV,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,CACR,8BACE,wBAAM,YAAY,GAAO,EACzB,KAAC,KAAK,IAAC,OAAO,EAAC,OAAO,YAAE,SAAS,GAAS,IACzC,CACJ,EACD,IAAI,EAAC,IAAI,GACT,EACF,KAAC,IAAI,CAAC,OAAO,KAAG,EAChB,KAAC,IAAI,CAAC,MAAM,IAAC,WAAW,EAAE,gBAAgB,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,EAAE;oBACnF,SAAS,EAAE,gBAAgB;iBAC5B,CAAC,GACA,IACG,CACR,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { Link } from 'react-router-dom';\nimport {\n Card, useMediaQuery, breakpoints, Badge,\n} from '@openedx/paragon';\nimport { resolveRouteByRole, useIntl } from '@openedx/frontend-base';\n\nimport noCourseImg from '@src/assets/images/no-course-image.svg';\nimport { courseAboutRole } from '@src/constants';\n\nimport type { CourseCardProps } from './types';\nimport messages from './messages';\nimport { getFullImageUrl, getStartDateDisplay } from './utils';\n\nexport const CourseCard = ({\n isLoading,\n courseId,\n courseOrg,\n courseName,\n courseNumber,\n courseImageUrl,\n courseStartDate,\n courseAdvertisedStart,\n}: CourseCardProps) => {\n const intl = useIntl();\n const isExtraSmall = useMediaQuery({ maxWidth: breakpoints.small.maxWidth });\n\n const startDateDisplay = (courseStartDate || courseAdvertisedStart) ? getStartDateDisplay({\n start: courseStartDate,\n advertisedStart: courseAdvertisedStart,\n }, intl) : null;\n\n const courseAboutUrl = courseId\n ? resolveRouteByRole(courseAboutRole, { courseId })?.url\n : undefined;\n\n return (\n <Card\n as={courseAboutUrl ? Link : 'div'}\n to={courseAboutUrl}\n // TODO: Temporary use of `d-flex` to fix alignment. Remove once the related Paragon issue\n // (https://github.com/openedx/paragon/issues/3792) is resolved.\n className={`course-card d-flex ${isExtraSmall ? 'w-100' : 'course-card-desktop'}`}\n isClickable={!isLoading}\n isLoading={isLoading}\n data-testid=\"course-card\"\n >\n <Card.ImageCap\n src={getFullImageUrl(courseImageUrl)}\n fallbackSrc={noCourseImg}\n srcAlt={`${courseName} ${courseNumber}`}\n skeletonDuringImageLoad\n />\n <Card.Header\n title={courseName}\n subtitle={(\n <>\n <div>{courseNumber}</div>\n <Badge variant=\"light\">{courseOrg}</Badge>\n </>\n )}\n size=\"sm\"\n />\n <Card.Section />\n <Card.Footer textElement={startDateDisplay && intl.formatMessage(messages.startDate, {\n startDate: startDateDisplay,\n })}\n />\n </Card>\n );\n};\n"]}
@@ -8,7 +8,8 @@ import { DEFAULT_PAGE_INDEX } from '../../../data/course-list-search/constants';
8
8
  import HomeCourseCardSlot from '../../../slots/HomeCourseCardSlot';
9
9
  import { LoaderSlot } from '../../../slots/LoaderSlot';
10
10
  import { appId, coursesRole } from '../../../constants';
11
- import { getStringConfig } from '../../../config';
11
+ import { getCountConfig, getStringConfig } from '../../../config';
12
+ import { DEFAULT_COURSES_COUNT } from '../../../home/constants';
12
13
  import messages from './messages';
13
14
  const CARD_GRID_LAYOUT = {
14
15
  xs: 12, md: 6, lg: 4, xl: 3,
@@ -17,7 +18,7 @@ const CoursesList = () => {
17
18
  var _a, _b;
18
19
  const intl = useIntl();
19
20
  const navigate = useNavigate();
20
- const maxCourses = getAppConfig(appId).HOMEPAGE_COURSE_MAX;
21
+ const maxCourses = getCountConfig('HOMEPAGE_COURSE_MAX', DEFAULT_COURSES_COUNT);
21
22
  const { data: courseData, isLoading: isCoursesLoading, isError: isCoursesError, } = useCourseListSearch({
22
23
  pageSize: maxCourses,
23
24
  pageIndex: DEFAULT_PAGE_INDEX,
@@ -1 +1 @@
1
- {"version":3,"file":"CoursesList.js","sourceRoot":"","sources":["../../../../src/home/components/courses-list/CoursesList.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n ErrorPage, getAppConfig, getUrlByRouteRole, useIntl,\n} from '@openedx/frontend-base';\nimport {\n Alert, Button, CardGrid, Container,\n} from '@openedx/paragon';\nimport { useNavigate } from 'react-router';\n\nimport { useCourseListSearch } from '@src/data/course-list-search/hooks';\nimport { AlertNotification } from '@src/generic';\nimport { DEFAULT_PAGE_INDEX } from '@src/data/course-list-search/constants';\nimport HomeCourseCardSlot from '@src/slots/HomeCourseCardSlot';\nimport { LoaderSlot } from '@src/slots/LoaderSlot';\nimport { appId, coursesRole } from '@src/constants';\nimport { getStringConfig } from '@src/config';\n\nimport messages from './messages';\n\nconst CARD_GRID_LAYOUT = {\n xs: 12, md: 6, lg: 4, xl: 3,\n};\n\nconst CoursesList = () => {\n const intl = useIntl();\n const navigate = useNavigate();\n\n const maxCourses = getAppConfig(appId).HOMEPAGE_COURSE_MAX as number;\n\n const {\n data: courseData,\n isLoading: isCoursesLoading,\n isError: isCoursesError,\n } = useCourseListSearch({\n pageSize: maxCourses,\n pageIndex: DEFAULT_PAGE_INDEX,\n enableCourseSortingByStartDate: getAppConfig(appId).ENABLE_COURSE_SORTING_BY_START_DATE === true,\n });\n\n const handleNavigateToCoursesPage = () => {\n const coursesUrl = getUrlByRouteRole(coursesRole);\n if (coursesUrl) {\n navigate(coursesUrl);\n }\n };\n\n if (isCoursesLoading) {\n return (\n <Container className=\"py-6\" size=\"xl\" data-testid=\"courses-list-loading\">\n <LoaderSlot>\n <CardGrid columnSizes={CARD_GRID_LAYOUT}>\n {Array.from({ length: maxCourses }, (_, index) => (\n <HomeCourseCardSlot key={`courses-list-loading-skeleton-card-${index}`} isLoading />\n ))}\n </CardGrid>\n </LoaderSlot>\n </Container>\n );\n }\n\n if (isCoursesError) {\n return (\n <Container className=\"py-6\" size=\"xl\">\n <Alert className=\"my-0\" variant=\"danger\">\n <ErrorPage\n // @ts-expect-error frontend-base ErrorPage declares message?: null but renders the prop as text. Remove when typing is fixed upstream.\n message={intl.formatMessage(messages.errorMessage, {\n supportEmail: getStringConfig('INFO_EMAIL'),\n })}\n />\n </Alert>\n </Container>\n );\n }\n\n if (getAppConfig(appId).NON_BROWSABLE_COURSES) {\n return null;\n }\n\n return (\n <Container\n className=\"py-6\"\n size=\"xl\"\n data-testid=\"courses-list\"\n >\n {!courseData?.results?.length ? (\n <AlertNotification\n className=\"my-0\"\n variant=\"info\"\n title={intl.formatMessage(messages.noCoursesAvailable)}\n message={intl.formatMessage(messages.noCoursesAvailableMessage)}\n />\n ) : (\n <Container className=\"text-center\">\n <CardGrid columnSizes={CARD_GRID_LAYOUT}>\n {courseData?.results?.map(course => (\n <HomeCourseCardSlot key={course.id} original={course} />\n ))}\n </CardGrid>\n {courseData?.total > maxCourses && (\n <Button\n className=\"mt-3\"\n variant=\"brand\"\n onClick={handleNavigateToCoursesPage}\n >\n {intl.formatMessage(messages.viewAllCoursesButton)}\n </Button>\n )}\n </Container>\n )}\n </Container>\n );\n};\n\nexport default CoursesList;\n"]}
1
+ {"version":3,"file":"CoursesList.js","sourceRoot":"","sources":["../../../../src/home/components/courses-list/CoursesList.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n ErrorPage, getAppConfig, getUrlByRouteRole, useIntl,\n} from '@openedx/frontend-base';\nimport {\n Alert, Button, CardGrid, Container,\n} from '@openedx/paragon';\nimport { useNavigate } from 'react-router';\n\nimport { useCourseListSearch } from '@src/data/course-list-search/hooks';\nimport { AlertNotification } from '@src/generic';\nimport { DEFAULT_PAGE_INDEX } from '@src/data/course-list-search/constants';\nimport HomeCourseCardSlot from '@src/slots/HomeCourseCardSlot';\nimport { LoaderSlot } from '@src/slots/LoaderSlot';\nimport { appId, coursesRole } from '@src/constants';\nimport { getCountConfig, getStringConfig } from '@src/config';\nimport { DEFAULT_COURSES_COUNT } from '@src/home/constants';\n\nimport messages from './messages';\n\nconst CARD_GRID_LAYOUT = {\n xs: 12, md: 6, lg: 4, xl: 3,\n};\n\nconst CoursesList = () => {\n const intl = useIntl();\n const navigate = useNavigate();\n\n const maxCourses = getCountConfig('HOMEPAGE_COURSE_MAX', DEFAULT_COURSES_COUNT);\n\n const {\n data: courseData,\n isLoading: isCoursesLoading,\n isError: isCoursesError,\n } = useCourseListSearch({\n pageSize: maxCourses,\n pageIndex: DEFAULT_PAGE_INDEX,\n enableCourseSortingByStartDate: getAppConfig(appId).ENABLE_COURSE_SORTING_BY_START_DATE === true,\n });\n\n const handleNavigateToCoursesPage = () => {\n const coursesUrl = getUrlByRouteRole(coursesRole);\n if (coursesUrl) {\n navigate(coursesUrl);\n }\n };\n\n if (isCoursesLoading) {\n return (\n <Container className=\"py-6\" size=\"xl\" data-testid=\"courses-list-loading\">\n <LoaderSlot>\n <CardGrid columnSizes={CARD_GRID_LAYOUT}>\n {Array.from({ length: maxCourses }, (_, index) => (\n <HomeCourseCardSlot key={`courses-list-loading-skeleton-card-${index}`} isLoading />\n ))}\n </CardGrid>\n </LoaderSlot>\n </Container>\n );\n }\n\n if (isCoursesError) {\n return (\n <Container className=\"py-6\" size=\"xl\">\n <Alert className=\"my-0\" variant=\"danger\">\n <ErrorPage\n // @ts-expect-error frontend-base ErrorPage declares message?: null but renders the prop as text. Remove when typing is fixed upstream.\n message={intl.formatMessage(messages.errorMessage, {\n supportEmail: getStringConfig('INFO_EMAIL'),\n })}\n />\n </Alert>\n </Container>\n );\n }\n\n if (getAppConfig(appId).NON_BROWSABLE_COURSES) {\n return null;\n }\n\n return (\n <Container\n className=\"py-6\"\n size=\"xl\"\n data-testid=\"courses-list\"\n >\n {!courseData?.results?.length ? (\n <AlertNotification\n className=\"my-0\"\n variant=\"info\"\n title={intl.formatMessage(messages.noCoursesAvailable)}\n message={intl.formatMessage(messages.noCoursesAvailableMessage)}\n />\n ) : (\n <Container className=\"text-center\">\n <CardGrid columnSizes={CARD_GRID_LAYOUT}>\n {courseData?.results?.map(course => (\n <HomeCourseCardSlot key={course.id} original={course} />\n ))}\n </CardGrid>\n {courseData?.total > maxCourses && (\n <Button\n className=\"mt-3\"\n variant=\"brand\"\n onClick={handleNavigateToCoursesPage}\n >\n {intl.formatMessage(messages.viewAllCoursesButton)}\n </Button>\n )}\n </Container>\n )}\n </Container>\n );\n};\n\nexport default CoursesList;\n"]}
@@ -0,0 +1 @@
1
+ export declare const DEFAULT_COURSES_COUNT = 9;
@@ -0,0 +1,2 @@
1
+ export const DEFAULT_COURSES_COUNT = 9;
2
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/home/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC","sourcesContent":["export const DEFAULT_COURSES_COUNT = 9;\n"]}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@openedx/frontend-app-catalog",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0-alpha.4",
4
+ "packageManager": "npm@11.12.1",
4
5
  "description": "Frontend catalog application",
5
6
  "repository": {
6
7
  "type": "git",
@@ -62,6 +63,8 @@
62
63
  },
63
64
  "devDependencies": {
64
65
  "@edx/browserslist-config": "^1.5.0",
66
+ "@openedx/frontend-base": "^2.0.0-alpha.15 || 0.0.0-dev",
67
+ "@openedx/paragon": "^23 || 0.0.0-dev",
65
68
  "@testing-library/jest-dom": "^6.9.1",
66
69
  "@testing-library/react": "^16.3.0",
67
70
  "@testing-library/user-event": "^14.6.1",
@@ -72,11 +75,12 @@
72
75
  "jest": "^29",
73
76
  "nodemon": "^3.1.14",
74
77
  "tsc-alias": "^1.8.16",
75
- "turbo": "^2.9.2"
78
+ "turbo": "^2.9.2",
79
+ "typescript": "^5.9.3"
76
80
  },
77
81
  "peerDependencies": {
78
- "@openedx/frontend-base": "^2.0.0-alpha.4 || 0.0.0-dev",
79
- "@openedx/paragon": "^23",
82
+ "@openedx/frontend-base": "^2.0.0-alpha.15 || 0.0.0-dev",
83
+ "@openedx/paragon": "^23 || 0.0.0-dev",
80
84
  "@tanstack/react-query": "^5",
81
85
  "react": "^18",
82
86
  "react-dom": "^18",