diff --git a/.env b/.env index 3521dee..52ce6a0 100644 --- a/.env +++ b/.env @@ -26,9 +26,4 @@ COLLECT_YEAR_OF_BIRTH=true APP_ID='' MFE_CONFIG_API_URL='' SEARCH_CATALOG_URL='' -ENABLE_SKILLS_BUILDER='' ENABLE_SKILLS_BUILDER_PROFILE='' -ALGOLIA_APP_ID='' -ALGOLIA_JOBS_INDEX_NAME='' -ALGOLIA_PRODUCT_INDEX_NAME='' -ALGOLIA_SEARCH_API_KEY='' diff --git a/.env.development b/.env.development index e0b32bf..6b42cba 100644 --- a/.env.development +++ b/.env.development @@ -27,9 +27,4 @@ COLLECT_YEAR_OF_BIRTH=true APP_ID='' MFE_CONFIG_API_URL='' SEARCH_CATALOG_URL='http://localhost:18000/courses' -ENABLE_SKILLS_BUILDER='true' ENABLE_SKILLS_BUILDER_PROFILE='' -ALGOLIA_APP_ID='' -ALGOLIA_JOBS_INDEX_NAME='' -ALGOLIA_PRODUCT_INDEX_NAME='' -ALGOLIA_SEARCH_API_KEY='' diff --git a/.env.test b/.env.test index 0b6574a..b79d85c 100644 --- a/.env.test +++ b/.env.test @@ -18,13 +18,8 @@ LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico ENABLE_LEARNER_RECORD_MFE='' -ENABLE_SKILLS_BUILDER='true' ENABLE_SKILLS_BUILDER_PROFILE='' LEARNER_RECORD_MFE_BASE_URL='http://localhost:1990' COLLECT_YEAR_OF_BIRTH=true APP_ID='' MFE_CONFIG_API_URL='' -ALGOLIA_APP_ID='' -ALGOLIA_JOBS_INDEX_NAME='' -ALGOLIA_PRODUCT_INDEX_NAME='' -ALGOLIA_SEARCH_API_KEY='' diff --git a/package-lock.json b/package-lock.json index fbccca8..b0bda80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ "@fortawesome/free-regular-svg-icons": "5.15.4", "@fortawesome/free-solid-svg-icons": "5.15.4", "@fortawesome/react-fontawesome": "0.2.0", - "algoliasearch": "4.18.0", "classnames": "2.3.2", "core-js": "3.31.0", "history": "4.10.1", @@ -31,7 +30,6 @@ "react": "16.14.0", "react-dom": "16.14.0", "react-helmet": "6.1.0", - "react-instantsearch-hooks-web": "^6.45.0", "react-redux": "7.2.9", "react-router": "5.3.4", "react-router-dom": "5.3.4", @@ -51,7 +49,6 @@ "@edx/frontend-build": "12.8.57", "@edx/reactifex": "2.2.0", "@testing-library/react": "11.2.7", - "@testing-library/react-hooks": "^8.0.1", "codecov": "3.8.3", "enzyme": "3.11.0", "enzyme-adapter-react-16": "1.15.7", @@ -61,140 +58,6 @@ "redux-mock-store": "1.5.4" } }, - "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.18.0.tgz", - "integrity": "sha512-rUAs49NLlO8LVLgGzM4cLkw8NJLKguQLgvFmBEe3DyzlinoqxzQMHfKZs6TSq4LZfw/z8qHvRo8NcTAAUJQLcw==", - "dependencies": { - "@algolia/cache-common": "4.18.0" - } - }, - "node_modules/@algolia/cache-common": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.18.0.tgz", - "integrity": "sha512-BmxsicMR4doGbeEXQu8yqiGmiyvpNvejYJtQ7rvzttEAMxOPoWEHrWyzBQw4x7LrBY9pMrgv4ZlUaF8PGzewHg==" - }, - "node_modules/@algolia/cache-in-memory": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.18.0.tgz", - "integrity": "sha512-evD4dA1nd5HbFdufBxLqlJoob7E2ozlqJZuV3YlirNx5Na4q1LckIuzjNYZs2ddLzuTc/Xd5O3Ibf7OwPskHxw==", - "dependencies": { - "@algolia/cache-common": "4.18.0" - } - }, - "node_modules/@algolia/client-account": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.18.0.tgz", - "integrity": "sha512-XsDnlROr3+Z1yjxBJjUMfMazi1V155kVdte6496atvBgOEtwCzTs3A+qdhfsAnGUvaYfBrBkL0ThnhMIBCGcew==", - "dependencies": { - "@algolia/client-common": "4.18.0", - "@algolia/client-search": "4.18.0", - "@algolia/transporter": "4.18.0" - } - }, - "node_modules/@algolia/client-analytics": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.18.0.tgz", - "integrity": "sha512-chEUSN4ReqU7uRQ1C8kDm0EiPE+eJeAXiWcBwLhEynfNuTfawN9P93rSZktj7gmExz0C8XmkbBU19IQ05wCNrQ==", - "dependencies": { - "@algolia/client-common": "4.18.0", - "@algolia/client-search": "4.18.0", - "@algolia/requester-common": "4.18.0", - "@algolia/transporter": "4.18.0" - } - }, - "node_modules/@algolia/client-common": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.18.0.tgz", - "integrity": "sha512-7N+soJFP4wn8tjTr3MSUT/U+4xVXbz4jmeRfWfVAzdAbxLAQbHa0o/POSdTvQ8/02DjCLelloZ1bb4ZFVKg7Wg==", - "dependencies": { - "@algolia/requester-common": "4.18.0", - "@algolia/transporter": "4.18.0" - } - }, - "node_modules/@algolia/client-personalization": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.18.0.tgz", - "integrity": "sha512-+PeCjODbxtamHcPl+couXMeHEefpUpr7IHftj4Y4Nia1hj8gGq4VlIcqhToAw8YjLeCTfOR7r7xtj3pJcYdP8A==", - "dependencies": { - "@algolia/client-common": "4.18.0", - "@algolia/requester-common": "4.18.0", - "@algolia/transporter": "4.18.0" - } - }, - "node_modules/@algolia/client-search": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.18.0.tgz", - "integrity": "sha512-F9xzQXTjm6UuZtnsLIew6KSraXQ0AzS/Ee+OD+mQbtcA/K1sg89tqb8TkwjtiYZ0oij13u3EapB3gPZwm+1Y6g==", - "dependencies": { - "@algolia/client-common": "4.18.0", - "@algolia/requester-common": "4.18.0", - "@algolia/transporter": "4.18.0" - } - }, - "node_modules/@algolia/events": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", - "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" - }, - "node_modules/@algolia/logger-common": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.18.0.tgz", - "integrity": "sha512-46etYgSlkoKepkMSyaoriSn2JDgcrpc/nkOgou/lm0y17GuMl9oYZxwKKTSviLKI5Irk9nSKGwnBTQYwXOYdRg==" - }, - "node_modules/@algolia/logger-console": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.18.0.tgz", - "integrity": "sha512-3P3VUYMl9CyJbi/UU1uUNlf6Z8N2ltW3Oqhq/nR7vH0CjWv32YROq3iGWGxB2xt3aXobdUPXs6P0tHSKRmNA6g==", - "dependencies": { - "@algolia/logger-common": "4.18.0" - } - }, - "node_modules/@algolia/requester-browser-xhr": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.18.0.tgz", - "integrity": "sha512-/AcWHOBub2U4TE/bPi4Gz1XfuLK6/7dj4HJG+Z2SfQoS1RjNLshZclU3OoKIkFp8D2NC7+BNsPvr9cPLyW8nyQ==", - "dependencies": { - "@algolia/requester-common": "4.18.0" - } - }, - "node_modules/@algolia/requester-common": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.18.0.tgz", - "integrity": "sha512-xlT8R1qYNRBCi1IYLsx7uhftzdfsLPDGudeQs+xvYB4sQ3ya7+ppolB/8m/a4F2gCkEO6oxpp5AGemM7kD27jA==" - }, - "node_modules/@algolia/requester-node-http": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.18.0.tgz", - "integrity": "sha512-TGfwj9aeTVgOUhn5XrqBhwUhUUDnGIKlI0kCBMdR58XfXcfdwomka+CPIgThRbfYw04oQr31A6/95ZH2QVJ9UQ==", - "dependencies": { - "@algolia/requester-common": "4.18.0" - } - }, - "node_modules/@algolia/transporter": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.18.0.tgz", - "integrity": "sha512-xbw3YRUGtXQNG1geYFEDDuFLZt4Z8YNKbamHPkzr3rWc6qp4/BqEeXcI2u/P/oMq2yxtXgMxrCxOPA8lyIe5jw==", - "dependencies": { - "@algolia/cache-common": "4.18.0", - "@algolia/logger-common": "4.18.0", - "@algolia/requester-common": "4.18.0" - } - }, - "node_modules/@algolia/ui-components-highlight-vdom": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@algolia/ui-components-highlight-vdom/-/ui-components-highlight-vdom-1.2.1.tgz", - "integrity": "sha512-IlYgIaCUEkz9ezNbwugwKv991oOHhveyq6nzL0F1jDzg1p3q5Yj/vO4KpNG910r2dwGCG3nEm5GtChcLnarhFA==", - "dependencies": { - "@algolia/ui-components-shared": "1.2.1", - "@babel/runtime": "^7.0.0" - } - }, - "node_modules/@algolia/ui-components-shared": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@algolia/ui-components-shared/-/ui-components-shared-1.2.1.tgz", - "integrity": "sha512-a7mYHf/GVQfhAx/HRiMveKkFvHspQv/REdG+C/FIOosiSmNZxX7QebDwJkrGSmDWdXO12D0Qv1xn3AytFcEDlQ==" - }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -4380,36 +4243,6 @@ "react-dom": "*" } }, - "node_modules/@testing-library/react-hooks": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz", - "integrity": "sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "react-error-boundary": "^3.1.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "@types/react": "^16.9.0 || ^17.0.0", - "react": "^16.9.0 || ^17.0.0", - "react-dom": "^16.9.0 || ^17.0.0", - "react-test-renderer": "^16.9.0 || ^17.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-test-renderer": { - "optional": true - } - } - }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -4532,11 +4365,6 @@ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==" }, - "node_modules/@types/dom-speech-recognition": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@types/dom-speech-recognition/-/dom-speech-recognition-0.0.1.tgz", - "integrity": "sha512-udCxb8DvjcDKfk1WTBzDsxFbLgYxmQGKrE/ricoMqHRNjSlSUCcamVTA5lIQqzY10mY5qCY0QDwBfFEwhfoDPw==" - }, "node_modules/@types/eslint": { "version": "8.37.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", @@ -4598,11 +4426,6 @@ "@types/node": "*" } }, - "node_modules/@types/google.maps": { - "version": "3.52.6", - "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.52.6.tgz", - "integrity": "sha512-CnwN5UcezNiRuJzV0wGIsqXWNwMM6WzIxmy9lOUx+yauRQMee5XH/N7NaVOsiY5T5ygrnBwPO+csND652HYsTQ==" - }, "node_modules/@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -4611,11 +4434,6 @@ "@types/node": "*" } }, - "node_modules/@types/hogan.js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/hogan.js/-/hogan.js-3.0.1.tgz", - "integrity": "sha512-D03i/2OY7kGyMq9wdQ7oD8roE49z/ZCZThe/nbahtvuqCNZY9T2MfedOWyeBdbEpY2W8Gnh/dyJLdFtUCOkYbg==" - }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", @@ -5087,11 +4905,6 @@ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -5255,38 +5068,6 @@ "ajv": "^8.8.2" } }, - "node_modules/algoliasearch": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.18.0.tgz", - "integrity": "sha512-pCuVxC1SVcpc08ENH32T4sLKSyzoU7TkRIDBMwSLfIiW+fq4znOmWDkAygHZ6pRcO9I1UJdqlfgnV7TRj+MXrA==", - "dependencies": { - "@algolia/cache-browser-local-storage": "4.18.0", - "@algolia/cache-common": "4.18.0", - "@algolia/cache-in-memory": "4.18.0", - "@algolia/client-account": "4.18.0", - "@algolia/client-analytics": "4.18.0", - "@algolia/client-common": "4.18.0", - "@algolia/client-personalization": "4.18.0", - "@algolia/client-search": "4.18.0", - "@algolia/logger-common": "4.18.0", - "@algolia/logger-console": "4.18.0", - "@algolia/requester-browser-xhr": "4.18.0", - "@algolia/requester-common": "4.18.0", - "@algolia/requester-node-http": "4.18.0", - "@algolia/transporter": "4.18.0" - } - }, - "node_modules/algoliasearch-helper": { - "version": "3.13.2", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.13.2.tgz", - "integrity": "sha512-1bZjtHuqCBYw7Eu3Qh0Jfq4s63UcbOs6VvLPdt7kxn5+zMgs46xiXgc65YhZBNM3hDGrudhAX9hDhE9OP+rKUw==", - "dependencies": { - "@algolia/events": "^4.0.1" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -10242,18 +10023,6 @@ "value-equal": "^1.0.1" } }, - "node_modules/hogan.js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", - "integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==", - "dependencies": { - "mkdirp": "0.3.0", - "nopt": "1.0.10" - }, - "bin": { - "hulk": "bin/hulk" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -10335,11 +10104,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/htm": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/htm/-/htm-3.1.1.tgz", - "integrity": "sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==" - }, "node_modules/html-element-map": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.3.1.tgz", @@ -10780,29 +10544,6 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, - "node_modules/instantsearch.js": { - "version": "4.56.3", - "resolved": "https://registry.npmjs.org/instantsearch.js/-/instantsearch.js-4.56.3.tgz", - "integrity": "sha512-ImMIMaqLL+n0PU3aQWaiX6TFg9h13ys4AY/NcZ4Ew7OVw20dzHYQeyCDZVdDJ52BHrO53fNZ7+omnG5ZF6v6xg==", - "dependencies": { - "@algolia/events": "^4.0.1", - "@algolia/ui-components-highlight-vdom": "^1.2.1", - "@algolia/ui-components-shared": "^1.2.1", - "@types/dom-speech-recognition": "^0.0.1", - "@types/google.maps": "^3.45.3", - "@types/hogan.js": "^3.0.0", - "@types/qs": "^6.5.3", - "algoliasearch-helper": "^3.13.2", - "hogan.js": "^3.0.2", - "htm": "^3.0.0", - "preact": "^10.10.0", - "qs": "^6.5.1 < 6.10", - "search-insights": "^2.6.0" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 6" - } - }, "node_modules/internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", @@ -13169,15 +12910,6 @@ "node": ">=0.10.0" } }, - "node_modules/mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "engines": { - "node": "*" - } - }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -13416,20 +13148,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -14751,15 +14469,6 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, - "node_modules/preact": { - "version": "10.13.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.13.2.tgz", - "integrity": "sha512-q44QFLhOhty2Bd0Y46fnYW0gD/cbVM9dUVtNTDKPcdXSMA7jfY+Jpd6rk3GB0lcQss0z5s/6CmVP0Z/hV+g6pw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, "node_modules/prebuild-install": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", @@ -15261,22 +14970,6 @@ "react": ">= 16.8 || 18.0.0" } }, - "node_modules/react-error-boundary": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", - "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, - "peerDependencies": { - "react": ">=16.13.1" - } - }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", @@ -15349,36 +15042,6 @@ "react": ">=16.3.0" } }, - "node_modules/react-instantsearch-hooks": { - "version": "6.45.0", - "resolved": "https://registry.npmjs.org/react-instantsearch-hooks/-/react-instantsearch-hooks-6.45.0.tgz", - "integrity": "sha512-SjE3lhWA+1saajDJ1YULQ1n+Fo0g3lWhnKMAXYrF0p5COKeCbJns6CmIH2t42H3hoTcmQz0Qm0WDfLaRAjssPQ==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "algoliasearch-helper": "^3.13.2", - "instantsearch.js": "4.56.3", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.8.0 < 19" - } - }, - "node_modules/react-instantsearch-hooks-web": { - "version": "6.45.0", - "resolved": "https://registry.npmjs.org/react-instantsearch-hooks-web/-/react-instantsearch-hooks-web-6.45.0.tgz", - "integrity": "sha512-/VOnDoQbyL4rY8tYtnnr8vPKKTyTupZQ+K26GWspid1izlDY7KLWZvtvcdePTrv3DU5bQhSxgD6/3WUmUtiYQQ==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "instantsearch.js": "4.56.3", - "react-instantsearch-hooks": "6.45.0" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.8.0 < 19", - "react-dom": ">= 16.8.0 < 19" - } - }, "node_modules/react-intl": { "version": "5.25.1", "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-5.25.1.tgz", @@ -16787,14 +16450,6 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "node_modules/search-insights": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.6.0.tgz", - "integrity": "sha512-vU2/fJ+h/Mkm/DJOe+EaM5cafJv/1rRTZpGJTuFPf/Q5LjzgMDsqPdSaZsAe+GAWHHsfsu+rQSAn6c8IGtBEVw==", - "engines": { - "node": ">=8.16.0" - } - }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -18892,14 +18547,6 @@ } } }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index cec2090..a072411 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "@fortawesome/free-regular-svg-icons": "5.15.4", "@fortawesome/free-solid-svg-icons": "5.15.4", "@fortawesome/react-fontawesome": "0.2.0", - "algoliasearch": "4.18.0", "classnames": "2.3.2", "core-js": "3.31.0", "history": "4.10.1", @@ -49,7 +48,6 @@ "react": "16.14.0", "react-dom": "16.14.0", "react-helmet": "6.1.0", - "react-instantsearch-hooks-web": "^6.40.1", "react-redux": "7.2.9", "react-router": "5.3.4", "react-router-dom": "5.3.4", @@ -69,7 +67,6 @@ "@edx/frontend-build": "12.8.57", "@edx/reactifex": "2.2.0", "@testing-library/react": "11.2.7", - "@testing-library/react-hooks": "^8.0.1", "codecov": "3.8.3", "enzyme": "3.11.0", "enzyme-adapter-react-16": "1.15.7", diff --git a/src/index.jsx b/src/index.jsx index 1a38ded..8a6bde8 100755 --- a/src/index.jsx +++ b/src/index.jsx @@ -52,13 +52,7 @@ initialize({ config: () => { mergeConfig({ COLLECT_YEAR_OF_BIRTH: process.env.COLLECT_YEAR_OF_BIRTH, - ENABLE_SKILLS_BUILDER: process.env.ENABLE_SKILLS_BUILDER, ENABLE_SKILLS_BUILDER_PROFILE: process.env.ENABLE_SKILLS_BUILDER_PROFILE, - ALGOLIA_APP_ID: process.env.ALGOLIA_APP_ID || null, - ALGOLIA_JOBS_INDEX_NAME: process.env.ALGOLIA_JOBS_INDEX_NAME || null, - ALGOLIA_PRODUCT_INDEX_NAME: process.env.ALGOLIA_PRODUCT_INDEX_NAME || null, - ALGOLIA_SEARCH_API_KEY: process.env.ALGOLIA_SEARCH_API_KEY || null, - MARKETING_SITE_SEARCH_URL: process.env.SEARCH_CATALOG_URL || null, }, 'App loadConfig override handler'); }, }, diff --git a/src/index.scss b/src/index.scss index 7b80a2b..173e0ec 100755 --- a/src/index.scss +++ b/src/index.scss @@ -6,6 +6,3 @@ @import "~@edx/frontend-component-footer/dist/footer"; @import './profile/index'; - -@import './skills-builder/skills-builder-modal/skillsBuilderModal.scss'; -@import './skills-builder/skills-builder-header/skillsBuilderHeader.scss'; diff --git a/src/routes/AppRoutes.jsx b/src/routes/AppRoutes.jsx index 8d202ef..097e359 100644 --- a/src/routes/AppRoutes.jsx +++ b/src/routes/AppRoutes.jsx @@ -1,18 +1,13 @@ import React from 'react'; -import { getConfig } from '@edx/frontend-platform'; import { AuthenticatedPageRoute, PageRoute, } from '@edx/frontend-platform/react'; import { Switch } from 'react-router-dom'; import { ProfilePage, NotFoundPage } from '../profile'; -import { SkillsBuilder } from '../skills-builder'; const AppRoutes = () => ( - {getConfig().ENABLE_SKILLS_BUILDER && ( - - )} diff --git a/src/routes/routes.test.jsx b/src/routes/routes.test.jsx index c344814..daa0ffa 100644 --- a/src/routes/routes.test.jsx +++ b/src/routes/routes.test.jsx @@ -13,21 +13,11 @@ jest.mock('@edx/frontend-platform/auth', () => ({ getLoginRedirectUrl: jest.fn(), })); -jest.mock('@edx/frontend-platform', () => ({ - getConfig: jest.fn(() => ({ - ENABLE_SKILLS_BUILDER: true, - })), -})); - jest.mock('../profile', () => ({ ProfilePage: () => (
Profile page
), NotFoundPage: () => (
Not found page
), })); -jest.mock('../skills-builder', () => ({ - SkillsBuilder: () => (
Skills Builder
), -})); - const RoutesWithProvider = (context, history) => ( @@ -73,14 +63,6 @@ describe('routes', () => { expect(screen.getByText('Profile page')).toBeTruthy(); }); - test('Skills Builder page should be accessible to unauthenticated users', () => { - history.push('/skills'); - render( - RoutesWithProvider(unauthenticatedUser, history), - ); - expect(screen.getByText('Skills Builder')).toBeTruthy(); - }); - test('should show NotFound page for a bad route', () => { history.push('/nonMatchingRoute'); render( diff --git a/src/skills-builder/SkillsBuilder.jsx b/src/skills-builder/SkillsBuilder.jsx deleted file mode 100644 index 0ebc3a5..0000000 --- a/src/skills-builder/SkillsBuilder.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { SkillsBuilderModal } from './skills-builder-modal'; -import { SkillsBuilderProvider } from './skills-builder-context'; - -const SkillsBuilder = () => ( - - - -); - -export default SkillsBuilder; diff --git a/src/skills-builder/data/actions.js b/src/skills-builder/data/actions.js deleted file mode 100644 index 70839e5..0000000 --- a/src/skills-builder/data/actions.js +++ /dev/null @@ -1,26 +0,0 @@ -import { - SET_GOAL, - SET_CURRENT_JOB_TITLE, - ADD_CAREER_INTEREST, - REMOVE_CAREER_INTEREST, -} from './constants'; - -export const setGoal = (payload) => ({ - type: SET_GOAL, - payload, -}); - -export const setCurrentJobTitle = (payload) => ({ - type: SET_CURRENT_JOB_TITLE, - payload, -}); - -export const addCareerInterest = (payload) => ({ - type: ADD_CAREER_INTEREST, - payload, -}); - -export const removeCareerInterest = (payload) => ({ - type: REMOVE_CAREER_INTEREST, - payload, -}); diff --git a/src/skills-builder/data/constants.js b/src/skills-builder/data/constants.js deleted file mode 100644 index 9bfe1ff..0000000 --- a/src/skills-builder/data/constants.js +++ /dev/null @@ -1,9 +0,0 @@ -// Actions for Skills Context -export const SET_GOAL = 'SET_GOAL'; -export const SET_CURRENT_JOB_TITLE = 'SET_CURRENT_JOB_TITLE'; -export const ADD_CAREER_INTEREST = 'ADD_CAREER_INTEREST'; -export const REMOVE_CAREER_INTEREST = 'REMOVE_CAREER_INTEREST'; - -// Stepper keys -export const STEP1 = 'select-your-preferences'; -export const STEP2 = 'review-your-results'; diff --git a/src/skills-builder/data/reducer.js b/src/skills-builder/data/reducer.js deleted file mode 100644 index e8876e0..0000000 --- a/src/skills-builder/data/reducer.js +++ /dev/null @@ -1,41 +0,0 @@ -import { - SET_GOAL, - SET_CURRENT_JOB_TITLE, - ADD_CAREER_INTEREST, - REMOVE_CAREER_INTEREST, -} from './constants'; - -export function skillsReducer(state, action) { - switch (action.type) { - case SET_GOAL: - return { - ...state, - currentGoal: action.payload, - }; - case SET_CURRENT_JOB_TITLE: - return { - ...state, - currentJobTitle: action.payload, - }; - case ADD_CAREER_INTEREST: - return { - ...state, - careerInterests: [...state.careerInterests, action.payload], - }; - case REMOVE_CAREER_INTEREST: - return { - ...state, - careerInterests: state.careerInterests.filter(interest => interest !== action.payload), - }; - default: - return state; - } -} - -export const skillsInitialState = { - currentGoal: '', - currentJobTitle: '', - careerInterests: [], -}; - -export default skillsReducer; diff --git a/src/skills-builder/data/test/reducer.test.js b/src/skills-builder/data/test/reducer.test.js deleted file mode 100644 index 07b11dd..0000000 --- a/src/skills-builder/data/test/reducer.test.js +++ /dev/null @@ -1,60 +0,0 @@ -import { skillsReducer, skillsInitialState } from '../reducer'; -import { - SET_GOAL, - SET_CURRENT_JOB_TITLE, - ADD_CAREER_INTEREST, - REMOVE_CAREER_INTEREST, -} from '../constants'; - -describe('skillsReducer', () => { - const testState = skillsInitialState; - beforeEach(() => jest.resetModules()); - - it('does not remove present data when SET_GOAL action is dispatched', () => { - const newGoalPayload = 'test-goal'; - const returnedState = skillsReducer(testState, { type: SET_GOAL, payload: newGoalPayload }); - const finalState = { - ...testState, - currentGoal: 'test-goal', - }; - expect(returnedState).toEqual(finalState); - }); - - it('does not remove present data when SET_JOB_TITLE action is dispatched', () => { - const newJobTitlePayload = 'test-job-title'; - const returnedState = skillsReducer(testState, { type: SET_CURRENT_JOB_TITLE, payload: newJobTitlePayload }); - const finalState = { - ...testState, - currentJobTitle: 'test-job-title', - }; - expect(returnedState).toEqual(finalState); - }); - - it('adds a careerInterest when ADD_CAREER_INTEREST action is dispatched', () => { - const newCareerInterestPayload = 'test-career-interest'; - const returnedState = skillsReducer(testState, { type: ADD_CAREER_INTEREST, payload: newCareerInterestPayload }); - const finalState = { - ...testState, - careerInterests: [...testState.careerInterests, 'test-career-interest'], - }; - expect(returnedState).toEqual(finalState); - }); - - it('removes a careerInterest when REMOVE_CAREER_INTEREST action is dispatched', () => { - const newCareerInterestPayload = 'test-career-interest'; - const testStateWithInterest = { - ...testState, - careerInterests: [newCareerInterestPayload], - }; - const returnedState = skillsReducer( - testStateWithInterest, - { type: REMOVE_CAREER_INTEREST, payload: newCareerInterestPayload }, - ); - const finalState = { - ...testStateWithInterest, - // override the 'careerInterests` field and remove 'test-career-interest' from the array - careerInterests: testStateWithInterest.careerInterests.filter(interest => interest !== newCareerInterestPayload), - }; - expect(returnedState).toEqual(finalState); - }); -}); diff --git a/src/skills-builder/images/card-imagecap-fallback.png b/src/skills-builder/images/card-imagecap-fallback.png deleted file mode 100644 index 1b03102..0000000 Binary files a/src/skills-builder/images/card-imagecap-fallback.png and /dev/null differ diff --git a/src/skills-builder/images/edX-logo.svg b/src/skills-builder/images/edX-logo.svg deleted file mode 100644 index 400cff1..0000000 --- a/src/skills-builder/images/edX-logo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/skills-builder/images/headerImage.png b/src/skills-builder/images/headerImage.png deleted file mode 100644 index 9df8987..0000000 Binary files a/src/skills-builder/images/headerImage.png and /dev/null differ diff --git a/src/skills-builder/index.js b/src/skills-builder/index.js deleted file mode 100644 index f6dd83e..0000000 --- a/src/skills-builder/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/prefer-default-export -export { default as SkillsBuilder } from './SkillsBuilder'; diff --git a/src/skills-builder/skills-builder-context/SkillsBuilderProvider.jsx b/src/skills-builder/skills-builder-context/SkillsBuilderProvider.jsx deleted file mode 100644 index f5984c4..0000000 --- a/src/skills-builder/skills-builder-context/SkillsBuilderProvider.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { createContext, useReducer, useMemo } from 'react'; -import PropTypes from 'prop-types'; -import reducer, { skillsInitialState } from '../data/reducer'; -import { useAlgoliaSearch } from '../utils/search'; - -export const SkillsBuilderContext = createContext(); - -export const SkillsBuilderProvider = ({ children }) => { - const [state, dispatch] = useReducer(reducer, skillsInitialState); - - const [searchClient, productSearchIndex, jobSearchIndex] = useAlgoliaSearch(); - - const value = useMemo(() => ({ - state, - dispatch, - algolia: { - searchClient, - productSearchIndex, - jobSearchIndex, - }, - }), [state, searchClient, productSearchIndex, jobSearchIndex]); - - return ( - - {children} - - ); -}; - -SkillsBuilderProvider.propTypes = { - children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired, -}; diff --git a/src/skills-builder/skills-builder-context/index.js b/src/skills-builder/skills-builder-context/index.js deleted file mode 100644 index 5ff6eb3..0000000 --- a/src/skills-builder/skills-builder-context/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/prefer-default-export -export { SkillsBuilderProvider, SkillsBuilderContext } from './SkillsBuilderProvider'; diff --git a/src/skills-builder/skills-builder-header/SkillsBuilderHeader.jsx b/src/skills-builder/skills-builder-header/SkillsBuilderHeader.jsx deleted file mode 100644 index 17544c0..0000000 --- a/src/skills-builder/skills-builder-header/SkillsBuilderHeader.jsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import edXLogo from '../images/edX-logo.svg'; -import messages from './messages'; - -const SkillsBuilderHeader = ({ isMedium }) => { - const { formatMessage } = useIntl(); - - if (isMedium) { - return ( -
-

- {formatMessage(messages.skillsBuilderHeaderTitleIsMedium)} -

-
- ); - } - return ( -
- edx-logo -
-
-

- {formatMessage(messages.skillsBuilderHeaderTitle)} -

-

- {formatMessage(messages.skillsBuilderHeaderSubheading)} -

-
-
- ); -}; - -SkillsBuilderHeader.propTypes = { - isMedium: PropTypes.bool.isRequired, -}; - -export default SkillsBuilderHeader; diff --git a/src/skills-builder/skills-builder-header/index.js b/src/skills-builder/skills-builder-header/index.js deleted file mode 100644 index 00e6b02..0000000 --- a/src/skills-builder/skills-builder-header/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/prefer-default-export -export { default as SkillsBuilderHeader } from './SkillsBuilderHeader'; diff --git a/src/skills-builder/skills-builder-header/messages.js b/src/skills-builder/skills-builder-header/messages.js deleted file mode 100644 index a39bcb2..0000000 --- a/src/skills-builder/skills-builder-header/messages.js +++ /dev/null @@ -1,21 +0,0 @@ -import { defineMessages } from '@edx/frontend-platform/i18n'; - -const messages = defineMessages({ - skillsBuilderHeaderTitle: { - id: 'skills.builder.header.title', - defaultMessage: 'Skills Builder', - description: 'Title for the Skills Builder feature', - }, - skillsBuilderHeaderSubheading: { - id: 'skills.builder.header.subheading', - defaultMessage: 'Let edX be your guide', - description: 'Subheading to the Skills Builder title in the header component', - }, - skillsBuilderHeaderTitleIsMedium: { - id: 'skills.builder.header.title.is.medium', - defaultMessage: 'edX Skills builder', - description: 'Title for the Skills Builder feature when screen size is medium or less', - }, -}); - -export default messages; diff --git a/src/skills-builder/skills-builder-header/skillsBuilderHeader.scss b/src/skills-builder/skills-builder-header/skillsBuilderHeader.scss deleted file mode 100644 index ca4be48..0000000 --- a/src/skills-builder/skills-builder-header/skillsBuilderHeader.scss +++ /dev/null @@ -1,4 +0,0 @@ -.vertical-line { - border-left: 7px solid #D23228; - transform: rotate(13deg); -} diff --git a/src/skills-builder/skills-builder-modal/SkillsBuilderModal.jsx b/src/skills-builder/skills-builder-modal/SkillsBuilderModal.jsx deleted file mode 100644 index deab56c..0000000 --- a/src/skills-builder/skills-builder-modal/SkillsBuilderModal.jsx +++ /dev/null @@ -1,114 +0,0 @@ -import React, { useState, useContext } from 'react'; -import { - Button, Container, Stepper, ModalDialog, Form, Hyperlink, useMediaQuery, breakpoints, -} from '@edx/paragon'; -import { getConfig } from '@edx/frontend-platform'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { - STEP1, STEP2, -} from '../data/constants'; -import messages from './messages'; - -import { SkillsBuilderContext } from '../skills-builder-context'; -import { SkillsBuilderHeader } from '../skills-builder-header'; -import { SelectPreferences } from './select-preferences'; -import ViewResults from './view-results/ViewResults'; - -import headerImage from '../images/headerImage.png'; - -const SkillsBuilderModal = () => { - const { formatMessage } = useIntl(); - const isMedium = useMediaQuery({ maxWidth: breakpoints.medium.maxWidth }); - const { state } = useContext(SkillsBuilderContext); - const { currentGoal, currentJobTitle, careerInterests } = state; - const [currentStep, setCurrentStep] = useState(STEP1); - - const sendActionButtonEvent = (eventSuffix) => { - sendTrackEvent( - `edx.skills_builder.${eventSuffix}`, - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - current_goal: currentGoal, - current_job_title: currentJobTitle, - career_interests: careerInterests, - }, - }, - ); - }; - - const nextStepHandle = () => { - setCurrentStep(STEP2); - sendActionButtonEvent('next_step'); - }; - const exitButtonHandle = () => { - sendActionButtonEvent('exit'); - }; - const closeButtonHandle = () => { - sendActionButtonEvent('close'); - window.location.href = getConfig().MARKETING_SITE_SEARCH_URL; - }; - - return ( - - - - - { !isMedium && } - - - - - - - - - - -
- - - - - - - -
-
-
- - - - - - - - - - - - - -
-
- ); -}; - -export default SkillsBuilderModal; diff --git a/src/skills-builder/skills-builder-modal/index.js b/src/skills-builder/skills-builder-modal/index.js deleted file mode 100644 index 9bd5b7b..0000000 --- a/src/skills-builder/skills-builder-modal/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/prefer-default-export -export { default as SkillsBuilderModal } from './SkillsBuilderModal'; diff --git a/src/skills-builder/skills-builder-modal/messages.js b/src/skills-builder/skills-builder-modal/messages.js deleted file mode 100644 index 66f207f..0000000 --- a/src/skills-builder/skills-builder-modal/messages.js +++ /dev/null @@ -1,32 +0,0 @@ -import { defineMessages } from '@edx/frontend-platform/i18n'; - -const messages = defineMessages({ - /* Modal Action Row Buttons */ - goBackButton: { - id: 'go.back.button', - defaultMessage: 'Go Back', - description: 'Button that sends the user to the previous step in the skills builder.', - }, - nextStepButton: { - id: 'next.step.button', - defaultMessage: 'Next Step', - description: 'Button that sends the user to the next step in the skills builder.', - }, - exitButton: { - id: 'exit.button', - defaultMessage: 'Exit', - description: 'Button that exits the Skills Builder.', - }, - selectPreferences: { - id: 'select.preferences', - defaultMessage: 'Select preferences', - description: 'The first step of the Skills Builder for selecting a goal, a current job/occupation, and career interests', - }, - reviewResults: { - id: 'review.results', - defaultMessage: 'Review results', - description: 'The second step of the Skills Builder for rendering results from learner input', - }, -}); - -export default messages; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/CareerInterestCard.jsx b/src/skills-builder/skills-builder-modal/select-preferences/CareerInterestCard.jsx deleted file mode 100644 index 1b6c33a..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/CareerInterestCard.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useContext } from 'react'; -import PropTypes from 'prop-types'; -import { - IconButton, Icon, -} from '@edx/paragon'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { Close } from '@edx/paragon/icons'; -import { SkillsBuilderContext } from '../../skills-builder-context'; -import { removeCareerInterest } from '../../data/actions'; -import messages from './messages'; - -const CareerInterestCard = ({ interest }) => { - const { formatMessage } = useIntl(); - const { dispatch } = useContext(SkillsBuilderContext); - - const handleRemoveCareerInterest = () => { - dispatch(removeCareerInterest(interest)); - - sendTrackEvent( - 'edx.skills_builder.career_interest.removed', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - career_interest: interest, - }, - }, - ); - }; - - return ( -
-

- {interest} -

- -
- ); -}; - -CareerInterestCard.propTypes = { - interest: PropTypes.string.isRequired, -}; - -export default CareerInterestCard; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/CareerInterestSelect.jsx b/src/skills-builder/skills-builder-modal/select-preferences/CareerInterestSelect.jsx deleted file mode 100644 index 1fc38e7..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/CareerInterestSelect.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import React, { useContext } from 'react'; -import { getConfig } from '@edx/frontend-platform'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { - Stack, Row, Col, Form, -} from '@edx/paragon'; -import { Configure, InstantSearch } from 'react-instantsearch-hooks-web'; -import JobTitleInstantSearch from './JobTitleInstantSearch'; -import CareerInterestCard from './CareerInterestCard'; -import { addCareerInterest } from '../../data/actions'; -import { SkillsBuilderContext } from '../../skills-builder-context'; -import messages from './messages'; - -const CareerInterestSelect = () => { - const { formatMessage } = useIntl(); - const { state, dispatch, algolia } = useContext(SkillsBuilderContext); - const { careerInterests } = state; - const { searchClient } = algolia; - - const handleCareerInterestSelect = (value) => { - if (!careerInterests.includes(value) && careerInterests.length < 3) { - dispatch(addCareerInterest(value)); - - sendTrackEvent( - 'edx.skills_builder.career_interest.added', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - career_interest: value, - }, - }, - ); - } - }; - - return ( - - -

- {formatMessage(messages.careerInterestPrompt)} -

- - - - -
- - {careerInterests.map((interest, index) => ( - // eslint-disable-next-line react/no-array-index-key - - - - ))} - -
- ); -}; - -export default CareerInterestSelect; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/GoalSelect.jsx b/src/skills-builder/skills-builder-modal/select-preferences/GoalSelect.jsx deleted file mode 100644 index 1eccfd1..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/GoalSelect.jsx +++ /dev/null @@ -1,56 +0,0 @@ -import React, { useContext } from 'react'; -import { - Form, -} from '@edx/paragon'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { setGoal } from '../../data/actions'; -import { SkillsBuilderContext } from '../../skills-builder-context'; -import messages from './messages'; - -const GoalDropdown = () => { - const { formatMessage } = useIntl(); - const { state, dispatch } = useContext(SkillsBuilderContext); - const { currentGoal } = state; - - const handleGoalSelect = (e) => { - const { value } = e.target; - dispatch(setGoal(value)); - - sendTrackEvent( - 'edx.skills_builder.goal.select', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - current_goal: value, - }, - }, - ); - }; - - return ( - - -

- {formatMessage(messages.learningGoalPrompt)} -

-
- - - - - - - - -
- ); -}; - -export default GoalDropdown; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/JobTitleInstantSearch.jsx b/src/skills-builder/skills-builder-modal/select-preferences/JobTitleInstantSearch.jsx deleted file mode 100644 index 138c61e..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/JobTitleInstantSearch.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { - Form, -} from '@edx/paragon'; -import { useHits, useSearchBox } from 'react-instantsearch-hooks-web'; - -const JobTitleInstantSearch = (props) => { - const { refine } = useSearchBox(props); - const { hits } = useHits(props); - - const [jobInput, setJobInput] = useState(''); - - const handleAutosuggestChange = (value) => { - setJobInput(value); - }; - - useEffect(() => { - refine(jobInput); - }, [jobInput, refine]); - - return ( - - {hits.map(job => ( - - {job.name} - - ))} - - ); -}; - -JobTitleInstantSearch.propTypes = { - onSelected: PropTypes.func.isRequired, -}; - -export default JobTitleInstantSearch; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/JobTitleSelect.jsx b/src/skills-builder/skills-builder-modal/select-preferences/JobTitleSelect.jsx deleted file mode 100644 index db86453..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/JobTitleSelect.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import React, { useContext } from 'react'; -import { getConfig } from '@edx/frontend-platform'; -import { - Form, Stack, -} from '@edx/paragon'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { InstantSearch } from 'react-instantsearch-hooks-web'; -import { setCurrentJobTitle } from '../../data/actions'; -import { SkillsBuilderContext } from '../../skills-builder-context'; -import JobTitleInstantSearch from './JobTitleInstantSearch'; -import messages from './messages'; - -const JobTitleSelect = () => { - const { formatMessage } = useIntl(); - const { state, dispatch, algolia } = useContext(SkillsBuilderContext); - const { searchClient } = algolia; - const { currentJobTitle } = state; - - const handleCurrentJobTitleSelect = (value) => { - dispatch(setCurrentJobTitle(value)); - sendTrackEvent( - 'edx.skills_builder.current_job.select', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - current_job_title: value, - }, - }, - ); - }; - - const handleCheckboxChange = (e) => { - const { value } = e.target; - // only setCurrentJobTitle if the user hasn't selected a current job as we don't want to override their selection - if (!currentJobTitle) { dispatch(setCurrentJobTitle(value)); } - - sendTrackEvent( - `edx.skills_builder.current_job.${value}`, - { - app_name: 'skills_builder', - category: 'skills_builder', - }, - ); - }; - - return ( - - -

- {formatMessage(messages.jobTitlePrompt)} -

- - - -
- - - - {formatMessage(messages.studentCheckboxPrompt)} - - - {formatMessage(messages.currentlyLookingCheckboxPrompt)} - - - -
- ); -}; - -export default JobTitleSelect; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/SelectPreferences.jsx b/src/skills-builder/skills-builder-modal/select-preferences/SelectPreferences.jsx deleted file mode 100644 index bf8c02c..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/SelectPreferences.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { useContext } from 'react'; -import { - Stack, -} from '@edx/paragon'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { SkillsBuilderContext } from '../../skills-builder-context'; -import GoalSelect from './GoalSelect'; -import JobTitleSelect from './JobTitleSelect'; -import CareerInterestSelect from './CareerInterestSelect'; -import messages from './messages'; - -const SelectPreferences = () => { - const { formatMessage } = useIntl(); - const { state } = useContext(SkillsBuilderContext); - const { currentGoal, currentJobTitle } = state; - - return ( - -

- {formatMessage(messages.skillsBuilderDescription)} -

- - - - - {currentGoal && ( - - )} - - {currentGoal && currentJobTitle && ( - - )} - -
- ); -}; - -export default SelectPreferences; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/index.js b/src/skills-builder/skills-builder-modal/select-preferences/index.js deleted file mode 100644 index f8d553d..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/prefer-default-export -export { default as SelectPreferences } from './SelectPreferences'; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/messages.js b/src/skills-builder/skills-builder-modal/select-preferences/messages.js deleted file mode 100644 index 8693ef0..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/messages.js +++ /dev/null @@ -1,80 +0,0 @@ -import { defineMessages } from '@edx/frontend-platform/i18n'; - -const messages = defineMessages({ - skillsBuilderDescription: { - id: 'skills.builder.description', - defaultMessage: 'Find the right courses and programs that help you reach your goals.', - description: 'Description of what the Skills Builder seeks to accomplish', - }, - learningGoalPrompt: { - id: 'learning.goal.prompt', - defaultMessage: 'First, tell us what you want to achieve', - description: 'Prompts the user to select their current goal.', - }, - selectLearningGoal: { - id: 'select.learning.goal', - defaultMessage: 'Select a goal', - description: 'Placeholder text for the goal selection component.', - }, - learningGoalStartCareer: { - id: 'learning.goal.start_career', - defaultMessage: 'I want to start my career', - description: 'Selected by user if their goal is to start their career.', - }, - learningGoalAdvanceCareer: { - id: 'learning.goal.advance_career', - defaultMessage: 'I want to advance my career', - description: 'Selected by user if their goal is to advance their career.', - }, - learningGoalChangeCareer: { - id: 'learning.goal.change_career', - defaultMessage: 'I want to change careers', - description: 'Selected by user if their goal is to change careers.', - }, - learningGoalSomethingNew: { - id: 'learning.goal.something.new', - defaultMessage: 'I want to learn something new', - description: 'Selected by user if their goal is to learn something new.', - }, - learningGoalSomethingElse: { - id: 'learning.goal.something.else', - defaultMessage: 'Something else', - description: 'Selected by user if their goal is not described by the other choices.', - }, - jobTitlePrompt: { - id: 'job.title.prompt', - defaultMessage: 'Next, search and select your current job title', - description: 'Prompts the user to select their current job title or occupation.', - }, - jobTitleInputPlaceholderText: { - id: 'job.title.input.placeholder.text', - defaultMessage: 'Search and select a job title', - description: 'Placeholder text for the job title input control.', - }, - studentCheckboxPrompt: { - id: 'student.checkbox.prompt', - defaultMessage: 'I\'m a student', - description: 'Label text for the corresponding checkbox', - }, - currentlyLookingCheckboxPrompt: { - id: 'currently.looking.checkbox.prompt', - defaultMessage: 'I\'m currently looking for work', - description: 'Label text for the corresponding checkbox', - }, - careerInterestPrompt: { - id: 'career.interest.prompt', - defaultMessage: 'What careers are you interested in?', - description: 'Prompts the user to select careers they are interested in pursuing.', - }, - careerInterestInputPlaceholderText: { - id: 'career.interest.input.placeholder.text', - defaultMessage: 'Select up to 3 new job titles', - description: 'Placeholder text for the career interest input control.', - }, - removeCareerInterestButtonAltText: { - id: 'career.interest.remove.button.alt.text', - defaultMessage: 'Remove career interest: ', - }, -}); - -export default messages; diff --git a/src/skills-builder/skills-builder-modal/select-preferences/test/SelectPreferences.test.jsx b/src/skills-builder/skills-builder-modal/select-preferences/test/SelectPreferences.test.jsx deleted file mode 100644 index 7f20a07..0000000 --- a/src/skills-builder/skills-builder-modal/select-preferences/test/SelectPreferences.test.jsx +++ /dev/null @@ -1,180 +0,0 @@ -import { - screen, render, cleanup, fireEvent, -} from '@testing-library/react'; -import { mergeConfig } from '@edx/frontend-platform'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { SkillsBuilderWrapperWithContext, dispatchMock, contextValue } from '../../../test/setupSkillsBuilder'; - -jest.mock('@edx/frontend-platform/analytics', () => ({ - sendTrackEvent: jest.fn(), -})); - -describe('select-preferences', () => { - beforeAll(() => { - mergeConfig({ - ALGOLIA_JOBS_INDEX_NAME: 'test-job-index-name', - }); - }); - beforeEach(() => cleanup()); - - describe('render behavior', () => { - it('should render the second prompt if a goal is selected', () => { - render( - SkillsBuilderWrapperWithContext( - { - ...contextValue, - state: { - ...contextValue.state, - currentGoal: 'I want to start my career', - }, - }, - ), - ); - const expectedGoal = { - payload: 'I want to advance my career', - type: 'SET_GOAL', - }; - const expectedStudent = { - payload: 'student', - type: 'SET_CURRENT_JOB_TITLE', - }; - - const expectedJobTitle = { - payload: 'Prospector', - type: 'SET_CURRENT_JOB_TITLE', - }; - - const goalSelect = screen.getByTestId('goal-select-dropdown'); - fireEvent.change(goalSelect, { target: { value: 'I want to advance my career' } }); - - const checkbox = screen.getByRole('checkbox', { name: 'I\'m a student' }); - fireEvent.click(checkbox); - - const jobTitleInput = screen.getByTestId('job-title-select'); - fireEvent.change(jobTitleInput, { target: { value: 'Prospector' } }); - fireEvent.click(screen.getByRole('button', { name: 'Prospector' })); - - expect(screen.getByText('Next, search and select your current job title')).toBeTruthy(); - expect(dispatchMock).toHaveBeenCalledWith(expectedGoal); - expect(dispatchMock).toHaveBeenCalledWith(expectedStudent); - expect(dispatchMock).toHaveBeenCalledWith(expectedJobTitle); - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.goal.select', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - current_goal: 'I want to advance my career', - }, - }, - ); - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.current_job.student', - { - app_name: 'skills_builder', - category: 'skills_builder', - }, - ); - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.current_job.select', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - current_job_title: 'Prospector', - }, - }, - ); - }); - - it('should render the third prompt if a current job title is selected', () => { - render( - SkillsBuilderWrapperWithContext( - { - ...contextValue, - state: { - ...contextValue.state, - currentGoal: 'I want to start my career', - currentJobTitle: 'Goblin Guide', - }, - }, - ), - ); - expect(screen.getByText('What careers are you interested in?')).toBeTruthy(); - }); - - it('should render a for each career interest', () => { - render( - SkillsBuilderWrapperWithContext( - { - ...contextValue, - state: { - ...contextValue.state, - currentGoal: 'I want to start my career', - currentJobTitle: 'Goblin Lackey', - careerInterests: ['Prospector'], - }, - }, - ), - ); - expect(screen.getByText('Prospector')).toBeTruthy(); - - const careerInterestInput = screen.getByTestId('career-interest-select'); - fireEvent.change(careerInterestInput, { target: { value: 'Mirror Breaker' } }); - fireEvent.click(screen.getByRole('button', { name: 'Mirror Breaker' })); - - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.career_interest.added', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - career_interest: 'Mirror Breaker', - }, - }, - ); - expect(dispatchMock).toHaveBeenCalledWith( - { - payload: 'Mirror Breaker', - type: 'ADD_CAREER_INTEREST', - }, - ); - }); - }); - - describe('controlled behavior', () => { - it('should remove a when the corresponding close button is selected', () => { - render( - SkillsBuilderWrapperWithContext( - { - ...contextValue, - state: { - ...contextValue.state, - currentGoal: 'I want to start my career', - currentJobTitle: 'Goblin Lackey', - careerInterests: ['Prospector', 'Mirror Breaker', 'Bombardment'], - }, - }, - ), - ); - - const expected = { - payload: 'Prospector', - type: 'REMOVE_CAREER_INTEREST', - }; - - fireEvent.click(screen.getByLabelText('Remove career interest: Prospector')); - expect(dispatchMock).toHaveBeenCalledWith(expected); - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.career_interest.removed', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - career_interest: 'Prospector', - }, - }, - ); - }); - }); -}); diff --git a/src/skills-builder/skills-builder-modal/skillsBuilderModal.scss b/src/skills-builder/skills-builder-modal/skillsBuilderModal.scss deleted file mode 100644 index 10ea166..0000000 --- a/src/skills-builder/skills-builder-modal/skillsBuilderModal.scss +++ /dev/null @@ -1,22 +0,0 @@ -.skills-builder-modal { - button[aria-label="Close"][type="button"]{ - color: $white; - } -} - -$breakpoint-medium: 992px; -@media (max-width: $breakpoint-medium) { - .med-min-height { - min-height: map-get($spacers, 6); - } - .skills-builder-modal { - button[aria-label="Close"][type="button"]{ - position: relative; - top: 0.5rem; - } - } -} - -.chip-max-width { - max-width: 16rem; -} diff --git a/src/skills-builder/skills-builder-modal/view-results/CarouselStack.jsx b/src/skills-builder/skills-builder-modal/view-results/CarouselStack.jsx deleted file mode 100644 index efa8b26..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/CarouselStack.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import { CardCarousel } from '@edx/paragon'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import RecommendationCard from './RecommendationCard'; -import messages from './messages'; - -const CarouselStack = ({ selectedRecommendations, productTypeNames }) => { - const { formatMessage } = useIntl(); - const { id: jobId, name: jobName, recommendations } = selectedRecommendations; - const courseKeys = recommendations.course?.map(rec => ({ - title: rec.title, - courserun_key: rec.active_run_key, - })); - - const normalizeProductTypeName = (productType) => { - // If the productType is more than one word (i.e. boot_camp) - if (productType.includes('_')) { - // split to remove underscore and return an array of strings (i.e. ['boot', 'camp']) - const splitStrings = productType.split('_'); - - // map through the array and normalize each string (i.e. ['Boot', 'Camp']) - const normalizeStrings = splitStrings.map(word => word[0].toUpperCase() + word.slice(1)); - - // return the array as a string joined by white spaces (i.e. Boot Camp) - return normalizeStrings.join(' '); - } - // Otherwise, return a normalized string - const normalizeString = productType[0].toUpperCase() + productType.slice(1).toLowerCase(); - return normalizeString; - }; - - const renderCarouselTitle = (productType) => ( -

- {formatMessage(messages.productRecommendationsHeaderText, { - productType: normalizeProductTypeName(productType), - jobName, - })} -

- ); - - const handleCourseCardClick = (courseKey, productType) => { - sendTrackEvent( - 'edx.skills_builder.recommendation.click', - { - app_name: 'skills_builder', - category: 'skills_builder', - page: 'skills_builder', - courserun_key: courseKey, - product_type: productType, - selected_recommendations: { - job_id: jobId, - job_name: jobName, - courserun_keys: courseKeys, - }, - }, - ); - }; - - return ( - productTypeNames.map(productType => ( - - {recommendations[productType].map(rec => ( - - ))} - - ))); -}; - -export default CarouselStack; diff --git a/src/skills-builder/skills-builder-modal/view-results/RecommendationCard.jsx b/src/skills-builder/skills-builder-modal/view-results/RecommendationCard.jsx deleted file mode 100644 index fbd170f..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/RecommendationCard.jsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import { - Card, Chip, Hyperlink, -} from '@edx/paragon'; -import PropTypes from 'prop-types'; -import cardImageCapFallbackSrc from '../../images/card-imagecap-fallback.png'; - -const RecommendationCard = ({ rec, productType, handleCourseCardClick }) => { - const { - card_image_url: cardImageUrl, - marketing_url: marketingUrl, - active_run_key: courseKey, - owners, - partner, - title, - } = rec; - - const { logoImageUrl } = owners[0]; - - return ( - - handleCourseCardClick(courseKey, productType)} - > - - - - {partner.map((orgName, index) => ( - // eslint-disable-next-line react/no-array-index-key - - {orgName} - - ))} - - - - ); -}; - -RecommendationCard.propTypes = { - rec: PropTypes.shape({ - title: PropTypes.string, - card_image_url: PropTypes.string, - marketing_url: PropTypes.string, - partner: PropTypes.arrayOf(PropTypes.string), - owners: PropTypes.arrayOf(PropTypes.shape({ - key: PropTypes.string, - logoImageUrl: PropTypes.string, - })), - active_run_key: PropTypes.string.isRequired, - }).isRequired, - productType: PropTypes.string.isRequired, - handleCourseCardClick: PropTypes.func.isRequired, -}; - -export default RecommendationCard; diff --git a/src/skills-builder/skills-builder-modal/view-results/RelatedSkillsSelectableBoxSet.jsx b/src/skills-builder/skills-builder-modal/view-results/RelatedSkillsSelectableBoxSet.jsx deleted file mode 100644 index 255a168..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/RelatedSkillsSelectableBoxSet.jsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { - SelectableBox, Chip, Stack, useMediaQuery, breakpoints, -} from '@edx/paragon'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import messages from './messages'; - -const RelatedSkillsSelectableBoxSet = ({ jobSkillsList, selectedJobTitle, onChange }) => { - const { formatMessage } = useIntl(); - const isExtraSmall = useMediaQuery({ maxWidth: breakpoints.extraSmall.maxWidth }); - - const renderTopFiveSkills = (skills) => { - const topFiveSkills = skills.sort((a, b) => b.significance - a.significance).slice(0, 5); - return ( - topFiveSkills.map(skill => ( - - {skill.name} - - )) - ); - }; - - return ( - - {jobSkillsList.map(job => ( - -

{job.name}

- -

{formatMessage(messages.relatedSkillsHeading)}

- {renderTopFiveSkills(job.skills)} -
-
- ))} -
- ); -}; - -RelatedSkillsSelectableBoxSet.propTypes = { - jobSkillsList: PropTypes.arrayOf(PropTypes.shape({})).isRequired, - selectedJobTitle: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired, -}; - -export default RelatedSkillsSelectableBoxSet; diff --git a/src/skills-builder/skills-builder-modal/view-results/ViewResults.jsx b/src/skills-builder/skills-builder-modal/view-results/ViewResults.jsx deleted file mode 100644 index a0e4186..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/ViewResults.jsx +++ /dev/null @@ -1,145 +0,0 @@ -import React, { - useContext, useEffect, useState, -} from 'react'; -import { - Stack, Row, Alert, Spinner, -} from '@edx/paragon'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { CheckCircle, ErrorOutline } from '@edx/paragon/icons'; -import { SkillsBuilderContext } from '../../skills-builder-context'; -import RelatedSkillsSelectableBoxSet from './RelatedSkillsSelectableBoxSet'; -import messages from './messages'; -import CarouselStack from './CarouselStack'; - -import { getRecommendations } from './data/service'; -import { useProductTypes } from './data/hooks'; - -const ViewResults = () => { - const { formatMessage } = useIntl(); - const { algolia, state } = useContext(SkillsBuilderContext); - const { jobSearchIndex, productSearchIndex } = algolia; - const { careerInterests } = state; - - const [selectedJobTitle, setSelectedJobTitle] = useState(''); - const [jobSkillsList, setJobSkillsList] = useState([]); - const [productRecommendations, setProductRecommendations] = useState([]); - const [selectedRecommendations, setSelectedRecommendations] = useState({}); - const [isLoading, setIsLoading] = useState(true); - const [fetchError, setFetchError] = useState(false); - - const productTypes = useProductTypes(); - - useEffect(() => { - const getAllRecommendations = async () => { - // eslint-disable-next-line max-len - const { jobInfo, results } = await getRecommendations(jobSearchIndex, productSearchIndex, careerInterests, productTypes); - - setJobSkillsList(jobInfo); - setSelectedJobTitle(results[0].name); - setProductRecommendations(results); - setIsLoading(false); - sendTrackEvent('edx.skills_builder.recommendation.shown', { - app_name: 'skills_builder', - category: 'skills_builder', - page: 'skills_builder', - selected_recommendations: { - job_id: results[0].id, - job_name: results[0].name, - /* We extract the title and course key into an array of objects */ - courserun_keys: results[0].recommendations.course?.map(rec => ({ - title: rec.title, - courserun_key: rec.active_run_key, - })), - }, - is_default: true, - }); - }; - - getAllRecommendations() - .catch(() => { - setFetchError(true); - setIsLoading(false); - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [careerInterests, jobSearchIndex, productSearchIndex]); - - useEffect(() => { - setSelectedRecommendations(productRecommendations.find(rec => rec.name === selectedJobTitle)); - }, [productRecommendations, selectedJobTitle]); - - const handleJobTitleChange = (e) => { - const { value } = e.target; - setSelectedJobTitle(value); - const currentSelection = productRecommendations.find(rec => rec.name === value); - const { id: jobId, name: jobName, recommendations } = currentSelection; - const courseKeys = recommendations.course?.map(rec => ({ - title: rec.title, - courserun_key: rec.active_run_key, - })); - /* - The is_default value will be set to false for any selections made by the user. - This code is intentionally duplicated from the event that fires in the useEffect for fetching recommendations. - This proved less clunky than refactoring to make things DRY as we have to ensure the first call fires only once. - The previous implementation wrapped the event in an additional useEffect that was looping unnecessarily. - We have plans to refactor all of the event code as part of APER-2392, where we will revisit this approach. - */ - sendTrackEvent('edx.skills_builder.recommendation.shown', { - app_name: 'skills_builder', - category: 'skills_builder', - page: 'skills_builder', - selected_recommendations: { - job_id: jobId, - job_name: jobName, - courserun_keys: courseKeys, - }, - is_default: false, - }); - }; - - if (fetchError) { - return ( - - - {formatMessage(messages.matchesNotFoundDangerAlert)} - - - ); - } - - return ( - isLoading ? ( - - - - ) : ( - - - - {formatMessage(messages.matchesFoundSuccessAlert)} - - - - - - - - ) - ); -}; - -export default ViewResults; diff --git a/src/skills-builder/skills-builder-modal/view-results/data/constants.js b/src/skills-builder/skills-builder-modal/view-results/data/constants.js deleted file mode 100644 index 182f783..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/data/constants.js +++ /dev/null @@ -1,14 +0,0 @@ -export const COURSE = 'course'; -const BOOT_CAMP = 'boot_camp'; -const EXECUTIVE_EDUCATION = 'executive_education'; -const DEGREE = '2U_degree'; -const PROGRAM = 'program'; - -// This array is used to determine the validity of product types as they are passed through the query string -export const productTypes = [ - DEGREE, - BOOT_CAMP, - EXECUTIVE_EDUCATION, - PROGRAM, - COURSE, -]; diff --git a/src/skills-builder/skills-builder-modal/view-results/data/hooks.js b/src/skills-builder/skills-builder-modal/view-results/data/hooks.js deleted file mode 100644 index adba093..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/data/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -import { useLocation } from 'react-router-dom'; -import { productTypes as acceptedProductTypes, COURSE } from './constants'; - -const defaultSetting = [COURSE]; - -/* - * Hook that calls the useLocation() hook from react-router-dom to have a reference to the query string in the URL. - * The returned array determines the order in which the recommendations will appear to the user. - * - * @return {Array[String]} productTypes - An array of strings that represent each line of business - */ -// eslint-disable-next-line import/prefer-default-export -export const useProductTypes = () => { - const { search } = useLocation(); - const checkedTypes = []; - - if (search) { - // remove the "?" and split the query string at "=" - const splitString = search.slice(1).split('='); - - // if the key is not "product_types", use a default setting - if (splitString[0] !== 'product_types') { - return defaultSetting; - } - - // split productTypes string into an array at "," - const queryProductTypes = splitString[1]?.split(','); - - // compare each product type from the query string with a list of accepted product types - queryProductTypes.forEach(productType => { - if (acceptedProductTypes.includes(productType)) { - checkedTypes.push(productType); - } - }); - } - - // if no types were set, use default setting - return checkedTypes.length > 0 ? checkedTypes : defaultSetting; -}; diff --git a/src/skills-builder/skills-builder-modal/view-results/data/service.js b/src/skills-builder/skills-builder-modal/view-results/data/service.js deleted file mode 100644 index 369edbb..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/data/service.js +++ /dev/null @@ -1,34 +0,0 @@ -/* eslint-disable import/prefer-default-export */ -import { searchJobs, getProductRecommendations } from '../../../utils/search'; - -export async function getRecommendations(jobSearchIndex, productSearchIndex, careerInterests, productTypes) { - const jobInfo = await searchJobs(jobSearchIndex, careerInterests); - - const results = await Promise.all(jobInfo.map(async (job) => { - const formattedSkills = job.skills.map(skill => skill.name); - - // create a data object for each job - const data = { - id: job.id, - name: job.name, - recommendations: {}, - }; - - // get recommendations for each product type based on the skills for the current job - - await Promise.all(productTypes.map(async (productType) => { - const formattedProductType = productType.replace('_', ' '); - const response = await getProductRecommendations(productSearchIndex, formattedProductType, formattedSkills); - - // add a new key to the recommendations object and set the value to the response - data.recommendations[productType] = response; - })); - - return data; - })); - - return { - jobInfo, - results, - }; -} diff --git a/src/skills-builder/skills-builder-modal/view-results/data/test/hooks.test.jsx b/src/skills-builder/skills-builder-modal/view-results/data/test/hooks.test.jsx deleted file mode 100644 index e9ee5b0..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/data/test/hooks.test.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import { renderHook } from '@testing-library/react-hooks'; -import { useProductTypes } from '../hooks'; - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: jest.fn(() => ({ search: global.query_string || '' })), -})); - -describe('useProductTypes', () => { - test('returns default setting if no query string is provided', () => { - const { result } = renderHook(() => useProductTypes()); - - const productTypes = result.current; - - expect(productTypes).toEqual(['course']); - }); - - test('returns a list of settings when serialized correctly', () => { - global.query_string = '?product_types=boot_camp,course'; - - const { result } = renderHook(() => useProductTypes()); - - const productTypes = result.current; - - expect(productTypes).toEqual(['boot_camp', 'course']); - }); - - test('returns the default setting if query string is not serialized correctly', () => { - global.query_string = '?legend_of_zelda=boot_camp,course'; - const { result } = renderHook(() => useProductTypes()); - - const productTypes = result.current; - - expect(productTypes).toEqual(['course']); - }); - - test('returns a filtered list if unrecognized values are provided', () => { - global.query_string = '?product_types=boot_camp,course,hack_the_mainframe'; - - const { result } = renderHook(() => useProductTypes()); - - const productTypes = result.current; - - expect(productTypes).toEqual(['boot_camp', 'course']); - }); -}); diff --git a/src/skills-builder/skills-builder-modal/view-results/index.js b/src/skills-builder/skills-builder-modal/view-results/index.js deleted file mode 100644 index b0af023..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/prefer-default-export -export { default as ViewResults } from './ViewResults'; diff --git a/src/skills-builder/skills-builder-modal/view-results/messages.js b/src/skills-builder/skills-builder-modal/view-results/messages.js deleted file mode 100644 index 91660d6..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/messages.js +++ /dev/null @@ -1,31 +0,0 @@ -import { defineMessages } from '@edx/frontend-platform/i18n'; - -const messages = defineMessages({ - matchesFoundSuccessAlert: { - id: 'matches.found.success.alert', - defaultMessage: 'We found skills and courses that match your preferences!', - description: 'Success alert message to display when recommendations are presented to the learner.', - }, - matchesNotFoundDangerAlert: { - id: 'matches.not.found.danger.alert', - defaultMessage: 'We were not able to retrieve recommendations at this time. Please try again later.', - description: 'Danger alert message to display when the component fails to get recommendations.', - }, - relatedSkillsHeading: { - id: 'related.skills.heading', - defaultMessage: 'Related Skills', - description: 'Heading text for a selectable box that displays related skills for a corresponding selected job title.', - }, - relatedSkillsSelectableBoxLabelText: { - id: 'related.skills.selectable.box.label.text', - defaultMessage: 'Related skills:', - description: 'Label text for a selectable box that displays related skills for a corresponding selected job title.', - }, - productRecommendationsHeaderText: { - id: 'product.recommendations.header.text', - defaultMessage: '{productType} recommendations for {jobName}', - description: 'Header text for a carousel of product recommendations.', - }, -}); - -export default messages; diff --git a/src/skills-builder/skills-builder-modal/view-results/test/ViewResults.test.jsx b/src/skills-builder/skills-builder-modal/view-results/test/ViewResults.test.jsx deleted file mode 100644 index d4df5fa..0000000 --- a/src/skills-builder/skills-builder-modal/view-results/test/ViewResults.test.jsx +++ /dev/null @@ -1,179 +0,0 @@ -import { - screen, render, cleanup, fireEvent, act, -} from '@testing-library/react'; -import { mergeConfig } from '@edx/frontend-platform'; -import { sendTrackEvent } from '@edx/frontend-platform/analytics'; -import { SkillsBuilderWrapperWithContext, contextValue } from '../../../test/setupSkillsBuilder'; -import { getProductRecommendations } from '../../../utils/search'; - -jest.mock('@edx/frontend-platform/analytics', () => ({ - sendTrackEvent: jest.fn(), -})); - -const renderSkillsBuilderWrapper = ( - value = { - ...contextValue, - state: { - ...contextValue.state, - currentGoal: 'I want to start my career', - currentJobTitle: 'Goblin Lackey', - careerInterests: ['Prospector', 'Mirror Breaker', 'Bombardment'], - }, - }, -) => { - render(SkillsBuilderWrapperWithContext(value)); -}; - -describe('view-results', () => { - beforeAll(() => { - mergeConfig({ - ALGOLIA_JOBS_INDEX_NAME: 'test-job-index-name', - }); - }); - - describe('user interface', () => { - beforeEach(async () => { - cleanup(); - // Render the form filled out - renderSkillsBuilderWrapper(); - // Click the next button to trigger "fetching" the data - await act(async () => { - fireEvent.click(screen.getByRole('button', { name: 'Next Step' })); - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should render a for each career interest the learner has submitted', () => { - expect(screen.getByText('Prospector')).toBeTruthy(); - expect(screen.getByText('Mirror Breaker')).toBeTruthy(); - - const chipComponents = document.querySelectorAll('.pgn__chip'); - expect(chipComponents[0].textContent).toEqual('finding shiny things'); - expect(chipComponents[1].textContent).toEqual('mining'); - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.recommendation.shown', - { - app_name: 'skills_builder', - category: 'skills_builder', - page: 'skills_builder', - selected_recommendations: { - job_id: 0, - job_name: 'Prospector', - courserun_keys: [ - { - title: 'Mining with the Mons', - courserun_key: 'MONS101', - }, - { - title: 'The Art of Warren Upkeep', - courserun_key: 'WAR101', - }, - ], - }, - is_default: true, - }, - ); - // called once when "Next Step" button is clicked and then again for above event - expect(sendTrackEvent).toHaveBeenCalledTimes(2); - }); - - it('renders a carousel of components', () => { - expect(screen.getByText('Course recommendations for Prospector')).toBeTruthy(); - }); - - it('changes the recommendations based on the selected job title', () => { - fireEvent.click(screen.getByRole('radio', { name: 'Mirror Breaker' })); - expect(screen.getByText('Course recommendations for Mirror Breaker')).toBeTruthy(); - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.recommendation.shown', - { - app_name: 'skills_builder', - category: 'skills_builder', - page: 'skills_builder', - selected_recommendations: { - job_id: 1, - job_name: 'Mirror Breaker', - courserun_keys: [ - { - title: 'Mining with the Mons', - courserun_key: 'MONS101', - }, - { - title: 'The Art of Warren Upkeep', - courserun_key: 'WAR101', - }, - ], - }, - is_default: false, - }, - ); - }); - - it('sends an event when the "Next Step" button is clicked', () => { - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.next_step', - { - app_name: 'skills_builder', - category: 'skills_builder', - learner_data: { - current_goal: 'I want to start my career', - current_job_title: 'Goblin Lackey', - career_interests: ['Prospector', 'Mirror Breaker', 'Bombardment'], - }, - }, - ); - }); - - it('fires an event when a product recommendation is clicked', () => { - fireEvent.click(screen.getByText('Mining with the Mons')); - expect(sendTrackEvent).toHaveBeenCalledWith( - 'edx.skills_builder.recommendation.click', - { - app_name: 'skills_builder', - category: 'skills_builder', - page: 'skills_builder', - courserun_key: 'MONS101', - product_type: 'course', - selected_recommendations: { - job_id: 0, - job_name: 'Prospector', - courserun_keys: [ - { - title: 'Mining with the Mons', - courserun_key: 'MONS101', - }, - { - title: 'The Art of Warren Upkeep', - courserun_key: 'WAR101', - }, - ], - }, - }, - ); - }); - }); - - describe('fetch recommendations', () => { - beforeEach(() => { - cleanup(); - // Render the form filled out - renderSkillsBuilderWrapper(); - }); - - it('renders an alert if an error is thrown while fetching', async () => { - getProductRecommendations.mockImplementationOnce(() => { - throw new Error(); - }); - - // Click the next button to trigger "fetching" the data - await act(async () => { - fireEvent.click(screen.getByRole('button', { name: 'Next Step' })); - }); - - expect(screen.getByText('We were not able to retrieve recommendations at this time. Please try again later.')).toBeTruthy(); - }); - }); -}); diff --git a/src/skills-builder/test/SkillsBuilder.test.jsx b/src/skills-builder/test/SkillsBuilder.test.jsx deleted file mode 100644 index 6803376..0000000 --- a/src/skills-builder/test/SkillsBuilder.test.jsx +++ /dev/null @@ -1,23 +0,0 @@ -import { IntlProvider } from '@edx/frontend-platform/i18n'; -import React from 'react'; -import { - screen, render, act, -} from '@testing-library/react'; -import { SkillsBuilder } from '..'; -import { SkillsBuilderProvider } from '../skills-builder-context'; - -describe('skills-builder', () => { - it('should render a Skills Builder modal with a prompt for the user', () => { - act(() => { - render( - - - - - , - ); - }); - expect(screen.getByText('Skills Builder')).toBeTruthy(); - expect(screen.getByText('First, tell us what you want to achieve')).toBeTruthy(); - }); -}); diff --git a/src/skills-builder/test/__mocks__/jobSkills.mockData.js b/src/skills-builder/test/__mocks__/jobSkills.mockData.js deleted file mode 100644 index 6d43f31..0000000 --- a/src/skills-builder/test/__mocks__/jobSkills.mockData.js +++ /dev/null @@ -1,69 +0,0 @@ -export const mockData = { - hits: [ - { - id: 0, - name: 'Prospector' - }, - { - id: 1, - name: 'Mirror Breaker' - }, - ], - searchJobs: [ - { - id: 0, - name: 'Prospector', - skills: [ - { external_id: 0, - name: 'mining', - significance: 50, - }, - { external_id: 1, - name: 'finding shiny things', - significance: 100, - }], - }, - { - id: 1, - name: 'Mirror Breaker', - skills: [ - { external_id: 0, - name: 'mining', - significance: 50, - }, - { external_id: 1, - name: 'finding shiny things', - significance: 100, - }], - }, - ], - productRecommendations: [ - { - title: 'Mining with the Mons', - uuid: 'thisIsARandomString01', - partner: ['edx'], - card_image_url: 'https://thisIsAUrl.ForAnImage.01.jpeg', - marketing_url: 'https://thisIsAUrl.ForTheRecommendedContent.01.com', - active_run_key: 'MONS101', - owners: [ - { - logoImageUrl: 'https://thisIsAUrl.ForALogoImage.01.jpeg', - } - ] - }, - { - title: 'The Art of Warren Upkeep', - uuid: 'thisIsARandomString02', - partner: ['edx'], - card_image_url: 'https://thisIsAUrl.ForAnImage.02.jpeg', - marketing_url: 'https://thisIsAUrl.ForTheRecommendedContent.02.com', - active_run_key: 'WAR101', - owners: [ - { - logoImageUrl: 'https://thisIsAUrl.ForALogoImage.02.jpeg', - } - ] - }, - ], - useAlgoliaSearch: [{}, {}, {}], -}; diff --git a/src/skills-builder/test/setupSkillsBuilder.jsx b/src/skills-builder/test/setupSkillsBuilder.jsx deleted file mode 100644 index 2e3b6c7..0000000 --- a/src/skills-builder/test/setupSkillsBuilder.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import { IntlProvider } from '@edx/frontend-platform/i18n'; -import React from 'react'; -import { SkillsBuilderModal } from '../skills-builder-modal'; -import { SkillsBuilderContext } from '../skills-builder-context'; -import { skillsInitialState } from '../data/reducer'; -import { mockData } from './__mocks__/jobSkills.mockData'; -import { getProductRecommendations, searchJobs, useAlgoliaSearch } from '../utils/search'; - -jest.mock('@edx/frontend-platform/logging'); - -jest.mock('react-instantsearch-hooks-web', () => ({ - // eslint-disable-next-line react/prop-types - InstantSearch: ({ children }) => (
{children}
), - Configure: jest.fn(() => (null)), - useSearchBox: jest.fn(() => ({ refine: jest.fn() })), - useHits: jest.fn(() => ({ hits: mockData.hits })), -})); - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: jest.fn(() => ({ search: '?query_string=values' })), -})); - -jest.mock('../utils/search', () => ({ - searchJobs: jest.fn(), - getProductRecommendations: jest.fn(), - useAlgoliaSearch: jest.fn(), -})); - -searchJobs.mockReturnValue(mockData.searchJobs); -getProductRecommendations.mockReturnValue(mockData.productRecommendations); -useAlgoliaSearch.mockReturnValue(mockData.useAlgoliaSearch); - -export const dispatchMock = jest.fn(); - -export const contextValue = { - state: { - ...skillsInitialState, - }, - dispatch: dispatchMock, - algolia: { - // Without this, tests would fail to destructure `searchClient` in the component - searchClient: {}, - productSearchIndex: {}, - jobSearchIndex: {}, - }, -}; - -export const SkillsBuilderWrapperWithContext = (value = contextValue) => ( - - - - - -); diff --git a/src/skills-builder/utils/search.js b/src/skills-builder/utils/search.js deleted file mode 100644 index 06a555a..0000000 --- a/src/skills-builder/utils/search.js +++ /dev/null @@ -1,110 +0,0 @@ -/* -Algolia utility functions used by the Skills Builder feature. -*/ -import { useMemo } from 'react'; -import { getConfig } from '@edx/frontend-platform'; -import { logError } from '@edx/frontend-platform/logging'; - -import algoliasearch from 'algoliasearch'; - -/* - * Utility function to create and return an Algolia client, as well as Index objects for our product and job data. - * - * @return {SearchClient} searchClient - An instantiated Algolia client - * @return {SearchIndex} productSearchIndex - An Algolia index of product data. Used to retrieve product - * recommendations for learners - * @return {SearchIndex} jobSearchIndex - An Algolia index of job taxonomy data. Used to retrieve job metadata that a - * learner is interested in. - */ -// eslint-disable-next-line import/prefer-default-export -export const useAlgoliaSearch = () => { - const config = getConfig(); - - const [searchClient, productSearchIndex, jobSearchIndex] = useMemo( - () => { - const client = algoliasearch( - config.ALGOLIA_APP_ID, - config.ALGOLIA_SEARCH_API_KEY, - ); - const productIndex = client.initIndex(config.ALGOLIA_PRODUCT_INDEX_NAME); - const jobIndex = client.initIndex(config.ALGOLIA_JOBS_INDEX_NAME); - return [client, productIndex, jobIndex]; - }, - [ - config.ALGOLIA_APP_ID, - config.ALGOLIA_PRODUCT_INDEX_NAME, - config.ALGOLIA_JOBS_INDEX_NAME, - config.ALGOLIA_SEARCH_API_KEY, - ], - ); - return [searchClient, productSearchIndex, jobSearchIndex]; -}; - -/* - * Utility function used to format a list of data so it matches syntax Algolia expects. - * - * @param {String} facetFilterType - A string declaring the facet filter type to prepend each search item (e.g. `name`) - * @param {Array[String]} data - An array of job or skills used to query data in Algolia. - * - * @return {Array[String]} formattedData - The transformed array of data to search prepended with the facet filter type - */ -export function formatFacetFilterData(facetFilterType, data) { - const formattedData = []; - if (data) { - data.forEach(item => formattedData.push(`${facetFilterType}:${item}`)); - } - - return formattedData; -} - -/* - * Utility function responsible for querying and returning job information based on input received from a learner. - * - * @param {SearchIndex} jobIndex - An Algolia index of taxonomy connector data used to retrieve job information a - * learner is interested in - * @param {Array[String]} jobNames - A list of job names a learner is interested in - * - * @return {Array[Object]} results - Job information retrieved from Algolia - */ -export const searchJobs = async (jobIndex, jobNames) => { - const formattedJobNames = formatFacetFilterData('name', jobNames); - try { - const { hits } = await jobIndex.search('', { - facetFilters: [ - formattedJobNames, - ], - }); - return hits; - } catch (error) { - logError(error); - } - - return []; -}; - -/* - * Utility function responsible for returning recommendations on products based on the skills of a job a learner is - * interested in. - * - * @param {SearchIndex} productIndex - An Algolia index of product data used to retrieve recommendations for learners. - * @param {String} productType - The type of product information you are trying to retrieve (e.g. `course` or `program`) - * @param {Array[String]} skills - An array of skill names related to a job/career a learner expressed interest in - * - * @return {Array[Object]} results - Product information retrieved from Algolia - */ -export const getProductRecommendations = async (productIndex, productType, skills) => { - const formattedSkillNames = formatFacetFilterData('skills.skill', skills); - try { - const { hits } = await productIndex.search('', { - filters: `product: "${productType}" AND language: "English"`, - facetFilters: [ - formattedSkillNames, - ], - }); - return hits; - } catch (error) { - logError(error); - } - - return []; -}; diff --git a/src/skills-builder/utils/tests/search.test.js b/src/skills-builder/utils/tests/search.test.js deleted file mode 100644 index 1e3edbd..0000000 --- a/src/skills-builder/utils/tests/search.test.js +++ /dev/null @@ -1,74 +0,0 @@ -import { - formatFacetFilterData, - getProductRecommendations, - searchJobs, -} from '../search'; - -jest.mock('@edx/frontend-platform/logging'); - -const mockAlgoliaResult = { - hits: [ - { - key: 'test-course-key', - title: 'Test Title', - skill_names: [ - { - id: 1, - name: 'Skill Name', - }, - ], - }, - ], -}; - -const mockIndex = { - search: jest.fn().mockImplementation(() => mockAlgoliaResult), -}; - -describe('Algolias utility function', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - it('formatFacetFilterData() should return a new array with data formatted as expected', () => { - const result = formatFacetFilterData('name', ['Organic Farmer']); - expect(result).toEqual(['name:Organic Farmer']); - }); - - it('searchJobs() queries Algolia with the expected search parameters', async () => { - const expectedSearchParameters = { - facetFilters: [ - ['name:Enchanter'], - ], - }; - - const results = await searchJobs(mockIndex, ['Enchanter']); - expect(mockIndex.search).toHaveBeenCalledTimes(1); - expect(mockIndex.search).toHaveBeenCalledWith('', expectedSearchParameters); - expect(results).toEqual(mockAlgoliaResult.hits); - }); - - it('searchJobs() returns an empty array when an exception occurs querying Algolia', async () => { - const results = await searchJobs(null, ['Organic Farmer']); - expect(results).toEqual([]); - }); - - it('getProductRecommendations() queries Algolia with the expected search parameters', async () => { - const expectedSearchParameters = { - filters: 'product: "Course" AND language: "English"', - facetFilters: [ - ['skills.skill:Sword Lobbing'], - ], - }; - - const results = await getProductRecommendations(mockIndex, 'Course', ['Sword Lobbing']); - expect(mockIndex.search).toHaveBeenCalledTimes(1); - expect(mockIndex.search).toHaveBeenCalledWith('', expectedSearchParameters); - expect(results).toEqual(mockAlgoliaResult.hits); - }); - - it('getProductRecommendations() returns an empty array when an exception occurs querying Algolia', async () => { - const results = await getProductRecommendations(null, 'Course', ['Management']); - expect(results).toEqual([]); - }); -});