Compare commits

...

109 Commits

Author SHA1 Message Date
Eugene Dyudyunov
5e3508051c fix: error when trying to save 'other education' (#746)
When user selects "Other Education" and clicks save - error occurs.

It's caused by the wrong API call payload value `'o'`
Fix: use the `'other'` payload value instead (the valid one).
2023-07-03 10:21:51 -07:00
Maxwell Frank
8c779590a1 Merge pull request #788 from openedx/mfrank/palm-release-remove-skills
refactor: remove Skills Builder from Palm
2023-06-28 14:21:23 -04:00
Maxwell Frank
b533bf7046 refactor: remove Skills Builder 2023-06-27 15:55:49 +00:00
Bilal Qamar
2af0383847 feat: upgraded to node v18, added .nvmrc and updated workflows (#712)
* feat: upgraded to node v18, added .nvmrc and updated workflows

* build: updated frontend-build, frontend-platform, component-footer & component-header packages

* refactor: updated snapshots

* refactor: updated snapshots
2023-06-09 08:51:17 +02:00
Sagirov Eugeniy
57e3bd0125 chore: update frontend-platform version to v4.2.0 2023-05-02 17:14:27 -03:00
renovate[bot]
85d85007d2 fix(deps): update dependency @edx/frontend-component-footer to v11.7.1 2023-04-10 13:30:36 +00:00
renovate[bot]
9276fe25ad chore(deps): update dependency @edx/frontend-build to v12.8.6 2023-04-10 09:32:52 +00:00
Jenkins
9c2dd68752 chore(i18n): update translations 2023-04-02 16:40:41 -04:00
Maxwell Frank
e4a9045e89 feat: course recommendations for Skills Builder with fix 2023-03-30 15:34:43 -04:00
Maxwell Frank
c1bbbe488a feat: skills builder course recommendations 2023-03-30 19:26:29 +00:00
Maxwell Frank
45ab2f8175 Merge pull request #725 from openedx/revert-721-mfrank/course-recommendations
Revert "feat: course recommendations for Skills Builder"
2023-03-28 14:34:51 -04:00
Maxwell Frank
d9c7096fd7 Revert "feat: course recommendations for Skills Builder" 2023-03-28 14:05:18 -04:00
Maxwell Frank
c6825393c6 feat: course recommendations for Skills Builder
feat: course recommendations for Skills Builder
2023-03-28 09:37:59 -04:00
renovate[bot]
9354f11a99 fix(deps): update dependency @edx/frontend-component-header to v3.6.5 2023-03-28 12:04:23 +00:00
renovate[bot]
e7fc8f52fb chore(deps): update dependency @commitlint/cli to v17.5.1 2023-03-28 10:16:30 +00:00
Maxwell Frank
d8c8f5d7bd feat: course recommendations for Skills Builder 2023-03-27 19:28:46 +00:00
renovate[bot]
e5355e7ac8 chore(deps): update dependency @edx/frontend-build to v12.6.2 2023-03-24 09:14:55 +00:00
Maxwell Frank
99a80d3e66 Merge pull request #718 from openedx/mfrank/authenticated-page-route
fix: authenticated page route
2023-03-22 10:56:11 -04:00
Maxwell Frank
abf9860f62 fix: authenticated page route 2023-03-20 13:39:01 +00:00
renovate[bot]
ccc62a0e48 fix(deps): update dependency redux-saga to v1.2.3 2023-03-20 10:39:41 +00:00
renovate[bot]
650d3d469f fix(deps): update dependency @edx/paragon to v20.28.5 2023-03-20 08:06:56 +00:00
renovate[bot]
ab80fd7671 fix(deps): update dependency @edx/frontend-component-header to v3.6.4 2023-03-13 13:09:42 +00:00
Mashal Malik
f55b304732 refactor: remove unused tranisfex v2 url (#704) 2023-03-13 10:45:28 +05:00
Jenkins
65971820d4 chore(i18n): update translations 2023-03-12 16:40:39 -04:00
Maxwell Frank
7da386264b Merge pull request #706 from openedx/mfrank/retrieving-job-skills-data
APER-2187 Render jobs and related skills for Skills Builder
2023-03-08 14:03:46 -05:00
Maxwell Frank
b1fe21cded feat: SkillsBuilder jobs with related skills 2023-03-07 19:07:10 +00:00
Jenkins
40225d7db3 chore(i18n): update translations 2023-03-05 15:40:37 -05:00
Maxwell Frank
b4ba5276ae Merge pull request #702 from openedx/mfrank/adding-career-interests
feat: SkillsBuilder career interests selection
2023-02-28 14:55:57 -05:00
Maxwell Frank
ddff5364ce feat: SkillsBuilder career interests selection 2023-02-28 19:51:16 +00:00
David Joy
f57f5c4725 docs: update the maintaining group to openedx/2u-aperture (#703)
The @edx/arch-fed group no longer exists - this repo is maintained by the @openedx/2u-aperture team.
2023-02-28 13:46:03 -05:00
Feanil Patel
e6feef00eb Merge pull request #696 from openedx/repo_checks/ensure_workflows
Update standard workflow files.
2023-02-27 22:36:12 -05:00
Maxwell Frank
87487e37d7 Merge pull request #693 from openedx/mfrank/goals-and-job-select-v2
APER-2186: adding goal and job title selection
2023-02-27 09:16:06 -05:00
renovate[bot]
6b451a4437 fix(deps): update dependency @edx/frontend-component-footer to v11.6.3 2023-02-27 12:33:52 +00:00
renovate[bot]
b10b31860d chore(deps): update commitlint monorepo to v17.4.4 2023-02-27 09:29:59 +00:00
Jenkins
83e2b66c77 chore(i18n): update translations 2023-02-26 15:40:39 -05:00
dependabot[bot]
6fa5681e91 build(deps): bump cookiejar from 2.1.3 to 2.1.4 (#674)
Bumps [cookiejar](https://github.com/bmeck/node-cookiejar) from 2.1.3 to 2.1.4.
- [Release notes](https://github.com/bmeck/node-cookiejar/releases)
- [Commits](https://github.com/bmeck/node-cookiejar/commits)

---
updated-dependencies:
- dependency-name: cookiejar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-24 13:07:48 -08:00
dependabot[bot]
e9e48e4eb0 build(deps): bump json5 from 1.0.1 to 1.0.2 (#661)
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-24 13:03:26 -08:00
renovate[bot]
17b4933278 fix(deps): update dependency @edx/frontend-platform to v3 (#660)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-24 12:52:53 -08:00
Maxwell Frank
68dc8a1045 feat: first two questions of Skills Builder 2023-02-24 19:26:53 +00:00
Justin Hynes
21a3e9259d Merge pull request #695 from openedx/jhynes/aper-2262
feat: add utility function to retrieve product recommendations based on job skills
2023-02-24 09:06:26 -05:00
Justin Hynes
a6086fd4bf feat: add utility function to retrieve product recommendations based on job skills
[APER-2262]

- add a utility function to retrieve product recommendations based on skills from a job a learner is interested in
- add additional tests and coverage around new utility functions in `search.jsx`
2023-02-24 08:57:37 -05:00
edX requirements bot
0c427cf5e3 chore: update browserslist DB (#656) 2023-02-23 13:44:15 -08:00
Feanil Patel
75ea8bc207 build: Updating a missing workflow file add-depr-ticket-to-depr-board.yml.
The .github/workflows/add-depr-ticket-to-depr-board.yml workflow is missing or needs an update to stay in
sync with the current standard for this workflow as defined in the
`.github` repo of the `openedx` GitHub org.
2023-02-23 14:01:50 -05:00
Feanil Patel
47c06c0f5d build: Creating a missing workflow file add-remove-label-on-comment.yml.
The .github/workflows/add-remove-label-on-comment.yml workflow is missing or needs an update to stay in
sync with the current standard for this workflow as defined in the
`.github` repo of the `openedx` GitHub org.
2023-02-23 14:01:49 -05:00
Feanil Patel
8e0ab6db4d build: Creating a missing workflow file self-assign-issue.yml.
The .github/workflows/self-assign-issue.yml workflow is missing or needs an update to stay in
sync with the current standard for this workflow as defined in the
`.github` repo of the `openedx` GitHub org.
2023-02-23 14:01:48 -05:00
Jenkins
20159f140e chore(i18n): update translations 2023-02-19 15:40:37 -05:00
Justin Hynes
2d05de92af Merge pull request #691 from openedx/jhynes/aper-2261_algolia-utility-functions
feat: Add utility functions for querying job related data from Algolia
2023-02-17 14:12:54 -05:00
Justin Hynes
10f93420f4 feat: Add utility functions for querying job related data from Algolia
[APER-2261]
* rename `hooks.jsx` to `search.jsx` as this is more of a collection of utilities for working with Algolia
* add a utiltiy function for returning job info (from our "job" Algolia index) based on a list of jobs a learner is interested in
* add a utility function for formatting job names based on the syntax Algolia expects
2023-02-17 14:08:11 -05:00
Maxwell Frank
a12f91f7a5 Merge pull request #685 from openedx/mfrank/building-out-reducer
feat: adding actions and reducer for Skills Builder
2023-02-15 13:34:06 -05:00
Maxwell Frank
8f42e6fbfb feat: adding actions and reducer 2023-02-15 17:09:12 +00:00
Justin Hynes
4ecdf583ea Merge pull request #690 from openedx/jhynes/aper-2261
feat: Add Algolia support to Profile MFE for Skills Builder
2023-02-15 11:37:46 -05:00
Justin Hynes
e75864b860 feat: Add Algolia support to Profile MFE
[APER-2261]

This PR adds Algolia support to the Profile MFE and the upcoming Skills Builder feature.

* Adds new dependency for the `algoliasearch` package
* Add new config to support Algolia
* Update MFE configuration so we can access the new configuration variables
* Add hook to initialize Algolia client and return job and product Algolia indexes (based on settings)
* Update SkillsBuilderModal to add test code that displays the results of querying Algolia
2023-02-15 09:56:52 -05:00
Jenkins
a697e3c543 chore(i18n): update translations 2023-02-12 15:40:35 -05:00
Jason Wesson
04607dba1d Feat: display Learning Goal in profile (#676)
* feat: add unit tests for LearningGoal component

* feat: add LearningGoals component to Profile

---------

Co-authored-by: Jason Wesson <jwesson@2u.com>
2023-02-08 13:54:47 -08:00
Justin Hynes
6a4c8d9138 Merge pull request #682 from openedx/jhynes/aper-2258
feat: add Skills Builder Header component, refactor to use ModalDialog
2023-02-06 14:45:31 -05:00
Justin Hynes
dbf716eef5 feat: add Skills Builder Header component, refactor to use ModalDialog
[APER-2258]

This PR adds the SkillsBuilderHeader component to the profile MFE.

There was also some additional refactoring work required to display the header in the modal. The FullscreenModal component is not flexible enough to allow custom header designs to be displayed (only text). We have to pivot to using the `ModalDialog` family of components instead.
2023-02-06 13:34:04 -05:00
renovate[bot]
5eaab4f07d fix(deps): update dependency redux to v4.2.1 2023-02-06 13:31:33 +00:00
renovate[bot]
a139c2f71d fix(deps): update dependency @edx/frontend-component-footer to v11.6.2 2023-02-06 11:47:01 +00:00
Maxwell Frank
9e34fdd68d Merge pull request #680 from openedx/mfrank/adding-skills-context
feat: added skills context
2023-02-01 13:31:52 -05:00
Justin Hynes
109c5d437d Merge pull request #681 from openedx/jhynes/aper-2240-cleanup
fix: remove LR MFE URL building logic
2023-01-31 13:48:51 -05:00
Justin Hynes
25d0ecb531 fix: remove learner record MFE URL building logic
[APER-2240]

The Profile MFE no longer needs to understand anything about the Learner Record MFE. The Credentials IDA now has logic to determine if a request should be redirected to the Learner Record MFE so we can remove these changes from the Profile MFE.
2023-01-30 14:00:13 -05:00
Maxwell Frank
767af3c40b feat: added skills context 2023-01-30 15:46:15 +00:00
renovate[bot]
6a05552969 fix(deps): update dependency core-js to v3.27.2 2023-01-30 15:02:41 +00:00
renovate[bot]
628914dce3 fix(deps): update dependency @edx/frontend-component-header to v3.6.1 2023-01-30 10:28:08 +00:00
Jenkins
be7e204c91 chore(i18n): update translations 2023-01-29 15:40:36 -05:00
Bilal Qamar
c1d4c36a65 chore: update dependency @edx/frontend-build to v12.4.19 (#675) 2023-01-26 12:20:35 +05:00
renovate[bot]
ce04a04c36 fix(deps): update dependency @edx/frontend-component-footer to v11.6.1 2023-01-23 14:58:40 +00:00
renovate[bot]
346c08e5d6 chore(deps): update dependency @edx/frontend-build to v12.4.16 2023-01-23 11:27:47 +00:00
Jenkins
fe61237464 chore(i18n): update translations 2023-01-22 15:40:35 -05:00
renovate[bot]
c89285f0e8 chore(deps): update dependency glob to v8.1.0 2023-01-16 15:28:14 +00:00
renovate[bot]
7523a1edb3 chore(deps): update commitlint monorepo to v17.4.2 2023-01-16 11:27:14 +00:00
Jenkins
9f1c16a599 chore(i18n): update translations 2023-01-15 15:40:34 -05:00
Maxwell Frank
fdcef0edc8 Merge pull request #664 from openedx/mfrank/adding-skills-route
feat: set up skills builder route
2023-01-11 13:53:03 -05:00
Maxwell Frank
1f056dfac7 feat: set up skills builder route 2023-01-11 18:45:06 +00:00
renovate[bot]
2814349f37 fix(deps): update dependency @edx/brand to v1.2.0 2023-01-09 11:50:01 +00:00
renovate[bot]
a4327a98e4 chore(deps): update commitlint monorepo to v17.4.0 2023-01-09 08:15:56 +00:00
renovate[bot]
50fe0ecb6f fix(deps): update dependency core-js to v3.27.1 2023-01-02 08:58:39 +00:00
renovate[bot]
8e011fdf7b fix(deps): update dependency core-js to v3.27.0 2022-12-26 08:57:37 +00:00
dependabot[bot]
a6a35f3762 build(deps): bump loader-utils from 1.4.0 to 1.4.2 (#655)
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-22 12:54:32 -08:00
renovate[bot]
259f4b2a5e chore(deps): update dependency @edx/frontend-build to v12.4.15 (#625)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-22 12:34:58 -08:00
Muhammad Abdullah Waheed
65a4091e78 Automate Browserlist DB Update (#615)
* feat: added cron github action to auto update brwoserlist DB periodically

* refactor: used a shared script to update broswerslist DB, create PR and automerge it
2022-12-22 12:06:26 -08:00
Jason Wesson
e5ee7894b0 refactor: updated frontend-build & resolved eslint issues (#654)
Co-authored-by: Bilal Qamar <59555732+BilalQamar95@users.noreply.github.com>
2022-12-22 12:00:53 -08:00
renovate[bot]
8f781ea867 chore(deps): update dependency glob to v8 (#622)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-20 13:16:24 -08:00
dependabot[bot]
7d208a91ac build(deps): bump loader-utils from 1.4.0 to 1.4.2 (#635)
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-20 13:07:00 -08:00
dependabot[bot]
80599a617f build(deps): bump minimatch and recursive-readdir (#642)
Bumps [minimatch](https://github.com/isaacs/minimatch) and [recursive-readdir](https://github.com/jergason/recursive-readdir). These dependencies needed to be updated together.

Updates `minimatch` from 3.0.4 to 3.1.2
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

Updates `recursive-readdir` from 2.2.2 to 2.2.3
- [Release notes](https://github.com/jergason/recursive-readdir/releases)
- [Changelog](https://github.com/jergason/recursive-readdir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jergason/recursive-readdir/commits/v2.2.3)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
- dependency-name: recursive-readdir
  dependency-type: indirect

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-20 12:59:41 -08:00
dependabot[bot]
652559b157 build(deps): bump decode-uri-component from 0.2.0 to 0.2.2 (#644)
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-20 12:53:22 -08:00
renovate[bot]
5363663170 fix(deps): update dependency universal-cookie to v4 (#279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-20 12:44:44 -08:00
renovate[bot]
b34041f090 fix(deps): update dependency core-js to v3.26.1 2022-12-19 10:22:55 +00:00
renovate[bot]
a82e3e9918 fix(deps): update dependency @edx/frontend-component-header to v3.6.0 2022-12-19 08:03:15 +00:00
mashal-m
6c15c2a0fd fix: remove is-es6 check 2022-12-15 12:43:57 +00:00
mashal-m
da5bf2f533 build: use shared browserslist configuration and upgrade paragon version 2022-12-15 12:43:57 +00:00
renovate[bot]
e507548d48 fix(deps): update dependency @edx/frontend-component-footer to v11.6.0 2022-12-12 11:18:25 +00:00
renovate[bot]
ff6c63c86b fix(deps): update dependency redux-saga to v1.2.2 2022-12-12 08:31:07 +00:00
renovate[bot]
6e24a48570 fix(deps): update dependency @edx/frontend-component-header to v3.5.0 2022-12-05 13:32:14 +00:00
renovate[bot]
42a0d27b47 fix(deps): update dependency @edx/frontend-component-footer to v11.5.2 2022-12-05 11:02:32 +00:00
edX requirements bot
6a79462567 fix: -t flag added in pull translation command (#639) 2022-11-30 16:43:21 +05:00
renovate[bot]
afe39e8b9e fix(deps): update dependency @edx/frontend-component-header to v3.4.1 2022-11-28 12:53:13 +00:00
renovate[bot]
38afcb8a5a fix(deps): update dependency @edx/frontend-component-footer to v11.5.1 2022-11-28 09:16:22 +00:00
renovate[bot]
5bf65de9e4 chore(deps): update commitlint monorepo to v17.3.0 2022-11-28 09:09:07 +00:00
renovate[bot]
28423c261d fix(deps): update dependency regenerator-runtime to v0.13.11 2022-11-21 09:04:15 +00:00
renovate[bot]
0986fd05ab chore(deps): update commitlint monorepo to v17.2.0 2022-11-14 08:32:19 +00:00
renovate[bot]
21adb70478 fix(deps): update dependency reselect to v4.1.7 2022-11-14 08:25:41 +00:00
renovate[bot]
daca35ffbe fix(deps): update dependency redux-thunk to v2.4.2 2022-11-07 10:07:44 +00:00
renovate[bot]
9fe9164bb2 chore(deps): update dependency enzyme-adapter-react-16 to v1.15.7 2022-11-07 07:58:45 +00:00
Jenkins
09e010443d chore(i18n): update translations 2022-10-30 16:40:23 -04:00
renovate[bot]
87377a1443 fix(deps): pin dependency react-helmet to 6.1.0 2022-10-24 08:47:44 +00:00
Jenkins
5f89049506 chore(i18n): update translations 2022-10-23 16:40:27 -04:00
Diana Olarte
4f00bc43b9 feat: allow runtieme configuration (#586)
Allows frontend-app-profile to be configured at
runtime using the LMS's new MFE Configuration API.

Part of https://github.com/openedx/frontend-wg/issues/103
2022-10-17 12:13:59 -04:00
renovate[bot]
f732fa7ffc fix(deps): update dependency regenerator-runtime to v0.13.10 2022-10-17 09:48:16 +00:00
57 changed files with 7304 additions and 21296 deletions

5
.env
View File

@@ -22,6 +22,7 @@ LOGO_URL=''
LOGO_TRADEMARK_URL=''
LOGO_WHITE_URL=''
FAVICON_URL=''
ENABLE_LEARNER_RECORD_MFE=''
LEARNER_RECORD_MFE_BASE_URL=''
COLLECT_YEAR_OF_BIRTH=true
APP_ID=''
MFE_CONFIG_API_URL=''
ENABLE_SKILLS_BUILDER_PROFILE=''

View File

@@ -23,6 +23,7 @@ LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
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=''
LEARNER_RECORD_MFE_BASE_URL='http://localhost:1990'
COLLECT_YEAR_OF_BIRTH=true
APP_ID=''
MFE_CONFIG_API_URL=''
ENABLE_SKILLS_BUILDER_PROFILE=''

View File

@@ -18,5 +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_PROFILE=''
LEARNER_RECORD_MFE_BASE_URL='http://localhost:1990'
COLLECT_YEAR_OF_BIRTH=true
APP_ID=''
MFE_CONFIG_API_URL=''

View File

@@ -16,4 +16,4 @@ jobs:
secrets:
GITHUB_APP_ID: ${{ secrets.GRAPHQL_AUTH_APP_ID }}
GITHUB_APP_PRIVATE_KEY: ${{ secrets.GRAPHQL_AUTH_APP_PEM }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}

View File

@@ -0,0 +1,20 @@
# This workflow runs when a comment is made on the ticket
# If the comment starts with "label: " it tries to apply
# the label indicated in rest of comment.
# If the comment starts with "remove label: ", it tries
# to remove the indicated label.
# Note: Labels are allowed to have spaces and this script does
# not parse spaces (as often a space is legitimate), so the command
# "label: really long lots of words label" will apply the
# label "really long lots of words label"
name: Allows for the adding and removing of labels via comment
on:
issue_comment:
types: [created]
jobs:
add_remove_labels:
uses: openedx/.github/.github/workflows/add-remove-label-on-comment.yml@master

View File

@@ -11,16 +11,15 @@ jobs:
matrix:
npm-test:
- i18n_extract
- is-es5
- lint
- test
node: [16]
steps:
- uses: actions/checkout@v3
- name: Setup Nodejs Env
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- run: npm install -g npm@8.x.x
node-version: ${{ env.NODE_VER }}
- run: make requirements
- run: make test NPM_TESTS=build
- run: make test NPM_TESTS=${{ matrix.npm-test }}

View File

@@ -10,4 +10,4 @@ on:
jobs:
version-check:
uses: openedx/.github/.github/workflows/lockfileversion-check.yml@master
uses: openedx/.github/.github/workflows/lockfileversion-check-v3.yml@master

12
.github/workflows/self-assign-issue.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# This workflow runs when a comment is made on the ticket
# If the comment starts with "assign me" it assigns the author to the
# ticket (case insensitive)
name: Assign comment author to ticket if they say "assign me"
on:
issue_comment:
types: [created]
jobs:
self_assign_by_comment:
uses: openedx/.github/.github/workflows/self-assign-issue.yml@master

View File

@@ -0,0 +1,12 @@
name: Update Browserslist DB
on:
schedule:
- cron: '0 0 * * 1'
workflow_dispatch:
jobs:
update-browserslist:
uses: openedx/.github/.github/workflows/update-browserslist-db.yml@master
secrets:
requirements_bot_github_token: ${{ secrets.requirements_bot_github_token }}

2
.nvmrc
View File

@@ -1 +1 @@
v16
18

7
Makefile Executable file → Normal file
View File

@@ -5,13 +5,10 @@ transifex_langs = "ar,fr,es_419,zh_CN,pt,it,de,uk,ru,hi,fr_CA"
transifex_utils = ./node_modules/.bin/transifex-utils.js
i18n = ./src/i18n
transifex_input = $(i18n)/transifex_input.json
tx_url1 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/translation/en/strings/
tx_url2 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/source/
# This directory must match .babelrc .
transifex_temp = ./temp/babel-plugin-react-intl
NPM_TESTS=build i18n_extract lint test is-es5
NPM_TESTS=build i18n_extract lint test
.PHONY: test
test: $(addprefix test.npm.,$(NPM_TESTS)) ## validate ci suite
@@ -54,7 +51,7 @@ push_translations:
# Pulls translations from Transifex.
pull_translations:
tx pull -f --mode reviewed --languages=$(transifex_langs)
tx pull -t -f --mode reviewed --languages=$(transifex_langs)
# This target is used by Travis.
validate-no-uncommitted-package-lock-changes:

View File

@@ -3,7 +3,7 @@
frontend-app-profile
====================
This is a micro-frontend application responsible for the display and updating of user profiles. Please tag **@edx/arch-fed** on any PRs or issues.
This is a micro-frontend application responsible for the display and updating of user profiles. Please tag **@openedx/2u-aperture** on any PRs or issues.
When a user views their own profile, they're given fields to edit their full name, location, primary spoken language, education, social links, and bio. Each field also has a dropdown to select the visibility of that field - i.e., whether it can be viewed by other learners.

27022
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,6 @@
"scripts": {
"build": "fedx-scripts webpack",
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
"is-es5": "es-check es5 ./dist/*.js",
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
"snapshot": "fedx-scripts jest --updateSnapshot",
"start": "fedx-scripts webpack-dev-server --progress",
@@ -25,22 +24,22 @@
"access": "public"
},
"browserslist": [
"last 2 versions",
"ie 11"
"extends @edx/browserslist-config"
],
"dependencies": {
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-component-footer": "10.3.0",
"@edx/frontend-component-header": "2.6.1",
"@edx/frontend-platform": "1.15.6",
"@edx/paragon": "19.25.3",
"@edx/brand": "npm:@edx/brand-openedx@1.2.0",
"@edx/frontend-component-footer": "12.0.0",
"@edx/frontend-component-header": "4.0.0",
"@edx/frontend-platform": "4.2.0",
"@edx/paragon": "^20.20.0",
"@fortawesome/fontawesome-svg-core": "1.2.36",
"@fortawesome/free-brands-svg-icons": "5.15.4",
"@fortawesome/free-regular-svg-icons": "5.15.4",
"@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/react-fontawesome": "0.2.0",
"classnames": "2.3.2",
"core-js": "3.25.5",
"core-js": "3.27.2",
"history": "4.10.1",
"lodash.camelcase": "4.3.0",
"lodash.get": "4.4.2",
"lodash.pick": "4.4.0",
@@ -48,28 +47,30 @@
"prop-types": "15.8.1",
"react": "16.14.0",
"react-dom": "16.14.0",
"react-helmet": "6.1.0",
"react-redux": "7.2.9",
"react-router": "5.3.4",
"react-router-dom": "5.3.4",
"redux": "4.2.0",
"redux": "4.2.1",
"redux-devtools-extension": "2.13.9",
"redux-logger": "3.0.6",
"redux-saga": "1.2.1",
"redux-thunk": "2.4.1",
"regenerator-runtime": "0.13.9",
"reselect": "4.1.6",
"universal-cookie": "3.1.0"
"redux-saga": "1.2.3",
"redux-thunk": "2.4.2",
"regenerator-runtime": "0.13.11",
"reselect": "4.1.7",
"universal-cookie": "4.0.4"
},
"devDependencies": {
"@commitlint/cli": "17.1.2",
"@commitlint/config-angular": "17.1.0",
"@commitlint/cli": "17.5.1",
"@commitlint/config-angular": "17.4.4",
"@edx/browserslist-config": "^1.1.1",
"@edx/frontend-build": "12.8.6",
"@edx/reactifex": "2.1.1",
"@edx/frontend-build": "12.0.6",
"@testing-library/react": "11.2.7",
"codecov": "3.8.3",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.6",
"es-check": "5.2.4",
"glob": "7.2.3",
"enzyme-adapter-react-16": "1.15.7",
"glob": "8.1.0",
"react-test-renderer": "16.14.0",
"reactifex": "1.1.1",
"redux-mock-store": "1.5.4"

21
src/head/Head.jsx Normal file
View File

@@ -0,0 +1,21 @@
import React from 'react';
import { Helmet } from 'react-helmet';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
import messages from './messages';
const Head = ({ intl }) => (
<Helmet>
<title>
{intl.formatMessage(messages['profile.page.title'], { siteName: getConfig().SITE_NAME })}
</title>
<link rel="shortcut icon" href={getConfig().FAVICON_URL} type="image/x-icon" />
</Helmet>
);
Head.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(Head);

17
src/head/Head.test.jsx Normal file
View File

@@ -0,0 +1,17 @@
import React from 'react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { Helmet } from 'react-helmet';
import { mount } from 'enzyme';
import { getConfig } from '@edx/frontend-platform';
import Head from './Head';
describe('Head', () => {
const props = {};
it('should match render title tag and favicon with the site configuration values', () => {
mount(<IntlProvider locale="en"><Head {...props} /></IntlProvider>);
const helmet = Helmet.peek();
expect(helmet.title).toEqual(`Profile | ${getConfig().SITE_NAME}`);
expect(helmet.linkTags[0].rel).toEqual('shortcut icon');
expect(helmet.linkTags[0].href).toEqual(getConfig().FAVICON_URL);
});
});

11
src/head/messages.js Normal file
View File

@@ -0,0 +1,11 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'profile.page.title': {
id: 'profile.page.title',
defaultMessage: 'Profile | {siteName}',
description: 'Title tag',
},
});
export default messages;

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "الملف الشخصي | {siteName}",
"profile.age.details": "لمشاركة ملفك الشخصي مع بقية متعلمي {siteName}، يجب أن تؤكد أنك عمرك يفوق 13 عامًا.",
"profile.age.set.date": "ضيط تاريخ ميلادك",
"profile.datejoined.member.since": "عضو منذ {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "تم الحفظ",
"profile.visibility.who.just.me": "أنا فقط",
"profile.visibility.who.everyone": "جميع من على {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "الاسم الكامل",
"profile.name.details": "هذا هو الاسم الذي يظهر في حسابك وفي شهاداتك",
"profile.name.empty": "إضافة الاسم",
@@ -47,5 +53,32 @@
"profile.notfound.message": "الصفحة التي تبحث عنها غير متوفرة أو هناك خطأ في العنوان. رجاءً تحقق من العنوان و حاول مجدّدًا.",
"profile.viewMyRecords": "عرض سجلّاتي",
"profile.loading": "يتم تحميل الملف الشخصي...",
"profile.username.description": "معلومات ملفك الشخصي تظهر لك فقط. وحده اسم المستخدم الخاص بك يظهر للآخرين على {siteName}."
"profile.username.description": "معلومات ملفك الشخصي تظهر لك فقط. وحده اسم المستخدم الخاص بك يظهر للآخرين على {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profile | {siteName}",
"profile.age.details": "To share your profile with other {siteName} learners, you must confirm that you are over the age of 13.",
"profile.age.set.date": "Set your date of birth",
"profile.datejoined.member.since": "Member since {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Saved",
"profile.visibility.who.just.me": "Just me",
"profile.visibility.who.everyone": "Everyone on {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "Full Name",
"profile.name.details": "This is the name that appears in your account and on your certificates.",
"profile.name.empty": "Add name",
@@ -47,5 +53,32 @@
"profile.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
"profile.viewMyRecords": "View My Records",
"profile.loading": "Profile loading...",
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}."
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Perfil | {siteName}",
"profile.age.details": "Para compartir el perfil con otros {siteName} estudiantes, debe confirmar que es mayor de 13 años.",
"profile.age.set.date": "Establece tu fecha de nacimiento",
"profile.datejoined.member.since": "Miembro desde {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Guardado",
"profile.visibility.who.just.me": "Solo yo",
"profile.visibility.who.everyone": "Todos en {siteName}",
"profile.learningGoal.learningGoal": "Objetivo de aprendizaje",
"profile.learningGoal.options.start_career": "quiero empezar mi carrera",
"profile.learningGoal.options.advance_career": "Quiero avanzar en mi carrera",
"profile.learningGoal.options.learn_something_new": "quiero aprender algo nuevo",
"profile.learningGoal.options.something_else": "Algo más",
"profile.name.full.name": "Nombre completo",
"profile.name.details": "Este es el nombre que aparecerá en tu cuenta y en tus certificados.",
"profile.name.empty": "Añade nombre",
@@ -47,5 +53,32 @@
"profile.notfound.message": "La página que estas buscando no está disponible o hay un error en la URL. Por favor, comprueba la URL y vuelve a intentarlo.",
"profile.viewMyRecords": "Ver mis registros",
"profile.loading": "Cargando perfil...",
"profile.username.description": "La información del perfil solo la visualiza usted. Solo el nombre de usuario es visible para los demás en {siteName}."
"profile.username.description": "La información del perfil solo la visualiza usted. Solo el nombre de usuario es visible para los demás en {siteName}.",
"skills.builder.header.title": "Constructor de habilidades",
"skills.builder.header.subheading": "Dejanos ser tu guía",
"go.back.button": "Volver Atrás",
"next.step.button": "Próximo paso",
"exit.button": "Salida",
"select.preferences": "Seleccionar preferencias",
"review.results": "Revisar resultados",
"skills.builder.description": "Encontrar los cursos y programas adecuados que lo ayuden a alcanzar sus metas.",
"learning.goal.prompt": "Primero, contar qué quieres lograr",
"select.learning.goal": "Seleccionar una meta",
"learning.goal.start_career": "Quiero empezar mi carrera",
"learning.goal.advance_career": "Quiero avanzar en mi carrera",
"learning.goal.change_career": "Quiero cambiar de carrera",
"learning.goal.something.new": "Quiero aprender algo nuevo",
"learning.goal.something.else": "Algo más",
"job.title.prompt": "A continuación, busque y seleccione su título de trabajo actual",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "Soy un estudiante",
"currently.looking.checkbox.prompt": "Actualmente estoy buscando trabajo",
"career.interest.prompt": "¿Qué carreras te interesan?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Eliminar interés profesional:",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profile | {siteName}",
"profile.age.details": "Pour partager votre profil avec d'autres étudiants {siteName}, vous devez confirmer que vous avez plus de 13 ans.",
"profile.age.set.date": "Définissez votre date de naissance",
"profile.datejoined.member.since": "Membre depuis {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Enregistré",
"profile.visibility.who.just.me": "Juste moi",
"profile.visibility.who.everyone": "Tout le monde sur {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "Nom complet",
"profile.name.details": "C'est le nom qui apparaît dans votre compte et sur vos certificats.",
"profile.name.empty": "Ajouter un nom",
@@ -47,5 +53,32 @@
"profile.notfound.message": "La page que vous recherchez n'est pas disponible ou il y a une erreur dans l'URL. Veuillez vérifier l'URL et réessayer.",
"profile.viewMyRecords": "Voir mes succès",
"profile.loading": "Chargement du profil....",
"profile.username.description": "Les informations de votre profil ne sont visibles que par vous. Seul votre nom d'utilisateur est visible par les autres sur {siteName}."
"profile.username.description": "Les informations de votre profil ne sont visibles que par vous. Seul votre nom d'utilisateur est visible par les autres sur {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profil | {siteName}",
"profile.age.details": "Pour partager votre profil avec d'autres apprenants {siteName}, vous devez confirmer que vous avez plus de 13 ans.",
"profile.age.set.date": "Entrez votre date de naissance",
"profile.datejoined.member.since": "Membre depuis {year}",
@@ -15,17 +16,17 @@
"profile.country.label": "Adresse",
"profile.country.empty": "Ajouter un emplacement",
"profile.education.empty": "Ajouter formation",
"profile.education.education": "Education",
"profile.education.education": "Formation",
"profile.education.levels.p": "Doctorat",
"profile.education.levels.m": "Maitrise ou diplôme professionnel",
"profile.education.levels.m": "Maîtrise ou diplôme professionnel",
"profile.education.levels.b": "Diplôme de baccalauréat",
"profile.education.levels.a": "Diplôme d'associé",
"profile.education.levels.hs": "Lycée / enseignement secondaire",
"profile.education.levels.jhs": "Collège / enseignement secondaire inférieur",
"profile.education.levels.el": "Enseignement primaire",
"profile.education.levels.none": "Sans diplôme",
"profile.education.levels.o": "Autre niveau d'étude",
"profile.editbutton.edit": "Modifier",
"profile.education.levels.none": "Sans formation formelle",
"profile.education.levels.o": "Autre niveau de formation",
"profile.editbutton.edit": "Éditer",
"profile.formcontrols.who.can.see": "Qui peut voir ça :",
"profile.formcontrols.button.cancel": "Annuler",
"profile.formcontrols.button.save": "Sauvegarder",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Sauvegardé",
"profile.visibility.who.just.me": "Juste moi",
"profile.visibility.who.everyone": "Tout le monde sur {siteName}",
"profile.learningGoal.learningGoal": "Objectif d'apprentissage",
"profile.learningGoal.options.start_career": "Je veux commencer ma carrière",
"profile.learningGoal.options.advance_career": "Je veux faire progresser ma carrière",
"profile.learningGoal.options.learn_something_new": "Je veux apprendre quelque chose de nouveau",
"profile.learningGoal.options.something_else": "Autre chose",
"profile.name.full.name": "Nom complet",
"profile.name.details": "C'est le nom qui apparaît dans votre compte et sur vos attestations.",
"profile.name.empty": "Ajouter un nom",
@@ -40,12 +46,39 @@
"profile.preferredlanguage.label": "Langue principale parlée",
"profile.profileavatar.upload-button": "Téléverser une photo",
"profile.profileavatar.remove.button": "Supprimer",
"profile.image.alt.attribute": "Avatar de profil",
"profile.image.alt.attribute": "avatar de profil",
"profile.profileavatar.change-button": "Modifier",
"profile.sociallinks.add": "Ajouter {network}",
"profile.sociallinks.social.links": "Liens vers les réseaux sociaux",
"profile.notfound.message": "La page que vous recherchez n'est pas disponible ou il y a une erreur dans l'URL. Veuillez vérifier l'URL et réessayer.",
"profile.viewMyRecords": "Afficher mes dossiers",
"profile.loading": "Chargement du profil...",
"profile.username.description": "Les informations de votre profil ne sont visibles que par vous. Seul votre nom d'utilisateur est visible par les autres sur {siteName}."
"profile.username.description": "Les informations de votre profil ne sont visibles que par vous. Seul votre nom d'utilisateur est visible par les autres sur {siteName}.",
"skills.builder.header.title": "Constructeur de compétences",
"skills.builder.header.subheading": "Laissez EDUlib être votre guide",
"go.back.button": "Retour",
"next.step.button": "Prochaine étape",
"exit.button": "Sortie",
"select.preferences": "Sélectionnez les préférences",
"review.results": "Examiner les résultats",
"skills.builder.description": "Trouvez les bons cours et programmes qui vous aideront à atteindre vos objectifs.",
"learning.goal.prompt": "Tout d&#39;abord, dites-nous ce que vous voulez réaliser",
"select.learning.goal": "Sélectionnez un objectif",
"learning.goal.start_career": "Je veux commencer ma carrière",
"learning.goal.advance_career": "Je veux faire progresser ma carrière",
"learning.goal.change_career": "Je veux changer de métier",
"learning.goal.something.new": "Je veux apprendre quelque chose de nouveau",
"learning.goal.something.else": "Autre chose",
"job.title.prompt": "Ensuite, recherchez et sélectionnez votre titre de poste actuel",
"job.title.input.placeholder.text": "Rechercher et sélectionner un intitulé de poste",
"student.checkbox.prompt": "Je suis étudiant.e",
"currently.looking.checkbox.prompt": "Je suis actuellement à la recherche d&#39;un emploi",
"career.interest.prompt": "Quels métiers vous intéressent ?",
"career.interest.input.placeholder.text": "Sélectionnez jusqu'à 3 nouveaux intitulés de poste",
"career.interest.remove.button.alt.text": "Supprimer l'intérêt professionnel :",
"matches.found.success.alert": "Nous avons trouvé des compétences et des cours qui correspondent à vos préférences !",
"matches.not.found.danger.alert": "Nous n'avons pas pu récupérer les recommandations pour le moment. Veuillez réessayer plus tard.",
"related.skills.heading": "Compétences connexes",
"related.skills.selectable.box.label.text": "Compétences connexes:",
"product.recommendations.header.text": "{productType} recommandations pour {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profile | {siteName}",
"profile.age.details": "To share your profile with other {siteName} learners, you must confirm that you are over the age of 13.",
"profile.age.set.date": "Set your date of birth",
"profile.datejoined.member.since": "Member since {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Saved",
"profile.visibility.who.just.me": "Just me",
"profile.visibility.who.everyone": "Everyone on {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "Full Name",
"profile.name.details": "This is the name that appears in your account and on your certificates.",
"profile.name.empty": "Add name",
@@ -47,5 +53,32 @@
"profile.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
"profile.viewMyRecords": "View My Records",
"profile.loading": "Profile loading...",
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}."
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profile | {siteName}",
"profile.age.details": "To share your profile with other {siteName} learners, you must confirm that you are over the age of 13.",
"profile.age.set.date": "Set your date of birth",
"profile.datejoined.member.since": "Member since {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Saved",
"profile.visibility.who.just.me": "Just me",
"profile.visibility.who.everyone": "Everyone on {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "Full Name",
"profile.name.details": "This is the name that appears in your account and on your certificates.",
"profile.name.empty": "Add name",
@@ -47,5 +53,32 @@
"profile.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
"profile.viewMyRecords": "View My Records",
"profile.loading": "Profile loading...",
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}."
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profile | {siteName}",
"profile.age.details": "To share your profile with other {siteName} learners, you must confirm that you are over the age of 13.",
"profile.age.set.date": "Set your date of birth",
"profile.datejoined.member.since": "Member since {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Saved",
"profile.visibility.who.just.me": "Just me",
"profile.visibility.who.everyone": "Everyone on {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "Full Name",
"profile.name.details": "This is the name that appears in your account and on your certificates.",
"profile.name.empty": "Add name",
@@ -47,5 +53,32 @@
"profile.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
"profile.viewMyRecords": "View My Records",
"profile.loading": "Profile loading...",
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}."
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profile | {siteName}",
"profile.age.details": "To share your profile with other {siteName} learners, you must confirm that you are over the age of 13.",
"profile.age.set.date": "Set your date of birth",
"profile.datejoined.member.since": "Member since {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Saved",
"profile.visibility.who.just.me": "Just me",
"profile.visibility.who.everyone": "Everyone on {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "Full Name",
"profile.name.details": "This is the name that appears in your account and on your certificates.",
"profile.name.empty": "Add name",
@@ -47,5 +53,32 @@
"profile.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
"profile.viewMyRecords": "View My Records",
"profile.loading": "Profile loading...",
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}."
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profile | {siteName}",
"profile.age.details": "To share your profile with other {siteName} learners, you must confirm that you are over the age of 13.",
"profile.age.set.date": "Set your date of birth",
"profile.datejoined.member.since": "Member since {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Saved",
"profile.visibility.who.just.me": "Just me",
"profile.visibility.who.everyone": "Everyone on {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "Full Name",
"profile.name.details": "This is the name that appears in your account and on your certificates.",
"profile.name.empty": "Add name",
@@ -47,5 +53,32 @@
"profile.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
"profile.viewMyRecords": "View My Records",
"profile.loading": "Profile loading...",
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}."
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -1,4 +1,5 @@
{
"profile.page.title": "Profile | {siteName}",
"profile.age.details": "To share your profile with other {siteName} learners, you must confirm that you are over the age of 13.",
"profile.age.set.date": "Set your date of birth",
"profile.datejoined.member.since": "Member since {year}",
@@ -33,6 +34,11 @@
"profile.formcontrols.button.saved": "Saved",
"profile.visibility.who.just.me": "Just me",
"profile.visibility.who.everyone": "Everyone on {siteName}",
"profile.learningGoal.learningGoal": "Learning Goal",
"profile.learningGoal.options.start_career": "I want to start my career",
"profile.learningGoal.options.advance_career": "I want to advance my career",
"profile.learningGoal.options.learn_something_new": "I want to learn something new",
"profile.learningGoal.options.something_else": "Something else",
"profile.name.full.name": "Full Name",
"profile.name.details": "This is the name that appears in your account and on your certificates.",
"profile.name.empty": "Add name",
@@ -47,5 +53,32 @@
"profile.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
"profile.viewMyRecords": "View My Records",
"profile.loading": "Profile loading...",
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}."
"profile.username.description": "Your profile information is only visible to you. Only your username is visible to others on {siteName}.",
"skills.builder.header.title": "Skills Builder",
"skills.builder.header.subheading": "Let edX be your guide",
"go.back.button": "Go Back",
"next.step.button": "Next Step",
"exit.button": "Exit",
"select.preferences": "Select preferences",
"review.results": "Review results",
"skills.builder.description": "Find the right courses and programs that help you reach your goals.",
"learning.goal.prompt": "First, tell us what you want to achieve",
"select.learning.goal": "Select a goal",
"learning.goal.start_career": "I want to start my career",
"learning.goal.advance_career": "I want to advance my career",
"learning.goal.change_career": "I want to change careers",
"learning.goal.something.new": "I want to learn something new",
"learning.goal.something.else": "Something else",
"job.title.prompt": "Next, search and select your current job title",
"job.title.input.placeholder.text": "Search and select a job title",
"student.checkbox.prompt": "I'm a student",
"currently.looking.checkbox.prompt": "I'm currently looking for work",
"career.interest.prompt": "What careers are you interested in?",
"career.interest.input.placeholder.text": "Select up to 3 new job titles",
"career.interest.remove.button.alt.text": "Remove career interest: ",
"matches.found.success.alert": "We found skills and courses that match your preferences!",
"matches.not.found.danger.alert": "We were not able to retrieve recommendations at this time. Please try again later.",
"related.skills.heading": "Related Skills",
"related.skills.selectable.box.label.text": "Related skills:",
"product.recommendations.header.text": "{productType} recommendations for {jobName}"
}

View File

@@ -15,27 +15,25 @@ import {
import React from 'react';
import ReactDOM from 'react-dom';
import { Route, Switch } from 'react-router-dom';
import Header, { messages as headerMessages } from '@edx/frontend-component-header';
import Footer, { messages as footerMessages } from '@edx/frontend-component-footer';
import appMessages from './i18n';
import { ProfilePage, NotFoundPage } from './profile';
import configureStore from './data/configureStore';
import './index.scss';
import Head from './head/Head';
import AppRoutes from './routes/AppRoutes';
subscribe(APP_READY, () => {
ReactDOM.render(
<AppProvider store={configureStore()}>
<Head />
<Header />
<main>
<Switch>
<Route path="/u/:username" component={ProfilePage} />
<Route path="/notfound" component={NotFoundPage} />
<Route path="*" component={NotFoundPage} />
</Switch>
<AppRoutes />
</main>
<Footer />
</AppProvider>,
@@ -53,14 +51,12 @@ initialize({
headerMessages,
footerMessages,
],
requireAuthenticatedUser: true,
hydrateAuthenticatedUser: true,
handlers: {
config: () => {
mergeConfig({
ENABLE_LEARNER_RECORD_MFE: (process.env.ENABLE_LEARNER_RECORD_MFE || false),
LEARNER_RECORD_MFE_BASE_URL: process.env.LEARNER_RECORD_MFE_BASE_URL,
COLLECT_YEAR_OF_BIRTH: process.env.COLLECT_YEAR_OF_BIRTH,
ENABLE_SKILLS_BUILDER_PROFILE: process.env.ENABLE_SKILLS_BUILDER_PROFILE,
}, 'App loadConfig override handler');
},
},

View File

@@ -4,35 +4,33 @@ import { Alert } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
function AgeMessage({ accountSettingsUrl }) {
return (
<Alert
variant="info"
dismissible={false}
show
>
<Alert.Heading id="profile.age.headline">
Your profile cannot be shared.
</Alert.Heading>
const AgeMessage = ({ accountSettingsUrl }) => (
<Alert
variant="info"
dismissible={false}
show
>
<Alert.Heading id="profile.age.headline">
Your profile cannot be shared.
</Alert.Heading>
<FormattedMessage
id="profile.age.details"
defaultMessage="To share your profile with other {siteName} learners, you must confirm that you are over the age of 13."
description="Error message"
tagName="p"
values={{
siteName: getConfig().SITE_NAME,
}}
/>
<Alert.Link href={accountSettingsUrl}>
<FormattedMessage
id="profile.age.details"
defaultMessage="To share your profile with other {siteName} learners, you must confirm that you are over the age of 13."
description="Error message"
tagName="p"
values={{
siteName: getConfig().SITE_NAME,
}}
id="profile.age.set.date"
defaultMessage="Set your date of birth"
description="Label on a link to set birthday"
/>
<Alert.Link href={accountSettingsUrl}>
<FormattedMessage
id="profile.age.set.date"
defaultMessage="Set your date of birth"
description="Label on a link to set birthday"
/>
</Alert.Link>
</Alert>
);
}
</Alert.Link>
</Alert>
);
AgeMessage.propTypes = {
accountSettingsUrl: PropTypes.string.isRequired,

View File

@@ -1,7 +1,5 @@
import React from 'react';
function Banner() {
return <div className="profile-page-bg-banner bg-primary d-none d-md-block p-relative" />;
}
const Banner = () => <div className="profile-page-bg-banner bg-primary d-none d-md-block p-relative" />;
export default Banner;

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, FormattedDate } from '@edx/frontend-platform/i18n';
function DateJoined({ date }) {
const DateJoined = ({ date }) => {
if (date == null) {
return null;
}
@@ -19,7 +19,7 @@ function DateJoined({ date }) {
/>
</p>
);
}
};
DateJoined.propTypes = {
date: PropTypes.string,

View File

@@ -1,16 +1,16 @@
import React from 'react';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
export default function NotFoundPage() {
return (
<div className="container-fluid d-flex py-5 justify-content-center align-items-start text-center">
<p className="my-0 py-5 text-muted" style={{ maxWidth: '32em' }}>
<FormattedMessage
id="profile.notfound.message"
defaultMessage="The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again."
description="error message when a page does not exist"
/>
</p>
</div>
);
}
const NotFoundPage = () => (
<div className="container-fluid d-flex py-5 justify-content-center align-items-start text-center">
<p className="my-0 py-5 text-muted" style={{ maxWidth: '32em' }}>
<FormattedMessage
id="profile.notfound.message"
defaultMessage="The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again."
description="error message when a page does not exist"
/>
</p>
</div>
);
export default NotFoundPage;

View File

@@ -33,6 +33,7 @@ import DateJoined from './DateJoined';
import UsernameDescription from './UsernameDescription';
import PageLoading from './PageLoading';
import Banner from './Banner';
import LearningGoal from './forms/LearningGoal';
// Selectors
import { profilePageSelector } from './data/selectors';
@@ -46,10 +47,10 @@ class ProfilePage extends React.Component {
constructor(props, context) {
super(props, context);
const recordsUrl = this.getRecordsUrl(context);
const credentialsBaseUrl = context.config.CREDENTIALS_BASE_URL;
this.state = {
viewMyRecordsUrl: recordsUrl,
viewMyRecordsUrl: credentialsBaseUrl ? `${credentialsBaseUrl}/records` : null,
accountSettingsUrl: `${context.config.LMS_BASE_URL}/account/settings`,
};
@@ -92,19 +93,6 @@ class ProfilePage extends React.Component {
this.props.updateDraft(name, value);
}
getRecordsUrl(context) {
let recordsUrl = null;
if (getConfig().ENABLE_LEARNER_RECORD_MFE) {
recordsUrl = getConfig().LEARNER_RECORD_MFE_BASE_URL;
} else {
const credentialsBaseUrl = context.config.CREDENTIALS_BASE_URL;
recordsUrl = credentialsBaseUrl ? `${credentialsBaseUrl}/records` : null;
}
return recordsUrl;
}
isYOBDisabled() {
const { yearOfBirth } = this.props;
const currentYear = new Date().getFullYear();
@@ -184,6 +172,8 @@ class ProfilePage extends React.Component {
socialLinks,
draftSocialLinksByPlatform,
visibilitySocialLinks,
learningGoal,
visibilityLearningGoal,
languageProficiencies,
visibilityLanguageProficiencies,
visibilityCourseCertificates,
@@ -278,6 +268,14 @@ class ProfilePage extends React.Component {
formId="bio"
{...commonFormProps}
/>
{getConfig().ENABLE_SKILLS_BUILDER_PROFILE && (
<LearningGoal
learningGoal={learningGoal}
visibilityLearningGoal={visibilityLearningGoal}
formId="learningGoal"
{...commonFormProps}
/>
)}
<Certificates
visibilityCourseCertificates={visibilityCourseCertificates}
formId="certificates"
@@ -346,6 +344,10 @@ ProfilePage.propTypes = {
})),
visibilitySocialLinks: PropTypes.string.isRequired,
// Learning Goal form data
learningGoal: PropTypes.string,
visibilityLearningGoal: PropTypes.string.isRequired,
// Other data we need
profileImage: PropTypes.shape({
src: PropTypes.string,
@@ -390,6 +392,7 @@ ProfilePage.defaultProps = {
socialLinks: [],
draftSocialLinksByPlatform: {},
bio: null,
learningGoal: null,
languageProficiencies: [],
courseCertificates: null,
requiresParentalConsent: null,

View File

@@ -66,21 +66,19 @@ beforeEach(() => {
analytics.sendTrackingLogEvent.mockReset();
});
function ProfilePageWrapper({
const ProfilePageWrapper = ({
contextValue, store, match, requiresParentalConsent,
}) {
return (
<AppContext.Provider
value={contextValue}
>
<IntlProvider locale="en">
<Provider store={store}>
<ProfilePage {...requiredProfilePageProps} match={match} requiresParentalConsent={requiresParentalConsent} />
</Provider>
</IntlProvider>
</AppContext.Provider>
);
}
}) => (
<AppContext.Provider
value={contextValue}
>
<IntlProvider locale="en">
<Provider store={store}>
<ProfilePage {...requiredProfilePageProps} match={match} requiresParentalConsent={requiresParentalConsent} />
</Provider>
</IntlProvider>
</AppContext.Provider>
);
ProfilePageWrapper.defaultProps = {
match: { params: { username: 'staff' } },

View File

@@ -4,22 +4,20 @@ import { VisibilityOff } from '@edx/paragon/icons';
import { Icon } from '@edx/paragon';
import { getConfig } from '@edx/frontend-platform';
function UsernameDescription() {
return (
<div className="d-flex align-items-center mt-3 mb-2rem">
<Icon src={VisibilityOff} className="icon-visibility-off" />
<div className="username-description">
<FormattedMessage
id="profile.username.description"
defaultMessage="Your profile information is only visible to you. Only your username is visible to others on {siteName}."
description="A description of the username field"
values={{
siteName: getConfig().SITE_NAME,
}}
/>
</div>
const UsernameDescription = () => (
<div className="d-flex align-items-center mt-3 mb-2rem">
<Icon src={VisibilityOff} className="icon-visibility-off" />
<div className="username-description">
<FormattedMessage
id="profile.username.description"
defaultMessage="Your profile information is only visible to you. Only your username is visible to others on {siteName}."
description="A description of the username field"
values={{
siteName: getConfig().SITE_NAME,
}}
/>
</div>
);
}
</div>
);
export default UsernameDescription;

View File

@@ -12,7 +12,8 @@ module.exports = {
imageUrlMedium: null,
imageUrlLarge: null
},
levelOfEducation: null
levelOfEducation: null,
learningGoal: null
},
profilePage: {
errors: {},

View File

@@ -42,7 +42,8 @@ module.exports = {
secondaryEmail: null,
timeZone: null,
gender: null,
accountPrivacy: 'custom'
accountPrivacy: 'custom',
learningGoal: null,
},
profilePage: {
errors: {},
@@ -91,7 +92,8 @@ module.exports = {
timeZone: null,
levelOfEducation: 'el',
gender: null,
accountPrivacy: 'custom'
accountPrivacy: 'custom',
learningGoal: null,
},
preferences: {
visibilityUserLocation: 'all_users',
@@ -104,7 +106,8 @@ module.exports = {
visibilityName: 'private',
visibilityLanguageProficiencies: 'all_users',
visibilityCountry: 'all_users',
accountPrivacy: 'custom'
accountPrivacy: 'custom',
visibilityLearningGoal: 'private',
},
courseCertificates: [
{

View File

@@ -42,7 +42,8 @@ module.exports = {
secondaryEmail: null,
timeZone: null,
gender: null,
accountPrivacy: 'custom'
accountPrivacy: 'custom',
learningGoal: 'advance_career',
},
profilePage: {
errors: {},
@@ -83,7 +84,8 @@ module.exports = {
preferences: {},
courseCertificates: [],
drafts: {},
isLoadingProfile: false
isLoadingProfile: false,
learningGoal: 'advance_career',
},
router: {
location: {

View File

@@ -42,7 +42,8 @@ module.exports = {
secondaryEmail: null,
timeZone: null,
gender: null,
accountPrivacy: 'custom'
accountPrivacy: 'custom',
learningGoal: 'advance_career'
},
profilePage: {
errors: {},
@@ -91,7 +92,8 @@ module.exports = {
timeZone: null,
levelOfEducation: 'el',
gender: null,
accountPrivacy: 'custom'
accountPrivacy: 'custom',
learningGoal: 'advance_career'
},
preferences: {
visibilityUserLocation: 'all_users',
@@ -104,7 +106,8 @@ module.exports = {
visibilityName: 'private',
visibilityLanguageProficiencies: 'all_users',
visibilityCountry: 'all_users',
accountPrivacy: 'custom'
accountPrivacy: 'custom',
visibilityLearningGoal: 'private',
},
courseCertificates: [
{

View File

@@ -60,7 +60,7 @@ exports[`<ProfilePage /> Renders correctly in various states test country edit w
className="profile-avatar-menu-container"
>
<div
className="dropdown"
className="pgn__dropdown pgn__dropdown-light dropdown"
data-testid="dropdown"
>
<button
@@ -120,12 +120,8 @@ exports[`<ProfilePage /> Renders correctly in various states test country edit w
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -202,12 +198,8 @@ exports[`<ProfilePage /> Renders correctly in various states test country edit w
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -2346,9 +2338,7 @@ exports[`<ProfilePage /> Renders correctly in various states test country edit w
<p
className="small mb-0"
>
<span>
From
</span>
From
</p>
<p
className="h6 mb-4"
@@ -2361,12 +2351,8 @@ exports[`<ProfilePage /> Renders correctly in various states test country edit w
<p
className="small mb-2"
>
<span>
Completed on
<span>
3/4/2019
</span>
</span>
Completed on
3/4/2019
</p>
<div>
<a
@@ -2455,7 +2441,7 @@ exports[`<ProfilePage /> Renders correctly in various states test education edit
className="profile-avatar-menu-container"
>
<div
className="dropdown"
className="pgn__dropdown pgn__dropdown-light dropdown"
data-testid="dropdown"
>
<button
@@ -2515,12 +2501,8 @@ exports[`<ProfilePage /> Renders correctly in various states test education edit
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -2597,12 +2579,8 @@ exports[`<ProfilePage /> Renders correctly in various states test education edit
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -3017,7 +2995,7 @@ exports[`<ProfilePage /> Renders correctly in various states test education edit
No formal education
</option>
<option
value="o"
value="other"
>
Other education
</option>
@@ -3535,9 +3513,7 @@ exports[`<ProfilePage /> Renders correctly in various states test education edit
<p
className="small mb-0"
>
<span>
From
</span>
From
</p>
<p
className="h6 mb-4"
@@ -3550,12 +3526,8 @@ exports[`<ProfilePage /> Renders correctly in various states test education edit
<p
className="small mb-2"
>
<span>
Completed on
<span>
3/4/2019
</span>
</span>
Completed on
3/4/2019
</p>
<div>
<a
@@ -3644,7 +3616,7 @@ exports[`<ProfilePage /> Renders correctly in various states test preferreded la
className="profile-avatar-menu-container"
>
<div
className="dropdown"
className="pgn__dropdown pgn__dropdown-light dropdown"
data-testid="dropdown"
>
<button
@@ -3704,12 +3676,8 @@ exports[`<ProfilePage /> Renders correctly in various states test preferreded la
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -3786,12 +3754,8 @@ exports[`<ProfilePage /> Renders correctly in various states test preferreded la
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -5599,9 +5563,7 @@ exports[`<ProfilePage /> Renders correctly in various states test preferreded la
<p
className="small mb-0"
>
<span>
From
</span>
From
</p>
<p
className="h6 mb-4"
@@ -5614,12 +5576,8 @@ exports[`<ProfilePage /> Renders correctly in various states test preferreded la
<p
className="small mb-2"
>
<span>
Completed on
<span>
3/4/2019
</span>
</span>
Completed on
3/4/2019
</p>
<div>
<a
@@ -5745,12 +5703,8 @@ exports[`<ProfilePage /> Renders correctly in various states viewing other profi
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<div
className="d-flex align-items-center mt-3 mb-2rem"
@@ -5777,9 +5731,7 @@ exports[`<ProfilePage /> Renders correctly in various states viewing other profi
<div
className="username-description"
>
<span>
Your profile information is only visible to you. Only your username is visible to others on localhost.
</span>
Your profile information is only visible to you. Only your username is visible to others on localhost.
</div>
</div>
<hr
@@ -5812,12 +5764,8 @@ exports[`<ProfilePage /> Renders correctly in various states viewing other profi
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<div
className="d-flex align-items-center mt-3 mb-2rem"
@@ -5844,9 +5792,7 @@ exports[`<ProfilePage /> Renders correctly in various states viewing other profi
<div
className="username-description"
>
<span>
Your profile information is only visible to you. Only your username is visible to others on localhost.
</span>
Your profile information is only visible to you. Only your username is visible to others on localhost.
</div>
</div>
<hr
@@ -5952,7 +5898,7 @@ exports[`<ProfilePage /> Renders correctly in various states viewing own profile
className="profile-avatar-menu-container"
>
<div
className="dropdown"
className="pgn__dropdown pgn__dropdown-light dropdown"
data-testid="dropdown"
>
<button
@@ -6012,12 +5958,8 @@ exports[`<ProfilePage /> Renders correctly in various states viewing own profile
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -6094,12 +6036,8 @@ exports[`<ProfilePage /> Renders correctly in various states viewing own profile
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -6907,9 +6845,7 @@ exports[`<ProfilePage /> Renders correctly in various states viewing own profile
<p
className="small mb-0"
>
<span>
From
</span>
From
</p>
<p
className="h6 mb-4"
@@ -6922,12 +6858,8 @@ exports[`<ProfilePage /> Renders correctly in various states viewing own profile
<p
className="small mb-2"
>
<span>
Completed on
<span>
3/4/2019
</span>
</span>
Completed on
3/4/2019
</p>
<div>
<a
@@ -7016,7 +6948,7 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
className="profile-avatar-menu-container"
>
<div
className="dropdown"
className="pgn__dropdown pgn__dropdown-light dropdown"
data-testid="dropdown"
>
<button
@@ -7076,12 +7008,8 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -7158,12 +7086,8 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -8038,9 +7962,7 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
<p
className="small mb-0"
>
<span>
From
</span>
From
</p>
<p
className="h6 mb-4"
@@ -8053,12 +7975,8 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
<p
className="small mb-2"
>
<span>
Completed on
<span>
3/4/2019
</span>
</span>
Completed on
3/4/2019
</p>
<div>
<a
@@ -8147,7 +8065,7 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
className="profile-avatar-menu-container"
>
<div
className="dropdown"
className="pgn__dropdown pgn__dropdown-light dropdown"
data-testid="dropdown"
>
<button
@@ -8207,12 +8125,8 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -8289,12 +8203,8 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -9175,9 +9085,7 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
<p
className="small mb-0"
>
<span>
From
</span>
From
</p>
<p
className="h6 mb-4"
@@ -9190,12 +9098,8 @@ exports[`<ProfilePage /> Renders correctly in various states while saving an edi
<p
className="small mb-2"
>
<span>
Completed on
<span>
3/4/2019
</span>
</span>
Completed on
3/4/2019
</p>
<div>
<a
@@ -9284,7 +9188,7 @@ exports[`<ProfilePage /> Renders correctly in various states without credentials
className="profile-avatar-menu-container"
>
<div
className="dropdown"
className="pgn__dropdown pgn__dropdown-light dropdown"
data-testid="dropdown"
>
<button
@@ -9344,12 +9248,8 @@ exports[`<ProfilePage /> Renders correctly in various states without credentials
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -9381,12 +9281,8 @@ exports[`<ProfilePage /> Renders correctly in various states without credentials
<p
className="mb-0"
>
<span>
Member since
<span>
2017
</span>
</span>
Member since
2017
</p>
<hr
className="d-none d-md-block"
@@ -10149,9 +10045,7 @@ exports[`<ProfilePage /> Renders correctly in various states without credentials
<p
className="small mb-0"
>
<span>
From
</span>
From
</p>
<p
className="h6 mb-4"
@@ -10164,12 +10058,8 @@ exports[`<ProfilePage /> Renders correctly in various states without credentials
<p
className="small mb-2"
>
<span>
Completed on
<span>
3/4/2019
</span>
</span>
Completed on
3/4/2019
</p>
<div>
<a

View File

@@ -7,7 +7,7 @@ const EDUCATION_LEVELS = [
'jhs',
'el',
'none',
'o',
'other',
];
const SOCIAL = {

View File

@@ -0,0 +1,7 @@
const mockData = {
learningGoal: 'advance_career',
editMode: 'static',
visibilityLearningGoal: 'private',
};
export default mockData;

View File

@@ -0,0 +1,92 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import get from 'lodash.get';
// Mock Data
import mockData from '../data/mock_data';
import messages from './LearningGoal.messages';
// Components
import EditableItemHeader from './elements/EditableItemHeader';
import SwitchContent from './elements/SwitchContent';
// Selectors
import { editableFormSelector } from '../data/selectors';
const LearningGoal = (props) => {
let { learningGoal, editMode, visibilityLearningGoal } = props;
const { intl } = props;
if (!learningGoal) {
learningGoal = mockData.learningGoal;
}
if (!editMode || editMode === 'empty') { // editMode defaults to 'empty', not sure why yet
editMode = mockData.editMode;
}
if (!visibilityLearningGoal) {
visibilityLearningGoal = mockData.visibilityLearningGoal;
}
return (
<SwitchContent
className="mb-5"
expression={editMode}
cases={{
editable: (
<>
<EditableItemHeader
content={intl.formatMessage(messages['profile.learningGoal.learningGoal'])}
showVisibility={visibilityLearningGoal !== null}
visibility={visibilityLearningGoal}
/>
<p data-hj-suppress className="lead">
{intl.formatMessage(get(
messages,
`profile.learningGoal.options.${learningGoal}`,
messages['profile.learningGoal.options.something_else'],
))}
</p>
</>
),
static: (
<>
<EditableItemHeader content={intl.formatMessage(messages['profile.learningGoal.learningGoal'])} />
<p data-hj-suppress className="lead">
{intl.formatMessage(get(
messages,
`profile.learningGoal.options.${learningGoal}`,
messages['profile.learningGoal.options.something_else'],
))}
</p>
</>
),
}}
/>
);
};
LearningGoal.propTypes = {
// From Selector
learningGoal: PropTypes.oneOf(['advance_career', 'start_career', 'learn_something_new', 'something_else']),
visibilityLearningGoal: PropTypes.oneOf(['private', 'all_users']),
editMode: PropTypes.oneOf(['editable', 'static']),
// i18n
intl: intlShape.isRequired,
};
LearningGoal.defaultProps = {
editMode: 'static',
learningGoal: null,
visibilityLearningGoal: 'private',
};
export default connect(
editableFormSelector,
{},
)(injectIntl(LearningGoal));

View File

@@ -0,0 +1,31 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'profile.learningGoal.learningGoal': {
id: 'profile.learningGoal.learningGoal',
defaultMessage: 'Learning Goal',
description: 'A section of a user profile that displays their current learning goal.',
},
'profile.learningGoal.options.start_career': {
id: 'profile.learningGoal.options.start_career',
defaultMessage: 'I want to start my career',
description: 'Selected by user if their goal is to start their career.',
},
'profile.learningGoal.options.advance_career': {
id: 'profile.learningGoal.options.advance_career',
defaultMessage: 'I want to advance my career',
description: 'Selected by user if their goal is to advance their career.',
},
'profile.learningGoal.options.learn_something_new': {
id: 'profile.learningGoal.options.learn_something_new',
defaultMessage: 'I want to learn something new',
description: 'Selected by user if their goal is to learn something new.',
},
'profile.learningGoal.options.something_else': {
id: 'profile.learningGoal.options.something_else',
defaultMessage: 'Something else',
description: 'Selected by user if their goal is not described by the other choices.',
},
});
export default messages;

View File

@@ -0,0 +1,122 @@
import PropTypes from 'prop-types';
import React, { useMemo } from 'react';
import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { configure as configureI18n, IntlProvider } from '@edx/frontend-platform/i18n';
import { getConfig } from '@edx/frontend-platform';
import { AppContext } from '@edx/frontend-platform/react';
import messages from '../../i18n';
import viewOwnProfileMockStore from '../__mocks__/viewOwnProfile.mockStore';
import savingEditedBioMockStore from '../__mocks__/savingEditedBio.mockStore';
import LearningGoal from './LearningGoal';
const mockStore = configureMockStore([thunk]);
// props to be passed down to LearningGoal component
const requiredLearningGoalProps = {
formId: 'learningGoal',
learningGoal: 'advance_career',
drafts: {},
visibilityLearningGoal: 'private',
editMode: 'static',
saveState: null,
error: null,
openHandler: jest.fn(),
};
configureI18n({
loggingService: { logError: jest.fn() },
config: {
ENVIRONMENT: 'production',
LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum',
},
messages,
});
const LearningGoalWrapper = (props) => {
const contextValue = useMemo(() => ({
authenticatedUser: { userId: null, username: null, administrator: false },
config: getConfig(),
}), []);
return (
<AppContext.Provider
value={contextValue}
>
<IntlProvider locale="en">
<Provider store={props.store}>
<LearningGoal {...props} />
</Provider>
</IntlProvider>
</AppContext.Provider>
);
};
LearningGoalWrapper.defaultProps = {
store: mockStore(viewOwnProfileMockStore),
};
LearningGoalWrapper.propTypes = {
store: PropTypes.shape({}),
};
const LearningGoalWrapperWithStore = ({ store }) => {
const contextValue = useMemo(() => ({
authenticatedUser: { userId: null, username: null, administrator: false },
config: getConfig(),
}), []);
return (
<AppContext.Provider
value={contextValue}
>
<IntlProvider locale="en">
<Provider store={mockStore(store)}>
<LearningGoal {...requiredLearningGoalProps} formId="learningGoal" />
</Provider>
</IntlProvider>
</AppContext.Provider>
);
};
LearningGoalWrapperWithStore.defaultProps = {
store: mockStore(savingEditedBioMockStore),
};
LearningGoalWrapperWithStore.propTypes = {
store: PropTypes.shape({}),
};
describe('<LearningGoal />', () => {
describe('renders the current learning goal', () => {
it('renders "I want to advance my career"', () => {
const learningGoalRenderer = renderer.create(
<LearningGoalWrapper
{...requiredLearningGoalProps}
formId="learningGoal"
/>,
);
const learningGoalInstance = learningGoalRenderer.root;
expect(learningGoalInstance.findByProps({ className: 'lead' }).children).toEqual(['I want to advance my career']);
});
it('renders "Something else"', () => {
requiredLearningGoalProps.learningGoal = 'something_else';
const learningGoalRenderer = renderer.create(
<LearningGoalWrapper
{...requiredLearningGoalProps}
formId="learningGoal"
/>,
);
const learningGoalInstance = learningGoalRenderer.root;
expect(learningGoalInstance.findByProps({ className: 'lead' }).children).toEqual(['Something else']);
});
});
});

View File

@@ -244,14 +244,12 @@ export default connect(
{},
)(injectIntl(SocialLinks));
function SocialLink({ url, name, platform }) {
return (
<a href={url} className="font-weight-bold">
<FontAwesomeIcon className="mr-2" icon={platformDisplayInfo[platform].icon} />
{name}
</a>
);
}
const SocialLink = ({ url, name, platform }) => (
<a href={url} className="font-weight-bold">
<FontAwesomeIcon className="mr-2" icon={platformDisplayInfo[platform].icon} />
{name}
</a>
);
SocialLink.propTypes = {
url: PropTypes.string.isRequired,
@@ -259,9 +257,9 @@ SocialLink.propTypes = {
name: PropTypes.string.isRequired,
};
function EditableListItem({
const EditableListItem = ({
url, platform, onClickEmptyContent, name,
}) {
}) => {
const linkDisplay = url ? (
<SocialLink name={name} url={url} platform={platform} />
) : (
@@ -269,7 +267,7 @@ function EditableListItem({
);
return <li className="form-group">{linkDisplay}</li>;
}
};
EditableListItem.propTypes = {
url: PropTypes.string,
@@ -282,24 +280,22 @@ EditableListItem.defaultProps = {
onClickEmptyContent: null,
};
function EditingListItem({
const EditingListItem = ({
platform, name, value, onChange, error,
}) {
return (
<li className="form-group">
<label htmlFor={`social-${platform}`}>{name}</label>
<input
className={classNames('form-control', { 'is-invalid': Boolean(error) })}
type="text"
id={`social-${platform}`}
name={platform}
value={value || ''}
onChange={onChange}
aria-describedby="social-error-feedback"
/>
</li>
);
}
}) => (
<li className="form-group">
<label htmlFor={`social-${platform}`}>{name}</label>
<input
className={classNames('form-control', { 'is-invalid': Boolean(error) })}
type="text"
id={`social-${platform}`}
name={platform}
value={value || ''}
onChange={onChange}
aria-describedby="social-error-feedback"
/>
</li>
);
EditingListItem.propTypes = {
platform: PropTypes.string.isRequired,
@@ -314,35 +310,31 @@ EditingListItem.defaultProps = {
error: null,
};
function EmptyListItem({ onClick, name }) {
return (
<li className="mb-4">
<EmptyContent onClick={onClick}>
<FormattedMessage
id="profile.sociallinks.add"
defaultMessage="Add {network}"
values={{
network: name,
}}
description="{network} is the name of a social network such as Facebook or Twitter"
/>
</EmptyContent>
</li>
);
}
const EmptyListItem = ({ onClick, name }) => (
<li className="mb-4">
<EmptyContent onClick={onClick}>
<FormattedMessage
id="profile.sociallinks.add"
defaultMessage="Add {network}"
values={{
network: name,
}}
description="{network} is the name of a social network such as Facebook or Twitter"
/>
</EmptyContent>
</li>
);
EmptyListItem.propTypes = {
name: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
};
function StaticListItem({ name, url, platform }) {
return (
<li className="mb-2">
<SocialLink name={name} url={url} platform={platform} />
</li>
);
}
const StaticListItem = ({ name, url, platform }) => (
<li className="mb-2">
<SocialLink name={name} url={url} platform={platform} />
</li>
);
StaticListItem.propTypes = {
name: PropTypes.string.isRequired,

View File

@@ -47,7 +47,7 @@ configureI18n({
messages,
});
function SocialLinksWrapper(props) {
const SocialLinksWrapper = (props) => {
const contextValue = useMemo(() => ({
authenticatedUser: { userId: null, username: null, administrator: false },
config: getConfig(),
@@ -63,7 +63,7 @@ function SocialLinksWrapper(props) {
</IntlProvider>
</AppContext.Provider>
);
}
};
SocialLinksWrapper.defaultProps = {
store: mockStore(savingEditedBio),
@@ -73,7 +73,7 @@ SocialLinksWrapper.propTypes = {
store: PropTypes.shape({}),
};
function SocialLinksWrapperWithStore({ store }) {
const SocialLinksWrapperWithStore = ({ store }) => {
const contextValue = useMemo(() => ({
authenticatedUser: { userId: null, username: null, administrator: false },
config: getConfig(),
@@ -89,7 +89,7 @@ function SocialLinksWrapperWithStore({ store }) {
</IntlProvider>
</AppContext.Provider>
);
}
};
SocialLinksWrapperWithStore.defaultProps = {
store: mockStore(savingEditedBio),

View File

@@ -399,9 +399,7 @@ exports[`<SocialLinks /> calls social links with edit mode goals 1`] = `
style={Object {}}
/>
</svg>
<span>
Add Facebook
</span>
Add Facebook
</button>
</div>
</li>
@@ -433,9 +431,7 @@ exports[`<SocialLinks /> calls social links with edit mode goals 1`] = `
style={Object {}}
/>
</svg>
<span>
Add Twitter
</span>
Add Twitter
</button>
</div>
</li>

View File

@@ -7,22 +7,20 @@ import { Button } from '@edx/paragon';
import messages from './EditButton.messages';
function EditButton({
const EditButton = ({
onClick, className, style, intl,
}) {
return (
<Button
variant="link"
size="sm"
className={className}
onClick={onClick}
style={style}
>
<FontAwesomeIcon className="mr-1" icon={faPencilAlt} />
{intl.formatMessage(messages['profile.editbutton.edit'])}
</Button>
);
}
}) => (
<Button
variant="link"
size="sm"
className={className}
onClick={onClick}
style={style}
>
<FontAwesomeIcon className="mr-1" icon={faPencilAlt} />
{intl.formatMessage(messages['profile.editbutton.edit'])}
</Button>
);
export default injectIntl(EditButton);

View File

@@ -4,24 +4,22 @@ import PropTypes from 'prop-types';
import EditButton from './EditButton';
import { Visibility } from './Visibility';
function EditableItemHeader({
const EditableItemHeader = ({
content,
showVisibility,
visibility,
showEditButton,
onClickEdit,
headingId,
}) {
return (
<div className="editable-item-header mb-2">
<h2 className="edit-section-header" id={headingId}>
{content}
{showEditButton ? <EditButton style={{ marginTop: '-.35rem' }} className="float-right px-0" onClick={onClickEdit} /> : null}
</h2>
{showVisibility ? <p className="mb-0"><Visibility to={visibility} /></p> : null}
</div>
);
}
}) => (
<div className="editable-item-header mb-2">
<h2 className="edit-section-header" id={headingId}>
{content}
{showEditButton ? <EditButton style={{ marginTop: '-.35rem' }} className="float-right px-0" onClick={onClickEdit} /> : null}
</h2>
{showVisibility ? <p className="mb-0"><Visibility to={visibility} /></p> : null}
</div>
);
export default EditableItemHeader;

View File

@@ -3,24 +3,22 @@ import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlus } from '@fortawesome/free-solid-svg-icons';
function EmptyContent({ children, onClick, showPlusIcon }) {
return (
<div>
{onClick ? (
<button
type="button"
className="pl-0 text-left btn btn-link"
onClick={onClick}
onKeyDown={(e) => { if (e.key === 'Enter') { onClick(); } }}
tabIndex={0}
>
{showPlusIcon ? <FontAwesomeIcon size="xs" className="mr-2" icon={faPlus} /> : null}
{children}
</button>
) : children}
</div>
);
}
const EmptyContent = ({ children, onClick, showPlusIcon }) => (
<div>
{onClick ? (
<button
type="button"
className="pl-0 text-left btn btn-link"
onClick={onClick}
onKeyDown={(e) => { if (e.key === 'Enter') { onClick(); } }}
tabIndex={0}
>
{showPlusIcon ? <FontAwesomeIcon size="xs" className="mr-2" icon={faPlus} /> : null}
{children}
</button>
) : children}
</div>
);
export default EmptyContent;

View File

@@ -7,9 +7,9 @@ import messages from './FormControls.messages';
import { VisibilitySelect } from './Visibility';
function FormControls({
const FormControls = ({
cancelHandler, changeHandler, visibility, visibilityId, saveState, intl,
}) {
}) => {
// Eliminate error/failed state for save button
const buttonState = saveState === 'error' ? null : saveState;
@@ -57,7 +57,7 @@ function FormControls({
</div>
</div>
);
}
};
export default injectIntl(FormControls);

View File

@@ -22,7 +22,7 @@ const onChildExit = (htmlNode) => {
}
};
function SwitchContent({ expression, cases, className }) {
const SwitchContent = ({ expression, cases, className }) => {
const getContent = (caseKey) => {
if (cases[caseKey]) {
if (typeof cases[caseKey] === 'string') {
@@ -48,7 +48,7 @@ function SwitchContent({ expression, cases, className }) {
{getContent(expression)}
</TransitionReplace>
);
}
};
SwitchContent.propTypes = {
expression: PropTypes.string,

View File

@@ -7,7 +7,7 @@ import { faEyeSlash, faEye } from '@fortawesome/free-regular-svg-icons';
import messages from './Visibility.messages';
function Visibility({ to, intl }) {
const Visibility = ({ to, intl }) => {
const icon = to === 'private' ? faEyeSlash : faEye;
const label = to === 'private'
? intl.formatMessage(messages['profile.visibility.who.just.me'])
@@ -18,7 +18,7 @@ function Visibility({ to, intl }) {
<FontAwesomeIcon icon={icon} /> {label}
</span>
);
}
};
Visibility.propTypes = {
to: PropTypes.oneOf(['private', 'all_users']),
@@ -30,7 +30,7 @@ Visibility.defaultProps = {
to: 'private',
};
function VisibilitySelect({ intl, className, ...props }) {
const VisibilitySelect = ({ intl, className, ...props }) => {
const { value } = props;
const icon = value === 'private' ? faEyeSlash : faEye;
@@ -49,7 +49,7 @@ function VisibilitySelect({ intl, className, ...props }) {
</select>
</span>
);
}
};
VisibilitySelect.propTypes = {
id: PropTypes.string,

17
src/routes/AppRoutes.jsx Normal file
View File

@@ -0,0 +1,17 @@
import React from 'react';
import {
AuthenticatedPageRoute,
PageRoute,
} from '@edx/frontend-platform/react';
import { Switch } from 'react-router-dom';
import { ProfilePage, NotFoundPage } from '../profile';
const AppRoutes = () => (
<Switch>
<AuthenticatedPageRoute path="/u/:username" component={ProfilePage} />
<PageRoute path="/notfound" component={NotFoundPage} />
<PageRoute path="*" component={NotFoundPage} />
</Switch>
);
export default AppRoutes;

View File

@@ -0,0 +1,73 @@
import React from 'react';
import { AppContext } from '@edx/frontend-platform/react';
import { getConfig } from '@edx/frontend-platform';
import { Router } from 'react-router';
import { render, screen } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import { getLoginRedirectUrl } from '@edx/frontend-platform/auth';
import AppRoutes from './AppRoutes';
jest.mock('@edx/frontend-platform/analytics');
jest.mock('@edx/frontend-platform/auth', () => ({
getLoginRedirectUrl: jest.fn(),
}));
jest.mock('../profile', () => ({
ProfilePage: () => (<div>Profile page</div>),
NotFoundPage: () => (<div>Not found page</div>),
}));
const RoutesWithProvider = (context, history) => (
<AppContext.Provider value={context}>
<Router history={history}>
<AppRoutes />
</Router>
</AppContext.Provider>
);
const unauthenticatedUser = {
authenticatedUser: null,
config: getConfig(),
};
describe('routes', () => {
let history;
beforeEach(() => {
history = createMemoryHistory();
});
test('Profile page should redirect for unauthenticated users', () => {
history.push('/u/edx');
render(
RoutesWithProvider(unauthenticatedUser, history),
);
expect(getLoginRedirectUrl).toHaveBeenCalled();
});
test('Profile page should be accessible for authenticated users', () => {
history.push('/u/edx');
render(
RoutesWithProvider(
{
authenticatedUser: {
username: 'edx',
email: 'edx@example.com',
},
config: getConfig(),
},
history,
),
);
expect(screen.getByText('Profile page')).toBeTruthy();
});
test('should show NotFound page for a bad route', () => {
history.push('/nonMatchingRoute');
render(
RoutesWithProvider(unauthenticatedUser, history),
);
expect(screen.getByText('Not found page')).toBeTruthy();
});
});